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

Subversion Repositories or1k

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 *      ROSE release 003
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
 *      History
13
 *      ROSE 001        Jonathan(G4KLX) Cloned from nr_subr.c
14
 *      ROSE 002        Jonathan(G4KLX) Centralised disconnect processing.
15
 *      ROSE 003        Jonathan(G4KLX) Added use count to neighbours.
16
 */
17
 
18
#include <linux/errno.h>
19
#include <linux/types.h>
20
#include <linux/socket.h>
21
#include <linux/in.h>
22
#include <linux/kernel.h>
23
#include <linux/sched.h>
24
#include <linux/timer.h>
25
#include <linux/string.h>
26
#include <linux/sockios.h>
27
#include <linux/net.h>
28
#include <net/ax25.h>
29
#include <linux/inet.h>
30
#include <linux/netdevice.h>
31
#include <linux/skbuff.h>
32
#include <net/sock.h>
33
#include <asm/segment.h>
34
#include <asm/system.h>
35
#include <linux/fcntl.h>
36
#include <linux/mm.h>
37
#include <linux/interrupt.h>
38
#include <net/rose.h>
39
 
40
/*
41
 *      This routine purges all of the queues of frames.
42
 */
43
void rose_clear_queues(struct sock *sk)
44
{
45
        skb_queue_purge(&sk->write_queue);
46
        skb_queue_purge(&sk->protinfo.rose->ack_queue);
47
}
48
 
49
/*
50
 * This routine purges the input queue of those frames that have been
51
 * acknowledged. This replaces the boxes labelled "V(a) <- N(r)" on the
52
 * SDL diagram.
53
 */
54
void rose_frames_acked(struct sock *sk, unsigned short nr)
55
{
56
        struct sk_buff *skb;
57
 
58
        /*
59
         * Remove all the ack-ed frames from the ack queue.
60
         */
61
        if (sk->protinfo.rose->va != nr) {
62
                while (skb_peek(&sk->protinfo.rose->ack_queue) != NULL && sk->protinfo.rose->va != nr) {
63
                        skb = skb_dequeue(&sk->protinfo.rose->ack_queue);
64
                        kfree_skb(skb);
65
                        sk->protinfo.rose->va = (sk->protinfo.rose->va + 1) % ROSE_MODULUS;
66
                }
67
        }
68
}
69
 
70
void rose_requeue_frames(struct sock *sk)
71
{
72
        struct sk_buff *skb, *skb_prev = NULL;
73
 
74
        /*
75
         * Requeue all the un-ack-ed frames on the output queue to be picked
76
         * up by rose_kick. This arrangement handles the possibility of an
77
         * empty output queue.
78
         */
79
        while ((skb = skb_dequeue(&sk->protinfo.rose->ack_queue)) != NULL) {
80
                if (skb_prev == NULL)
81
                        skb_queue_head(&sk->write_queue, skb);
82
                else
83
                        skb_append(skb_prev, skb);
84
                skb_prev = skb;
85
        }
86
}
87
 
88
/*
89
 *      Validate that the value of nr is between va and vs. Return true or
90
 *      false for testing.
91
 */
92
int rose_validate_nr(struct sock *sk, unsigned short nr)
93
{
94
        unsigned short vc = sk->protinfo.rose->va;
95
 
96
        while (vc != sk->protinfo.rose->vs) {
97
                if (nr == vc) return 1;
98
                vc = (vc + 1) % ROSE_MODULUS;
99
        }
100
 
101
        if (nr == sk->protinfo.rose->vs) return 1;
102
 
103
        return 0;
104
}
105
 
106
/*
107
 *  This routine is called when the packet layer internally generates a
108
 *  control frame.
109
 */
