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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [net/] [ax25/] [ax25_subr.c] - Blame information for rev 1772

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1629 jcastillo
/*
2
 *      AX.25 release 035
3
 *
4
 *      This code REQUIRES 1.3.61 or higher/ NET3.029
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
 */
34
 
35
#include <linux/config.h>
36
#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
37
#include <linux/errno.h>
38
#include <linux/types.h>
39
#include <linux/socket.h>
40
#include <linux/in.h>
41
#include <linux/kernel.h>
42
#include <linux/sched.h>
43
#include <linux/timer.h>
44
#include <linux/string.h>
45
#include <linux/sockios.h>
46
#include <linux/net.h>
47
#include <net/ax25.h>
48
#include <linux/inet.h>
49
#include <linux/netdevice.h>
50
#include <linux/skbuff.h>
51
#include <net/sock.h>
52
#include <asm/segment.h>
53
#include <asm/system.h>
54
#include <linux/fcntl.h>
55
#include <linux/mm.h>
56
#include <linux/interrupt.h>
57
 
58
/*
59
 *      This routine purges all the queues of frames.
60
 */
61
void ax25_clear_queues(ax25_cb *ax25)
62
{
63
        struct sk_buff *skb;
64
 
65
        while ((skb = skb_dequeue(&ax25->write_queue)) != NULL)
66
                kfree_skb(skb, FREE_WRITE);
67
 
68
        while ((skb = skb_dequeue(&ax25->ack_queue)) != NULL)
69
                kfree_skb(skb, FREE_WRITE);
70
 
71
        while ((skb = skb_dequeue(&ax25->reseq_queue)) != NULL)
72
                kfree_skb(skb, FREE_READ);
73
 
74
        while ((skb = skb_dequeue(&ax25->frag_queue)) != NULL)
75
                kfree_skb(skb, FREE_READ);
76
}
77
 
78
/*
79
 * This routine purges the input queue of those frames that have been
80
 * acknowledged. This replaces the boxes labelled "V(a) <- N(r)" on the
81
 * SDL diagram.
82
 */
83
void ax25_frames_acked(ax25_cb *ax25, unsigned short nr)
84
{
85
        struct sk_buff *skb;
86
 
87
        /*
88
         * Remove all the ack-ed frames from the ack queue.
89
         */
90
        if (ax25->va != nr) {
91
                while (skb_peek(&ax25->ack_queue) != NULL && ax25->va != nr) {
92
                        skb = skb_dequeue(&ax25->ack_queue);
93
                        kfree_skb(skb, FREE_WRITE);
94
                        ax25->va = (ax25->va + 1) % ax25->modulus;
95
                        if (ax25->dama_slave)
96
                                ax25->n2count = 0;
97
                }
98
        }
99
}
100
 
101
/*
102
 * Maybe this should be your ax25_invoke_retransmission(), which appears
103
 * to be used but not do anything.  ax25_invoke_retransmission() used to
104
 * be in AX 0.29, but has now gone in 0.30.
105
 */
106
void ax25_requeue_frames(ax25_cb *ax25)
107
{
108
        struct sk_buff *skb, *skb_prev = NULL;
109
 
110
        /*
111
         * Requeue all the un-ack-ed frames on the output queue to be picked
112
         * up by ax25_kick called from the timer. This arrangement handles the
113
         * possibility of an empty output queue.
114
         */
115
        while ((skb = skb_dequeue(&ax25->ack_queue)) != NULL) {
116
                if (skb_prev == NULL)
117
                        skb_queue_head(&ax25->write_queue, skb);
118
                else
119
                        skb_append(skb_prev, skb);
120
                skb_prev = skb;
121
        }
122
}
123
 
124
/*
125
 *      Validate that the value of nr is between va and vs. Return true or
126
 *      false for testing.
127
 */
