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

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [net/] [rose/] [rose_subr.c] - Blame information for rev 67

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

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

powered by: WebSVN 2.1.0

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