110
void rose_write_internal(struct sock *sk, int frametype)
111
{
112
        struct sk_buff *skb;
113
        unsigned char  *dptr;
114
        unsigned char  lci1, lci2;
115
        char buffer[100];
116
        int len, faclen = 0;
117
        int ax25_header_len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + 1;
118
 
119
        len = ax25_header_len + ROSE_MIN_LEN;
120
 
121
        switch (frametype) {
122
                case ROSE_CALL_REQUEST:
123
                        len   += 1 + ROSE_ADDR_LEN + ROSE_ADDR_LEN;
124
                        faclen = rose_create_facilities(buffer, sk->protinfo.rose);
125
                        len   += faclen;
126
                        break;
127
                case ROSE_CALL_ACCEPTED:
128
                case ROSE_RESET_REQUEST:
129
                        len   += 2;
130
                        break;
131
                case ROSE_CLEAR_REQUEST:
132
                        len   += 3;
133
                        /* facilities */
134
                        faclen = 3 + 2 + AX25_ADDR_LEN + 3 + ROSE_ADDR_LEN;
135
                        dptr = buffer;
136
                        *dptr++ = faclen-1;     /* Facilities length */
137
                        *dptr++ = 0;
138
                        *dptr++ = FAC_NATIONAL;
139
                        *dptr++ = FAC_NATIONAL_FAIL_CALL;
140
                        *dptr++ = AX25_ADDR_LEN;
141
                        memcpy(dptr, &rose_callsign, AX25_ADDR_LEN);
142
                        dptr += AX25_ADDR_LEN;
143
                        *dptr++ = FAC_NATIONAL_FAIL_ADD;
144
                        *dptr++ = ROSE_ADDR_LEN + 1;
145
                        *dptr++ = ROSE_ADDR_LEN * 2;
146
                        memcpy(dptr, &sk->protinfo.rose->source_addr, ROSE_ADDR_LEN);
147
                        len   += faclen;
148
                        break;
149
        }
150
 
151
        if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
152
                return;
153
 
154
        /*
155
         *      Space for AX.25 header and PID.
156
         */
157
        skb_reserve(skb, ax25_header_len);
158
 
159
        dptr = skb_put(skb, len - ax25_header_len);
160
 
161
        lci1 = (sk->protinfo.rose->lci >> 8) & 0x0F;
162
        lci2 = (sk->protinfo.rose->lci >> 0) & 0xFF;
163
 
164
        switch (frametype) {
165
 
166
                case ROSE_CALL_REQUEST:
167
                        *dptr++ = ROSE_GFI | lci1;
168
                        *dptr++ = lci2;
169
                        *dptr++ = frametype;
170
                        *dptr++ = 0xAA;
171
                        memcpy(dptr, &sk->protinfo.rose->dest_addr,  ROSE_ADDR_LEN);
172
                        dptr   += ROSE_ADDR_LEN;
173
                        memcpy(dptr, &sk->protinfo.rose->source_addr, ROSE_ADDR_LEN);
174
                        dptr   += ROSE_ADDR_LEN;
175
                        memcpy(dptr, buffer, faclen);
176
                        dptr   += faclen;
177
                        break;
178
 
179
                case ROSE_CALL_ACCEPTED:
180
                        *dptr++ = ROSE_GFI | lci1;
181
                        *dptr++ = lci2;
182
                        *dptr++ = frametype;
183
                        *dptr++ = 0x00;         /* Address length */
184
                        *dptr++ = 0;             /* Facilities length */
185
                        break;
186
 
187
                case ROSE_CLEAR_REQUEST:
188
                        *dptr++ = ROSE_GFI | lci1;
189
                        *dptr++ = lci2;
190
                        *dptr++ = frametype;
191
                        *dptr++ = sk->protinfo.rose->cause;
192
                        *dptr++ = sk->protinfo.rose->diagnostic;
193
                        *dptr++ = 0x00;         /* Address length */
194
                        memcpy(dptr, buffer, faclen);
195
                        dptr   += faclen;
196
                        break;
197
 
198
                case ROSE_RESET_REQUEST:
199
                        *dptr++ = ROSE_GFI | lci1;
200
                        *dptr++ = lci2;
201
                        *dptr++ = frametype;
202
                        *dptr++ = ROSE_DTE_ORIGINATED;
203
                        *dptr++ = 0;
204
                        break;
205
 
206
                case ROSE_RR:
207
                case ROSE_RNR:
208
                        *dptr++ = ROSE_GFI | lci1;
209
                        *dptr++ = lci2;
210
                        *dptr   = frametype;
211
                        *dptr++ |= (sk->protinfo.rose->vr << 5) & 0xE0;
212
                        break;
213
 
214
                case ROSE_CLEAR_CONFIRMATION:
215
                case ROSE_RESET_CONFIRMATION:
216
                        *dptr++ = ROSE_GFI | lci1;
217
                        *dptr++ = lci2;
218
                        *dptr++  = frametype;
219
                        break;
220
 
221
                default:
222
                        printk(KERN_ERR "ROSE: rose_write_internal - invalid frametype %02X\n", frametype);
223
                        kfree_skb(skb);
224
                        return;
225
        }
226
 
227
        rose_transmit_link(skb, sk->protinfo.rose->neighbour);
228
}
229
 