128
int ax25_validate_nr(ax25_cb *ax25, unsigned short nr)
129
{
130
        unsigned short vc = ax25->va;
131
 
132
        while (vc != ax25->vs) {
133
                if (nr == vc) return 1;
134
                vc = (vc + 1) % ax25->modulus;
135
        }
136
 
137
        if (nr == ax25->vs) return 1;
138
 
139
        return 0;
140
}
141
 
142
/*
143
 *      This routine is the centralised routine for parsing the control
144
 *      information for the different frame formats.
145
 */
146
int ax25_decode(ax25_cb *ax25, struct sk_buff *skb, int *ns, int *nr, int *pf)
147
{
148
        unsigned char *frame;
149
        int frametype = AX25_ILLEGAL;
150
 
151
        frame = skb->data;
152
        *ns = *nr = *pf = 0;
153
 
154
        if (ax25->modulus == AX25_MODULUS) {
155
                if ((frame[0] & AX25_S) == 0) {
156
                        frametype = AX25_I;                     /* I frame - carries NR/NS/PF */
157
                        *ns = (frame[0] >> 1) & 0x07;
158
                        *nr = (frame[0] >> 5) & 0x07;
159
                        *pf = frame[0] & AX25_PF;
160
                } else if ((frame[0] & AX25_U) == 1) {   /* S frame - take out PF/NR */
161
                        frametype = frame[0] & 0x0F;
162
                        *nr = (frame[0] >> 5) & 0x07;
163
                        *pf = frame[0] & AX25_PF;
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
                }
168
                skb_pull(skb, 1);
169
        } else {
170
                if ((frame[0] & AX25_S) == 0) {
171
                        frametype = AX25_I;                     /* I frame - carries NR/NS/PF */
172
                        *ns = (frame[0] >> 1) & 0x7F;
173
                        *nr = (frame[1] >> 1) & 0x7F;
174
                        *pf = frame[1] & AX25_EPF;
175
                        skb_pull(skb, 2);
176
                } else if ((frame[0] & AX25_U) == 1) {   /* S frame - take out PF/NR */
177
                        frametype = frame[0] & 0x0F;
178
                        *nr = (frame[1] >> 1) & 0x7F;
179
                        *pf = frame[1] & AX25_EPF;
180
                        skb_pull(skb, 2);
181
                } else if ((frame[0] & AX25_U) == 3) {   /* U frame - take out PF */
182
                        frametype = frame[0] & ~AX25_PF;
183
                        *pf = frame[0] & AX25_PF;
184
                        skb_pull(skb, 1);
185
                }
186
        }
187
 
188
        return frametype;
189
}
190
 
191
/*
192
 *      This routine is called when the HDLC layer internally  generates a
193
 *      command or  response  for  the remote machine ( eg. RR, UA etc. ).
194
 *      Only supervisory or unnumbered frames are processed.
195
 */
196
void ax25_send_control(ax25_cb *ax25, int frametype, int poll_bit, int type)
197
{
198
        struct sk_buff *skb;
199
        unsigned char  *dptr;
200
        struct device *dev;
201
 
202
        if ((dev = ax25->device) == NULL)
203
                return; /* Route died */
204
 
205
        if ((skb = alloc_skb(AX25_BPQ_HEADER_LEN + size_ax25_addr(ax25->digipeat) + 2, GFP_ATOMIC)) == NULL)
206
                return;
207
 
208
        skb->free = 1;
209
 
210
        skb_reserve(skb, AX25_BPQ_HEADER_LEN + size_ax25_addr(ax25->digipeat));
211
 
212
        /* Assume a response - address structure for DTE */
213
        if (ax25->modulus == AX25_MODULUS) {
214
                dptr = skb_put(skb, 1);
215
                *dptr = frametype;
216
                *dptr |= (poll_bit) ? AX25_PF : 0;
217
                if ((frametype & AX25_U) == AX25_S)             /* S frames carry NR */
218
                        *dptr |= (ax25->vr << 5);
219
        } else {
220
                if ((frametype & AX25_U) == AX25_U) {
221
                        dptr = skb_put(skb, 1);
222
                        *dptr = frametype;
223
                        *dptr |= (poll_bit) ? AX25_PF : 0;
224
                } else {
225
                        dptr = skb_put(skb, 2);
226
                        dptr[0] = frametype;
227
                        dptr[1] = (ax25->vr << 1);
228
                        dptr[1] |= (poll_bit) ? AX25_EPF : 0;
229
                }
230
        }
231
 
232
        ax25_transmit_buffer(ax25, skb, type);
233
}
234
 
