OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [net/] [ax25/] [ax25_subr.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 *      AX.25 release 037
3
 *
4
 *      This code REQUIRES 2.1.15 or higher/ NET3.038
5
 *
6
 *      This module:
7
 *              This module is free software; you can redistribute it and/or
8
 *              modify it under the terms of the GNU General Public License
9
 *              as published by the Free Software Foundation; either version
10
 *              2 of the License, or (at your option) any later version.
11
 *
12
 *      Most of this code is based on the SDL diagrams published in the 7th
13
 *      ARRL Computer Networking Conference papers. The diagrams have mistakes
14
 *      in them, but are mostly correct. Before you modify the code could you
15
 *      read the SDL diagrams as the code is not obvious and probably very
16
 *      easy to break;
17
 *
18
 *      History
19
 *      AX.25 029       Alan(GW4PTS)    Switched to KA9Q constant names. Removed
20
 *                                      old BSD code.
21
 *      AX.25 030       Jonathan(G4KLX) Added support for extended AX.25.
22
 *                                      Added fragmentation support.
23
 *                      Darryl(G7LED)   Added function ax25_requeue_frames() to split
24
 *                                      it up from ax25_frames_acked().
25
 *      AX.25 031       Joerg(DL1BKE)   DAMA needs KISS Fullduplex ON/OFF.
26
 *                                      Thus we have ax25_kiss_cmd() now... ;-)
27
 *                      Dave Brown(N2RJT)
28
 *                                      Killed a silly bug in the DAMA code.
29
 *                      Joerg(DL1BKE)   Found the real bug in ax25.h, sri.
30
 *      AX.25 032       Joerg(DL1BKE)   Added ax25_queue_length to count the number of
31
 *                                      enqueued buffers of a socket..
32
 *      AX.25 035       Frederic(F1OAT) Support for pseudo-digipeating.
33
 *      AX.25 037       Jonathan(G4KLX) New timer architecture.
34
 */
35
 
36
#include <linux/errno.h>
37
#include <linux/types.h>
38
#include <linux/socket.h>
39
#include <linux/in.h>
40
#include <linux/kernel.h>
41
#include <linux/sched.h>
42
#include <linux/timer.h>
43
#include <linux/string.h>
44
#include <linux/sockios.h>
45
#include <linux/net.h>
46
#include <net/ax25.h>
47
#include <linux/inet.h>
48
#include <linux/netdevice.h>
49
#include <linux/skbuff.h>
50
#include <net/sock.h>
51
#include <asm/uaccess.h>
52
#include <asm/system.h>
53
#include <linux/fcntl.h>
54
#include <linux/mm.h>
55
#include <linux/interrupt.h>
56
 
57
/*
58
 *      This routine purges all the queues of frames.
59
 */
60
void ax25_clear_queues(ax25_cb *ax25)
61
{
62
        skb_queue_purge(&ax25->write_queue);
63
        skb_queue_purge(&ax25->ack_queue);
64
        skb_queue_purge(&ax25->reseq_queue);
65
        skb_queue_purge(&ax25->frag_queue);
66
}
67
 
68
/*
69
 * This routine purges the input queue of those frames that have been
70
 * acknowledged. This replaces the boxes labelled "V(a) <- N(r)" on the
71
 * SDL diagram.
72
 */
73
void ax25_frames_acked(ax25_cb *ax25, unsigned short nr)
74
{
75
        struct sk_buff *skb;
76
 
77
        /*
78
         * Remove all the ack-ed frames from the ack queue.
79
         */
80
        if (ax25->va != nr) {
81
                while (skb_peek(&ax25->ack_queue) != NULL && ax25->va != nr) {
82
                        skb = skb_dequeue(&ax25->ack_queue);
83
                        kfree_skb(skb);
84
                        ax25->va = (ax25->va + 1) % ax25->modulus;
85
                }
86
        }
87
}
88
 
89
void ax25_requeue_frames(ax25_cb *ax25)
90
{
91
        struct sk_buff *skb, *skb_prev = NULL;
92
 
93
        /*
94
         * Requeue all the un-ack-ed frames on the output queue to be picked
95
         * up by ax25_kick called from the timer. This arrangement handles the
96
         * possibility of an empty output queue.
97
         */
98
        while ((skb = skb_dequeue(&ax25->ack_queue)) != NULL) {
99
                if (skb_prev == NULL)
100
                        skb_queue_head(&ax25->write_queue, skb);
101
                else
102
                        skb_append(skb_prev, skb);
103
                skb_prev = skb;
104
        }
105
}
106
 