230
int rose_decode(struct sk_buff *skb, int *ns, int *nr, int *q, int *d, int *m)
231
{
232
        unsigned char *frame;
233
 
234
        frame = skb->data;
235
 
236
        *ns = *nr = *q = *d = *m = 0;
237
 
238
        switch (frame[2]) {
239
                case ROSE_CALL_REQUEST:
240
                case ROSE_CALL_ACCEPTED:
241
                case ROSE_CLEAR_REQUEST:
242
                case ROSE_CLEAR_CONFIRMATION:
243
                case ROSE_RESET_REQUEST:
244
                case ROSE_RESET_CONFIRMATION:
245
                        return frame[2];
246
                default:
247
                        break;
248
        }
249
 
250
        if ((frame[2] & 0x1F) == ROSE_RR  ||
251
            (frame[2] & 0x1F) == ROSE_RNR) {
252
                *nr = (frame[2] >> 5) & 0x07;
253
                return frame[2] & 0x1F;
254
        }
255
 
256
        if ((frame[2] & 0x01) == ROSE_DATA) {
257
                *q  = (frame[0] & ROSE_Q_BIT) == ROSE_Q_BIT;
258
                *d  = (frame[0] & ROSE_D_BIT) == ROSE_D_BIT;
259
                *m  = (frame[2] & ROSE_M_BIT) == ROSE_M_BIT;
260
                *nr = (frame[2] >> 5) & 0x07;
261
                *ns = (frame[2] >> 1) & 0x07;
262
                return ROSE_DATA;
263
        }
264
 
265
        return ROSE_ILLEGAL;
266
}
267
 
268
static int rose_parse_national(unsigned char *p, struct rose_facilities_struct *facilities, int len)
269
{
270
        unsigned char *pt;
271
        unsigned char l, lg, n = 0;
272
        int fac_national_digis_received = 0;
273
 
274
        do {
275
                switch (*p & 0xC0) {
276
                        case 0x00:
277
                                p   += 2;
278
                                n   += 2;
279
                                len -= 2;
280
                                break;
281
 
282
                        case 0x40:
283
                                if (*p == FAC_NATIONAL_RAND)
284
                                        facilities->rand = ((p[1] << 8) & 0xFF00) + ((p[2] << 0) & 0x00FF);
285
                                p   += 3;
286
                                n   += 3;
287
                                len -= 3;
288
                                break;
289
 
290
                        case 0x80:
291
                                p   += 4;
292
                                n   += 4;
293
                                len -= 4;
294
                                break;
295
 
296
                        case 0xC0:
297
                                l = p[1];
298
                                if (*p == FAC_NATIONAL_DEST_DIGI) {
299
                                        if (!fac_national_digis_received) {
300
                                                memcpy(&facilities->source_digis[0], p + 2, AX25_ADDR_LEN);
301
                                                facilities->source_ndigis = 1;
302
                                        }
303
                                }
304
                                else if (*p == FAC_NATIONAL_SRC_DIGI) {
305
                                        if (!fac_national_digis_received) {
306
                                                memcpy(&facilities->dest_digis[0], p + 2, AX25_ADDR_LEN);
307
                                                facilities->dest_ndigis = 1;
308
                                        }
309
                                }
310
                                else if (*p == FAC_NATIONAL_FAIL_CALL) {
311
                                        memcpy(&facilities->fail_call, p + 2, AX25_ADDR_LEN);
312
                                }
313
                                else if (*p == FAC_NATIONAL_FAIL_ADD) {
314
                                        memcpy(&facilities->fail_addr, p + 3, ROSE_ADDR_LEN);
315
                                }
316
                                else if (*p == FAC_NATIONAL_DIGIS) {
317
                                        fac_national_digis_received = 1;
318
                                        facilities->source_ndigis = 0;
319
                                        facilities->dest_ndigis   = 0;
320
                                        for (pt = p + 2, lg = 0 ; lg < l ; pt += AX25_ADDR_LEN, lg += AX25_ADDR_LEN) {
321
                                                if (pt[6] & AX25_HBIT)
322
                                                        memcpy(&facilities->dest_digis[facilities->dest_ndigis++], pt, AX25_ADDR_LEN);
323
                                                else
324
                                                        memcpy(&facilities->source_digis[facilities->source_ndigis++], pt, AX25_ADDR_LEN);
325
                                        }
326
                                }
327
                                p   += l + 2;
328
                                n   += l + 2;
329
                                len -= l + 2;
330
                                break;
331
                }
332
        } while (*p != 0x00 && len > 0);
333
 
334
        return n;
335
}
336
 