235
/*
236
 *      Send a 'DM' to an unknown connection attempt, or an invalid caller.
237
 *
238
 *      Note: src here is the sender, thus it's the target of the DM
239
 */
240
void ax25_return_dm(struct device *dev, ax25_address *src, ax25_address *dest, ax25_digi *digi)
241
{
242
        struct sk_buff *skb;
243
        char *dptr;
244
        ax25_digi retdigi;
245
 
246
        if (dev == NULL)
247
                return;
248
 
249
        if ((skb = alloc_skb(AX25_BPQ_HEADER_LEN + size_ax25_addr(digi) + 1, GFP_ATOMIC)) == NULL)
250
                return; /* Next SABM will get DM'd */
251
 
252
        skb->free = 1;
253
 
254
        skb_reserve(skb, AX25_BPQ_HEADER_LEN + size_ax25_addr(digi));
255
 
256
        ax25_digi_invert(digi, &retdigi);
257
 
258
        dptr = skb_put(skb, 1);
259
 
260
        *dptr = AX25_DM | AX25_PF;
261
 
262
        /*
263
         *      Do the address ourselves
264
         */
265
        dptr  = skb_push(skb, size_ax25_addr(digi));
266
        dptr += build_ax25_addr(dptr, dest, src, &retdigi, AX25_RESPONSE, AX25_MODULUS);
267
 
268
        ax25_queue_xmit(skb, dev, SOPRI_NORMAL);
269
}
270
 
271
/*
272
 *      Exponential backoff for AX.25
273
 */
274
unsigned short ax25_calculate_t1(ax25_cb *ax25)
275
{
276
        int n, t = 2;
277
 
278
        switch (ax25->backoff) {
279
                case 0:
280
                        break;
281
 
282
                case 1:
283
                        t += 2 * ax25->n2count;
284
                        break;
285
 
286
                case 2:
287
                        for (n = 0; n < ax25->n2count; n++)
288
                                t *= 2;
289
                        if (t > 8) t = 8;
290
                        break;
291
        }
292
 
293
        return t * ax25->rtt;
294
}
295
 
296
/*
297
 *      Calculate the Round Trip Time
298
 */
299
void ax25_calculate_rtt(ax25_cb *ax25)
300
{
301
        switch (ax25->backoff) {
302
                case 0:
303
                        ax25->rtt = ax25->t1 / 2;
304
                        break;
305
 
306
                case 1:
307
                case 2:
308
                        if (ax25->t1timer > 0 && ax25->n2count == 0)
309
                                ax25->rtt = (9 * ax25->rtt + ax25->t1 - ax25->t1timer) / 10;
310
                        break;
311
        }
312
 
313
        if (ax25->rtt < AX25_T1CLAMPLO)
314
                ax25->rtt = AX25_T1CLAMPLO;
315
 
316
        if (ax25->rtt > AX25_T1CLAMPHI)
317
                ax25->rtt = AX25_T1CLAMPHI;
318
}
319
 
320
/*
321
 *      Digipeated address processing
322
 */
323
 
324
 
325
/*
326
 *      Given an AX.25 address pull of to, from, digi list, command/response and the start of data
327
 *
328
 */