107
/*
108
 *      Validate that the value of nr is between va and vs. Return true or
109
 *      false for testing.
110
 */
111
int ax25_validate_nr(ax25_cb *ax25, unsigned short nr)
112
{
113
        unsigned short vc = ax25->va;
114
 
115
        while (vc != ax25->vs) {
116
                if (nr == vc) return 1;
117
                vc = (vc + 1) % ax25->modulus;
118
        }
119
 
120
        if (nr == ax25->vs) return 1;
121
 
122
        return 0;
123
}
124
 
125
/*
126
 *      This routine is the centralised routine for parsing the control
127
 *      information for the different frame formats.
128
 */
129
int ax25_decode(ax25_cb *ax25, struct sk_buff *skb, int *ns, int *nr, int *pf)
130
{
131
        unsigned char *frame;
132
        int frametype = AX25_ILLEGAL;
133
 
134
        frame = skb->data;
135
        *ns = *nr = *pf = 0;
136
 
137
        if (ax25->modulus == AX25_MODULUS) {
138
                if ((frame[0] & AX25_S) == 0) {
139
                        frametype = AX25_I;                     /* I frame - carries NR/NS/PF */
140
                        *ns = (frame[0] >> 1) & 0x07;
141
                        *nr = (frame[0] >> 5) & 0x07;
142
                        *pf = frame[0] & AX25_PF;
143
                } else if ((frame[0] & AX25_U) == 1) {   /* S frame - take out PF/NR */
144
                        frametype = frame[0] & 0x0F;
145
                        *nr = (frame[0] >> 5) & 0x07;
146
                        *pf = frame[0] & AX25_PF;
147
                } else if ((frame[0] & AX25_U) == 3) {   /* U frame - take out PF */
148
                        frametype = frame[0] & ~AX25_PF;
149
                        *pf = frame[0] & AX25_PF;
150
                }
151
                skb_pull(skb, 1);
152
        } else {
153
                if ((frame[0] & AX25_S) == 0) {
154
                        frametype = AX25_I;                     /* I frame - carries NR/NS/PF */
155
                        *ns = (frame[0] >> 1) & 0x7F;
156
                        *nr = (frame[1] >> 1) & 0x7F;
157
                        *pf = frame[1] & AX25_EPF;
158
                        skb_pull(skb, 2);
159
                } else if ((frame[0] & AX25_U) == 1) {   /* S frame - take out PF/NR */
160
                        frametype = frame[0] & 0x0F;
161
                        *nr = (frame[1] >> 1) & 0x7F;
162
                        *pf = frame[1] & AX25_EPF;
163
                        skb_pull(skb, 2);
164
                } else if ((frame[0] & AX25_U) == 3) {   /* U frame - take out PF */
165
                        frametype = frame[0] & ~AX25_PF;
166
                        *pf = frame[0] & AX25_PF;
167
                        skb_pull(skb, 1);
168
                }
169
        }
170
 
171
        return frametype;
172
}
173
 
174
/*
175
 *      This routine is called when the HDLC layer internally  generates a
176
 *      command or  response  for  the remote machine ( eg. RR, UA etc. ).
177
 *      Only supervisory or unnumbered frames are processed.
178
 */
179
void ax25_send_control(ax25_cb *ax25, int frametype, int poll_bit, int type)
180
{
181
        struct sk_buff *skb;
182
        unsigned char  *dptr;
183
 
184
        if ((skb = alloc_skb(AX25_BPQ_HEADER_LEN + ax25_addr_size(ax25->digipeat) + 2, GFP_ATOMIC)) == NULL)
185
                return;
186
 
187
        skb_reserve(skb, AX25_BPQ_HEADER_LEN + ax25_addr_size(ax25->digipeat));
188
 
189
        skb->nh.raw = skb->data;
190
 
191
        /* Assume a response - address structure for DTE */
192
        if (ax25->modulus == AX25_MODULUS) {
193
                dptr = skb_put(skb, 1);
194
                *dptr = frametype;
195
                *dptr |= (poll_bit) ? AX25_PF : 0;
196
                if ((frametype & AX25_U) == AX25_S)             /* S frames carry NR */
197
                        *dptr |= (ax25->vr << 5);
198
        } else {
199
                if ((frametype & AX25_U) == AX25_U) {
200
                        dptr = skb_put(skb, 1);
201
                        *dptr = frametype;
202
                        *dptr |= (poll_bit) ? AX25_PF : 0;
203
                } else {
204
                        dptr = skb_put(skb, 2);
205
                        dptr[0] = frametype;
206
                        dptr[1] = (ax25->vr << 1);
207
                        dptr[1] |= (poll_bit) ? AX25_EPF : 0;
208
                }
209
        }
210
 
211
        ax25_transmit_buffer(ax25, skb, type);
212
}
213
 