337
static int rose_parse_ccitt(unsigned char *p, struct rose_facilities_struct *facilities, int len)
338
{
339
        unsigned char l, n = 0;
340
        char callsign[11];
341
 
342
        do {
343
                switch (*p & 0xC0) {
344
                        case 0x00:
345
                                p   += 2;
346
                                n   += 2;
347
                                len -= 2;
348
                                break;
349
 
350
                        case 0x40:
351
                                p   += 3;
352
                                n   += 3;
353
                                len -= 3;
354
                                break;
355
 
356
                        case 0x80:
357
                                p   += 4;
358
                                n   += 4;
359
                                len -= 4;
360
                                break;
361
 
362
                        case 0xC0:
363
                                l = p[1];
364
                                if (*p == FAC_CCITT_DEST_NSAP) {
365
                                        memcpy(&facilities->source_addr, p + 7, ROSE_ADDR_LEN);
366
                                        memcpy(callsign, p + 12,   l - 10);
367
                                        callsign[l - 10] = '\0';
368
                                        facilities->source_call = *asc2ax(callsign);
369
                                }
370
                                if (*p == FAC_CCITT_SRC_NSAP) {
371
                                        memcpy(&facilities->dest_addr, p + 7, ROSE_ADDR_LEN);
372
                                        memcpy(callsign, p + 12, l - 10);
373
                                        callsign[l - 10] = '\0';
374
                                        facilities->dest_call = *asc2ax(callsign);
375
                                }
376
                                p   += l + 2;
377
                                n   += l + 2;
378
                                len -= l + 2;
379
                                break;
380
                }
381
        } while (*p != 0x00 && len > 0);
382
 
383
        return n;
384
}
385
 
386
int rose_parse_facilities(unsigned char *p, struct rose_facilities_struct *facilities)
387
{
388
        int facilities_len, len;
389
 
390
        facilities_len = *p++;
391
 
392
        if (facilities_len == 0)
393
                return 0;
394
 
395
        while (facilities_len > 0) {
396
                if (*p == 0x00) {
397
                        facilities_len--;
398
                        p++;
399
 
400
                        switch (*p) {
401
                                case FAC_NATIONAL:              /* National */
402
                                        len = rose_parse_national(p + 1, facilities, facilities_len - 1);
403
                                        facilities_len -= len + 1;
404
                                        p += len + 1;
405
                                        break;
406
 
407
                                case FAC_CCITT:         /* CCITT */
408
                                        len = rose_parse_ccitt(p + 1, facilities, facilities_len - 1);
409
                                        facilities_len -= len + 1;
410
                                        p += len + 1;
411
                                        break;
412
 
413
                                default:
414
                                        printk(KERN_DEBUG "ROSE: rose_parse_facilities - unknown facilities family %02X\n", *p);
415
                                        facilities_len--;
416
                                        p++;
417
                                        break;
418
                        }
419
                }
420
                else break;     /* Error in facilities format */
421
        }
422
 
423
        return 1;
424
}
425
 