329
unsigned char *ax25_parse_addr(unsigned char *buf, int len, ax25_address *src, ax25_address *dest, ax25_digi *digi, int *flags, int *dama)
330
{
331
        int d = 0;
332
 
333
        if (len < 14) return NULL;
334
 
335
        *flags = 0;
336
 
337
        if (buf[6] & AX25_CBIT)
338
                *flags = AX25_COMMAND;
339
        if (buf[13] & AX25_CBIT)
340
                *flags = AX25_RESPONSE;
341
 
342
        if (dama != NULL)
343
                *dama = ~buf[13] & AX25_DAMA_FLAG;
344
 
345
        /* Copy to, from */
346
        memcpy(dest, buf + 0, AX25_ADDR_LEN);
347
        memcpy(src,  buf + 7, AX25_ADDR_LEN);
348
 
349
        buf += 2 * AX25_ADDR_LEN;
350
        len -= 2 * AX25_ADDR_LEN;
351
 
352
        digi->lastrepeat = -1;
353
        digi->ndigi      = 0;
354
 
355
        while (!(buf[-1] & AX25_EBIT)) {
356
                if (d >= AX25_MAX_DIGIS)  return NULL;  /* Max of 6 digis */
357
                if (len < 7) return NULL;       /* Short packet */
358
 
359
                memcpy(&digi->calls[d], buf, AX25_ADDR_LEN);
360
                digi->ndigi = d + 1;
361
 
362
                if (buf[6] & AX25_HBIT) {
363
                        digi->repeated[d] = 1;
364
                        digi->lastrepeat  = d;
365
                } else {
366
                        digi->repeated[d] = 0;
367
                }
368
 
369
                buf += AX25_ADDR_LEN;
370
                len -= AX25_ADDR_LEN;
371
                d++;
372
        }
373
 
374
        return buf;
375
}
376
 
377
/*
378
 *      Assemble an AX.25 header from the bits
379
 */
380
int build_ax25_addr(unsigned char *buf, ax25_address *src, ax25_address *dest, ax25_digi *d, int flag, int modulus)
381
{
382
        int len = 0;
383
        int ct  = 0;
384
 
385
        memcpy(buf, dest, AX25_ADDR_LEN);
386
        buf[6] &= ~(AX25_EBIT | AX25_CBIT);
387
        buf[6] |= AX25_SSSID_SPARE;
388
 
389
        if (flag == AX25_COMMAND) buf[6] |= AX25_CBIT;
390
 
391
        buf += AX25_ADDR_LEN;
392
        len += AX25_ADDR_LEN;
393
 
394
        memcpy(buf, src, AX25_ADDR_LEN);
395
        buf[6] &= ~(AX25_EBIT | AX25_CBIT);
396
        buf[6] &= ~AX25_SSSID_SPARE;
397
 
398
        if (modulus == AX25_MODULUS)
399
                buf[6] |= AX25_SSSID_SPARE;
400
        else
401
                buf[6] |= AX25_ESSID_SPARE;
402
 
403
        if (flag == AX25_RESPONSE) buf[6] |= AX25_CBIT;
404
 
405
        /*
406
         *      Fast path the normal digiless path
407
         */
408
        if (d == NULL || d->ndigi == 0) {
409
                buf[6] |= AX25_EBIT;
410
                return 2 * AX25_ADDR_LEN;
411
        }
412
 
413
        buf += AX25_ADDR_LEN;
414
        len += AX25_ADDR_LEN;
415
 
416
        while (ct < d->ndigi) {
417
                memcpy(buf, &d->calls[ct], AX25_ADDR_LEN);
418
 
419
                if (d->repeated[ct])
420
                        buf[6] |= AX25_HBIT;
421
                else
422
                        buf[6] &= ~AX25_HBIT;
423
 
424
                buf[6] &= ~AX25_EBIT;
425
                buf[6] |= AX25_SSSID_SPARE;
426
 
427
                buf += AX25_ADDR_LEN;
428
                len += AX25_ADDR_LEN;
429
                ct++;
430
        }
431
 
432
        buf[-1] |= AX25_EBIT;
433
 
434
        return len;
435
}
436
 
437
int size_ax25_addr(ax25_digi *dp)
438
{
439
        if (dp == NULL)
440
                return 2 * AX25_ADDR_LEN;
441
 
442
        return AX25_ADDR_LEN * (2 + dp->ndigi);
443
}
444
 