214
/*
215
 *      Send a 'DM' to an unknown connection attempt, or an invalid caller.
216
 *
217
 *      Note: src here is the sender, thus it's the target of the DM
218
 */
219
void ax25_return_dm(struct net_device *dev, ax25_address *src, ax25_address *dest, ax25_digi *digi)
220
{
221
        struct sk_buff *skb;
222
        char *dptr;
223
        ax25_digi retdigi;
224
 
225
        if (dev == NULL)
226
                return;
227
 
228
        if ((skb = alloc_skb(AX25_BPQ_HEADER_LEN + ax25_addr_size(digi) + 1, GFP_ATOMIC)) == NULL)
229
                return; /* Next SABM will get DM'd */
230
 
231
        skb_reserve(skb, AX25_BPQ_HEADER_LEN + ax25_addr_size(digi));
232
        skb->nh.raw = skb->data;
233
 
234
        ax25_digi_invert(digi, &retdigi);
235
 
236
        dptr = skb_put(skb, 1);
237
 
238
        *dptr = AX25_DM | AX25_PF;
239
 
240
        /*
241
         *      Do the address ourselves
242
         */
243
        dptr  = skb_push(skb, ax25_addr_size(digi));
244
        dptr += ax25_addr_build(dptr, dest, src, &retdigi, AX25_RESPONSE, AX25_MODULUS);
245
 
246
        skb->dev      = dev;
247
 
248
        ax25_queue_xmit(skb);
249
}
250
 
251
/*
252
 *      Exponential backoff for AX.25
253
 */
254
void ax25_calculate_t1(ax25_cb *ax25)
255
{
256
        int n, t = 2;
257
 
258
        switch (ax25->backoff) {
259
                case 0:
260
                        break;
261
 
262
                case 1:
263
                        t += 2 * ax25->n2count;
264
                        break;
265
 
266
                case 2:
267
                        for (n = 0; n < ax25->n2count; n++)
268
                                t *= 2;
269
                        if (t > 8) t = 8;
270
                        break;
271
        }
272
 
273
        ax25->t1 = t * ax25->rtt;
274
}
275
 
276
/*
277
 *      Calculate the Round Trip Time
278
 */
279
void ax25_calculate_rtt(ax25_cb *ax25)
280
{
281
        if (ax25->backoff == 0)
282
                return;
283
 
284
        if (ax25_t1timer_running(ax25) && ax25->n2count == 0)
285
                ax25->rtt = (9 * ax25->rtt + ax25->t1 - ax25_display_timer(&ax25->t1timer)) / 10;
286
 
287
        if (ax25->rtt < AX25_T1CLAMPLO)
288
                ax25->rtt = AX25_T1CLAMPLO;
289
 
290
        if (ax25->rtt > AX25_T1CLAMPHI)
291
                ax25->rtt = AX25_T1CLAMPHI;
292
}
293
 
294
void ax25_disconnect(ax25_cb *ax25, int reason)
295
{
296
        ax25_clear_queues(ax25);
297
 
298
        ax25_stop_t1timer(ax25);
299
        ax25_stop_t2timer(ax25);
300
        ax25_stop_t3timer(ax25);
301
        ax25_stop_idletimer(ax25);
302
 
303
        ax25->state = AX25_STATE_0;
304
 
305
        ax25_link_failed(ax25, reason);
306
 
307
        if (ax25->sk != NULL) {
308
                ax25->sk->state     = TCP_CLOSE;
309
                ax25->sk->err       = reason;
310
                ax25->sk->shutdown |= SEND_SHUTDOWN;
311
                if (!ax25->sk->dead)
312
                        ax25->sk->state_change(ax25->sk);
313
                ax25->sk->dead      = 1;
314
        }
315
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.