426
int rose_create_facilities(unsigned char *buffer, rose_cb *rose)
427
{
428
        unsigned char *p = buffer + 1;
429
        char *callsign;
430
        int len, nb;
431
 
432
        /* National Facilities */
433
        if (rose->rand != 0 || rose->source_ndigis == 1 || rose->dest_ndigis == 1) {
434
                *p++ = 0x00;
435
                *p++ = FAC_NATIONAL;
436
 
437
                if (rose->rand != 0) {
438
                        *p++ = FAC_NATIONAL_RAND;
439
                        *p++ = (rose->rand >> 8) & 0xFF;
440
                        *p++ = (rose->rand >> 0) & 0xFF;
441
                }
442
 
443
                /* Sent before older facilities */
444
                if ((rose->source_ndigis > 0) || (rose->dest_ndigis > 0)) {
445
                        int maxdigi = 0;
446
                        *p++ = FAC_NATIONAL_DIGIS;
447
                        *p++ = AX25_ADDR_LEN * (rose->source_ndigis + rose->dest_ndigis);
448
                        for (nb = 0 ; nb < rose->source_ndigis ; nb++) {
449
                                if (++maxdigi >= ROSE_MAX_DIGIS)
450
                                        break;
451
                                memcpy(p, &rose->source_digis[nb], AX25_ADDR_LEN);
452
                                p[6] |= AX25_HBIT;
453
                                p += AX25_ADDR_LEN;
454
                        }
455
                        for (nb = 0 ; nb < rose->dest_ndigis ; nb++) {
456
                                if (++maxdigi >= ROSE_MAX_DIGIS)
457
                                        break;
458
                                memcpy(p, &rose->dest_digis[nb], AX25_ADDR_LEN);
459
                                p[6] &= ~AX25_HBIT;
460
                                p += AX25_ADDR_LEN;
461
                        }
462
                }
463
 
464
                /* For compatibility */
465
                if (rose->source_ndigis > 0) {
466
                        *p++ = FAC_NATIONAL_SRC_DIGI;
467
                        *p++ = AX25_ADDR_LEN;
468
                        memcpy(p, &rose->source_digis[0], AX25_ADDR_LEN);
469
                        p   += AX25_ADDR_LEN;
470
                }
471
 
472
                /* For compatibility */
473
                if (rose->dest_ndigis > 0) {
474
                        *p++ = FAC_NATIONAL_DEST_DIGI;
475
                        *p++ = AX25_ADDR_LEN;
476
                        memcpy(p, &rose->dest_digis[0], AX25_ADDR_LEN);
477
                        p   += AX25_ADDR_LEN;
478
                }
479
        }
480
 
481
        *p++ = 0x00;
482
        *p++ = FAC_CCITT;
483
 
484
        *p++ = FAC_CCITT_DEST_NSAP;
485
 
486
        callsign = ax2asc(&rose->dest_call);
487
 
488
        *p++ = strlen(callsign) + 10;
489
        *p++ = (strlen(callsign) + 9) * 2;              /* ??? */
490
 
491
        *p++ = 0x47; *p++ = 0x00; *p++ = 0x11;
492
        *p++ = ROSE_ADDR_LEN * 2;
493
        memcpy(p, &rose->dest_addr, ROSE_ADDR_LEN);
494
        p   += ROSE_ADDR_LEN;
495
 
496
        memcpy(p, callsign, strlen(callsign));
497
        p   += strlen(callsign);
498
 
499
        *p++ = FAC_CCITT_SRC_NSAP;
500
 
501
        callsign = ax2asc(&rose->source_call);
502
 
503
        *p++ = strlen(callsign) + 10;
504
        *p++ = (strlen(callsign) + 9) * 2;              /* ??? */
505
 
506
        *p++ = 0x47; *p++ = 0x00; *p++ = 0x11;
507
        *p++ = ROSE_ADDR_LEN * 2;
508
        memcpy(p, &rose->source_addr, ROSE_ADDR_LEN);
509
        p   += ROSE_ADDR_LEN;
510
 
511
        memcpy(p, callsign, strlen(callsign));
512
        p   += strlen(callsign);
513
 
514
        len       = p - buffer;
515
        buffer[0] = len - 1;
516
 
517
        return len;
518
}
519
 
520
void rose_disconnect(struct sock *sk, int reason, int cause, int diagnostic)
521
{
522
        rose_stop_timer(sk);
523
        rose_stop_idletimer(sk);
524
 
525
        rose_clear_queues(sk);
526
 
527
        sk->protinfo.rose->lci   = 0;
528
        sk->protinfo.rose->state = ROSE_STATE_0;
529
 
530
        if (cause != -1)
531
                sk->protinfo.rose->cause = cause;
532
 
533
        if (diagnostic != -1)
534
                sk->protinfo.rose->diagnostic = diagnostic;
535
 
536
        sk->state     = TCP_CLOSE;
537
        sk->err       = reason;
538
        sk->shutdown |= SEND_SHUTDOWN;
539
 
540
        if (!sk->dead)
541
                sk->state_change(sk);
542
 
543
        sk->dead  = 1;
544
}

powered by: WebSVN 2.1.0

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