445
/*
446
 *      Reverse Digipeat List. May not pass both parameters as same struct
447
 */
448
void ax25_digi_invert(ax25_digi *in, ax25_digi *out)
449
{
450
        int ct;
451
 
452
        out->ndigi      = in->ndigi;
453
        out->lastrepeat = in->ndigi - in->lastrepeat - 2;
454
 
455
        /* Invert the digipeaters */
456
 
457
        for (ct = 0; ct < in->ndigi; ct++) {
458
                out->calls[ct] = in->calls[in->ndigi - ct - 1];
459
 
460
                if (ct <= out->lastrepeat) {
461
                        out->calls[ct].ax25_call[6] |= AX25_HBIT;
462
                        out->repeated[ct]            = 1;
463
                } else {
464
                        out->calls[ct].ax25_call[6] &= ~AX25_HBIT;
465
                        out->repeated[ct]            = 0;
466
                }
467
        }
468
}
469
 
470
/*
471
 *      :::FIXME:::
472
 *      This is ****NOT**** the right approach. Not all drivers do kiss. We
473
 *      need a driver level request to switch duplex mode, that does either
474
 *      SCC changing, PI config or KISS as required.
475
 *
476
 *      Not to mention this request isn't currently reliable.
477
 */
478
void ax25_kiss_cmd(ax25_cb *ax25, unsigned char cmd, unsigned char param)
479
{
480
        struct sk_buff *skb;
481
        unsigned char *p;
482
 
483
        if (ax25->device == NULL)
484
                return;
485
 
486
        if ((skb = alloc_skb(2, GFP_ATOMIC)) == NULL)
487
                return;
488
 
489
        skb->free = 1;
490
        skb->arp  = 1;
491
 
492
        skb->protocol = htons(ETH_P_AX25);
493
 
494
        p = skb_put(skb, 2);
495
 
496
        *p++ = cmd;
497
        *p++ = param;
498
 
499
        dev_queue_xmit(skb, ax25->device, SOPRI_NORMAL);
500
}
501
 
502
void ax25_dama_on(ax25_cb *ax25)
503
{
504
        if (ax25_dev_is_dama_slave(ax25->device) == 0) {
505
                if (ax25->sk != NULL && ax25->sk->debug)
506
                        printk("ax25_dama_on: DAMA on\n");
507
 
508
                ax25_kiss_cmd(ax25, 5, 1);
509
        }
510
}
511
 
512
void ax25_dama_off(ax25_cb *ax25)
513
{
514
        if (ax25->dama_slave == 0)
515
                return;
516
 
517
        ax25->dama_slave = 0;
518
 
519
        if (ax25_dev_is_dama_slave(ax25->device) == 0) {
520
                if (ax25->sk != NULL && ax25->sk->debug)
521
                        printk("ax25_dama_off: DAMA off\n");
522
 
523
                ax25_kiss_cmd(ax25, 5, 0);
524
        }
525
}
526
 
527
void ax25_disconnect(ax25_cb *ax25, int reason)
528
{
529
        ax25_clear_queues(ax25);
530
 
531
        ax25_dama_off(ax25);
532
 
533
        ax25->t1timer   = 0;
534
        ax25->t2timer   = 0;
535
        ax25->t3timer   = 0;
536
        ax25->idletimer = 0;
537
 
538
        ax25->state = AX25_STATE_0;
539
 
540
        ax25_link_failed(ax25, reason);
541
 
542
        if (ax25->sk != NULL) {
543
                ax25->sk->state     = TCP_CLOSE;
544
                ax25->sk->err       = reason;
545
                ax25->sk->shutdown |= SEND_SHUTDOWN;
546
                if (!ax25->sk->dead)
547
                        ax25->sk->state_change(ax25->sk);
548
                ax25->sk->dead      = 1;
549
        }
550
}
551
 
552
#endif

powered by: WebSVN 2.1.0

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