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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [uclinux/] [uClinux-2.0.x/] [net/] [rose/] [rose_route.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 199 simons
/*
2
 *      ROSE release 003
3
 *
4
 *      This code REQUIRES 2.1.0 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
 *      History
13
 *      ROSE 001        Jonathan(G4KLX) Cloned from nr_route.c.
14
 *                      Terry(VK2KTJ)   Added support for variable length
15
 *                                      address masks.
16
 *      ROSE 002        Jonathan(G4KLX) Uprated through routing of packets.
17
 *                                      Routing loop detection.
18
 *      ROSE 003        Jonathan(G4KLX) Added use count to neighbours.
19
 */
20
 
21
#include <linux/config.h>
22
#if defined(CONFIG_ROSE) || defined(CONFIG_ROSE_MODULE)
23
#include <linux/errno.h>
24
#include <linux/types.h>
25
#include <linux/socket.h>
26
#include <linux/in.h>
27
#include <linux/kernel.h>
28
#include <linux/sched.h>
29
#include <linux/timer.h>
30
#include <linux/string.h>
31
#include <linux/sockios.h>
32
#include <linux/net.h>
33
#include <net/ax25.h>
34
#include <linux/inet.h>
35
#include <linux/netdevice.h>
36
#include <net/arp.h>
37
#include <linux/if_arp.h>
38
#include <linux/skbuff.h>
39
#include <net/sock.h>
40
#include <asm/segment.h>
41
#include <asm/system.h>
42
#include <linux/fcntl.h>
43
#include <linux/termios.h>      /* For TIOCINQ/OUTQ */
44
#include <linux/mm.h>
45
#include <linux/interrupt.h>
46
#include <linux/notifier.h>
47
#include <linux/firewall.h>
48
#include <net/rose.h>
49
 
50
static unsigned int rose_neigh_no = 1;
51
 
52
static struct rose_node  *rose_node_list  = NULL;
53
static struct rose_neigh *rose_neigh_list = NULL;
54
static struct rose_route *rose_route_list = NULL;
55
 
56
static void rose_remove_neigh(struct rose_neigh *);
57
static int rose_del_node(struct rose_route_struct *, struct device *);
58
 
59
static int rose_is_null(rose_address *address)
60
{
61
        int i;
62
 
63
        for (i = 0 ; i < sizeof(rose_address) ; i++)
64
                if (address->rose_addr[i])
65
                        return 0;
66
        return 1;
67
}
68
 
69
/*
70
 *      Add a new route to a node, and in the process add the node and the
71
 *      neighbour if it is new.
72
 */
73
static int rose_add_node(struct rose_route_struct *rose_route, struct device *dev)
74
{
75
        struct rose_node  *rose_node, *rose_tmpn, *rose_tmpp;
76
        struct rose_neigh *rose_neigh;
77
        struct rose_route_struct dummy_route;
78
        unsigned long flags;
79
        int i;
80
 
81
        for (rose_node = rose_node_list; rose_node != NULL; rose_node = rose_node->next)
82
                if ((rose_node->mask == rose_route->mask) && (rosecmpm(&rose_route->address, &rose_node->address, rose_route->mask) == 0))
83
                        break;
84
 
85
        for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next)
86
                if (ax25cmp(&rose_route->neighbour, &rose_neigh->callsign) == 0 && rose_neigh->dev == dev)
87
                        break;
88
 
89
        if (rose_neigh == NULL) {
90
                if ((rose_neigh = (struct rose_neigh *)kmalloc(sizeof(*rose_neigh), GFP_ATOMIC)) == NULL)
91
                        return -ENOMEM;
92
 
93
                rose_neigh->callsign  = rose_route->neighbour;
94
                rose_neigh->digipeat  = NULL;
95
                rose_neigh->ax25      = NULL;
96
                rose_neigh->dev       = dev;
97
                rose_neigh->count     = 0;
98
                rose_neigh->use       = 0;
99
                rose_neigh->dce_mode  = 0;
100
                rose_neigh->number    = rose_neigh_no++;
101
                rose_neigh->restarted = 0;
102
                skb_queue_head_init(&rose_neigh->queue);
103
                rose_neigh->t0timer   = 0;
104
                rose_neigh->ftimer    = 0;
105
                init_timer(&rose_neigh->timer);
106
 
107
                if (rose_route->ndigis != 0) {
108
                        if ((rose_neigh->digipeat = kmalloc(sizeof(ax25_digi), GFP_KERNEL)) == NULL) {
109
                                kfree_s(rose_neigh, sizeof(*rose_neigh));
110
                                return -ENOMEM;
111
                        }
112
 
113
                        rose_neigh->digipeat->ndigi      = rose_route->ndigis;
114
                        rose_neigh->digipeat->lastrepeat = -1;
115
 
116
                        for (i = 0; i < rose_route->ndigis; i++) {
117
                                rose_neigh->digipeat->calls[i]    = rose_route->digipeaters[i];
118
                                rose_neigh->digipeat->repeated[i] = 0;
119
                        }
120
                }
121
 
122
                save_flags(flags); cli();
123
                rose_neigh->next = rose_neigh_list;
124
                rose_neigh_list  = rose_neigh;
125
                restore_flags(flags);
126
        }
127
 
128
        /*
129
         * This is a new node to be inserted into the list. Find where it needs
130
         * to be inserted into the list, and insert it. We want to be sure
131
         * to order the list in descending order of mask size to ensure that
132
         * later when we are searching this list the first match will be the
133
         * best match.
134
         */
135
        if (rose_node == NULL) {
136
                rose_tmpn = rose_node_list;
137
                rose_tmpp = NULL;
138
 
139
                while (rose_tmpn != NULL) {
140
                        if (rose_tmpn->mask > rose_route->mask) {
141
                                rose_tmpp = rose_tmpn;
142
                                rose_tmpn = rose_tmpn->next;
143
                        } else {
144
                                break;
145
                        }
146
                }
147
 
148
                /* create new node */
149
                if ((rose_node = (struct rose_node *)kmalloc(sizeof(*rose_node), GFP_ATOMIC)) == NULL)
150
                        return -ENOMEM;
151
 
152
                rose_node->address = rose_route->address;
153
                rose_node->mask    = rose_route->mask;
154
                rose_node->count   = 1;
155
                rose_node->neighbour[0] = rose_neigh;
156
 
157
                save_flags(flags); cli();
158
 
159
                if (rose_tmpn == NULL) {
160
                        if (rose_tmpp == NULL) {        /* Empty list */
161
                                rose_node_list  = rose_node;
162
                                rose_node->next = NULL;
163
                        } else {
164
                                rose_tmpp->next = rose_node;
165
                                rose_node->next = NULL;
166
                        }
167
                } else {
168
                        if (rose_tmpp == NULL) {        /* 1st node */
169
                                rose_node->next = rose_node_list;
170
                                rose_node_list  = rose_node;
171
                        } else {
172
                                rose_tmpp->next = rose_node;
173
                                rose_node->next = rose_tmpn;
174
                        }
175
                }
176
 
177
                restore_flags(flags);
178
 
179
                rose_neigh->count++;
180
 
181
        } else if (rose_node->count < ROSE_MAX_ALTERNATE) {
182
                /* We have space, slot it in */
183
                rose_node->neighbour[rose_node->count] = rose_neigh;
184
                rose_node->count++;
185
                rose_neigh->count++;
186
        }
187
 
188
        if (!rose_is_null(&rose_route->address))
189
        {
190
                /* Delete this neighbourg from the dummy node 0000000000 */
191
                dummy_route = *rose_route;
192
                dummy_route.mask = 10;
193
                memset(&dummy_route.address, 0, sizeof(rose_address));
194
                rose_del_node(&dummy_route, dev);
195
        }
196
 
197
        return 0;
198
}
199
 
200
static void rose_remove_node(struct rose_node *rose_node)
201
{
202
        struct rose_node *s;
203
        unsigned long flags;
204
 
205
        save_flags(flags);
206
        cli();
207
 
208
        if ((s = rose_node_list) == rose_node) {
209
                rose_node_list = rose_node->next;
210
                restore_flags(flags);
211
                kfree_s(rose_node, sizeof(struct rose_node));
212
                return;
213
        }
214
 
215
        while (s != NULL && s->next != NULL) {
216
                if (s->next == rose_node) {
217
                        s->next = rose_node->next;
218
                        restore_flags(flags);
219
                        kfree_s(rose_node, sizeof(struct rose_node));
220
                        return;
221
                }
222
 
223
                s = s->next;
224
        }
225
 
226
        restore_flags(flags);
227
}
228
 
229
static void rose_remove_neigh(struct rose_neigh *rose_neigh)
230
{
231
        struct rose_neigh *s;
232
        unsigned long flags;
233
        struct sk_buff *skb;
234
 
235
        del_timer(&rose_neigh->timer);
236
 
237
        while ((skb = skb_dequeue(&rose_neigh->queue)) != NULL)
238
                kfree_skb(skb, FREE_WRITE);
239
 
240
        save_flags(flags);
241
        cli();
242
 
243
        if ((s = rose_neigh_list) == rose_neigh) {
244
                rose_neigh_list = rose_neigh->next;
245
                restore_flags(flags);
246
                if (rose_neigh->digipeat != NULL)
247
                        kfree_s(rose_neigh->digipeat, sizeof(ax25_digi));
248
                kfree_s(rose_neigh, sizeof(struct rose_neigh));
249
                return;
250
        }
251
 
252
        while (s != NULL && s->next != NULL) {
253
                if (s->next == rose_neigh) {
254
                        s->next = rose_neigh->next;
255
                        restore_flags(flags);
256
                        if (rose_neigh->digipeat != NULL)
257
                                kfree_s(rose_neigh->digipeat, sizeof(ax25_digi));
258
                        kfree_s(rose_neigh, sizeof(struct rose_neigh));
259
                        return;
260
                }
261
 
262
                s = s->next;
263
        }
264
 
265
        restore_flags(flags);
266
}
267
 
268
static void rose_remove_route(struct rose_route *rose_route)
269
{
270
        struct rose_route *s;
271
        unsigned long flags;
272
 
273
        if (rose_route->tr1.neigh != NULL)
274
                rose_route->tr1.neigh->use--;
275
 
276
        if (rose_route->tr2.neigh != NULL)
277
                rose_route->tr2.neigh->use--;
278
 
279
        save_flags(flags);
280
        cli();
281
 
282
        if ((s = rose_route_list) == rose_route) {
283
                rose_route_list = rose_route->next;
284
                restore_flags(flags);
285
                kfree_s(rose_route, sizeof(struct rose_route));
286
                return;
287
        }
288
 
289
        while (s != NULL && s->next != NULL) {
290
                if (s->next == rose_route) {
291
                        s->next = rose_route->next;
292
                        restore_flags(flags);
293
                        kfree_s(rose_route, sizeof(struct rose_route));
294
                        return;
295
                }
296
 
297
                s = s->next;
298
        }
299
 
300
        restore_flags(flags);
301
}
302
 
303
/*
304
 *      "Delete" a node. Strictly speaking remove a route to a node. The node
305
 *      is only deleted if no routes are left to it.
306
 */
307
static int rose_del_node(struct rose_route_struct *rose_route, struct device *dev)
308
{
309
        struct rose_node  *rose_node;
310
        struct rose_neigh *rose_neigh;
311
        struct rose_route_struct dummy_route;
312
        int i;
313
 
314
        for (rose_node = rose_node_list; rose_node != NULL; rose_node = rose_node->next)
315
                if ((rose_node->mask == rose_route->mask) && (rosecmpm(&rose_route->address, &rose_node->address, rose_route->mask) == 0))
316
                        break;
317
 
318
        if (rose_node == NULL) return -EINVAL;
319
 
320
        for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next)
321
                if (ax25cmp(&rose_route->neighbour, &rose_neigh->callsign) == 0 && rose_neigh->dev == dev)
322
                        break;
323
 
324
        if (rose_neigh == NULL) return -EINVAL;
325
 
326
        for (i = 0; i < rose_node->count; i++) {
327
                if (rose_node->neighbour[i] == rose_neigh) {
328
                        rose_neigh->count--;
329
 
330
                        if (rose_neigh->count == 0) {
331
                                /* Add a dummy node to keep the neighbourg still visible */
332
                                dummy_route = *rose_route;
333
                                dummy_route.mask = 10;
334
                                memset(&dummy_route.address, 0, sizeof(rose_address));
335
                                rose_add_node(&dummy_route, dev);
336
                        }
337
                        /* if (rose_neigh->count == 0 && rose_neigh->use == 0) {
338
                                rose_remove_neigh(rose_neigh);
339
                        } */
340
 
341
                        rose_node->count--;
342
 
343
                        if (rose_node->count == 0) {
344
                                rose_remove_node(rose_node);
345
                        } else {
346
                                switch (i) {
347
                                        case 0:
348
                                                rose_node->neighbour[0] = rose_node->neighbour[1];
349
                                        case 1:
350
                                                rose_node->neighbour[1] = rose_node->neighbour[2];
351
                                        case 2:
352
                                                break;
353
                                }
354
                        }
355
 
356
                        return 0;
357
                }
358
        }
359
 
360
        return -EINVAL;
361
}
362
 
363
/*
364
 *      A device has been removed. Remove its routes and neighbours.
365
 */
366
void rose_rt_device_down(struct device *dev)
367
{
368
        struct rose_neigh *s, *rose_neigh = rose_neigh_list;
369
        struct rose_node  *t, *rose_node;
370
        int i;
371
 
372
        while (rose_neigh != NULL) {
373
                s          = rose_neigh;
374
                rose_neigh = rose_neigh->next;
375
 
376
                if (s->dev == dev) {
377
                        rose_node = rose_node_list;
378
 
379
                        while (rose_node != NULL) {
380
                                t         = rose_node;
381
                                rose_node = rose_node->next;
382
 
383
                                for (i = 0; i < t->count; i++) {
384
                                        if (t->neighbour[i] == s) {
385
                                                t->count--;
386
 
387
                                                switch (i) {
388
                                                        case 0:
389
                                                                t->neighbour[0] = t->neighbour[1];
390
                                                        case 1:
391
                                                                t->neighbour[1] = t->neighbour[2];
392
                                                        case 2:
393
                                                                break;
394
                                                }
395
                                        }
396
                                }
397
 
398
                                if (t->count <= 0)
399
                                        rose_remove_node(t);
400
                        }
401
 
402
                        rose_remove_neigh(s);
403
                }
404
        }
405
}
406
 
407
/*
408
 *      A device has been removed. Remove its links.
409
 */
410
void rose_route_device_down(struct device *dev)
411
{
412
        struct rose_route *s, *rose_route = rose_route_list;
413
 
414
        while (rose_route != NULL) {
415
                s          = rose_route;
416
                rose_route = rose_route->next;
417
 
418
                if (s->tr1.neigh->dev == dev || s->tr2.neigh->dev == dev)
419
                        rose_remove_route(s);
420
        }
421
}
422
 
423
/*
424
 *      Clear all nodes and neighbours out, except for neighbours with
425
 *      active connections going through them.
426
 */
427
static int rose_clear_routes(void)
428
{
429
        struct rose_neigh *s, *rose_neigh = rose_neigh_list;
430
        struct rose_node  *t, *rose_node  = rose_node_list;
431
 
432
        while (rose_node != NULL) {
433
                t         = rose_node;
434
                rose_node = rose_node->next;
435
 
436
                rose_remove_node(t);
437
        }
438
 
439
        while (rose_neigh != NULL) {
440
                s          = rose_neigh;
441
                rose_neigh = rose_neigh->next;
442
 
443
                s->count = 0;
444
 
445
                if (s->use == 0)
446
                        rose_remove_neigh(s);
447
        }
448
 
449
        return 0;
450
}
451
 
452
/*
453
 *      Check that the device given is a valid AX.25 interface that is "up".
454
 */
455
struct device *rose_ax25_dev_get(char *devname)
456
{
457
        struct device *dev;
458
 
459
        if ((dev = dev_get(devname)) == NULL)
460
                return NULL;
461
 
462
        if ((dev->flags & IFF_UP) && dev->type == ARPHRD_AX25)
463
                return dev;
464
 
465
        return NULL;
466
}
467
 
468
/*
469
 *      Find the first active ROSE device, usually "rose0".
470
 */
471
struct device *rose_dev_first(void)
472
{
473
        struct device *dev, *first = NULL;
474
 
475
        for (dev = dev_base; dev != NULL; dev = dev->next)
476
                if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ROSE)
477
                        if (first == NULL || strncmp(dev->name, first->name, 3) < 0)
478
                                first = dev;
479
 
480
        return first;
481
}
482
 
483
/*
484
 *      Find the ROSE device for the given address.
485
 */
486
struct device *rose_dev_get(rose_address *addr)
487
{
488
        struct device *dev;
489
 
490
        for (dev = dev_base; dev != NULL; dev = dev->next)
491
                if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ROSE && rosecmp(addr, (rose_address *)dev->dev_addr) == 0)
492
                        return dev;
493
 
494
        return NULL;
495
}
496
 
497
struct rose_route *rose_route_free_lci(unsigned int lci, struct rose_neigh *neigh)
498
{
499
        struct rose_route *rose_route;
500
 
501
        for (rose_route = rose_route_list; rose_route != NULL; rose_route = rose_route->next)
502
                if ((rose_route->tr1.neigh == neigh && rose_route->tr1.lci == lci) ||
503
                    (rose_route->tr2.neigh == neigh && rose_route->tr2.lci == lci))
504
                        return rose_route;
505
 
506
        return NULL;
507
}
508
 
509
/*
510
 *      Find a neighbour given a ROSE address.
511
 */
512
struct rose_neigh *rose_get_neigh(rose_address *addr, unsigned char *cause, unsigned char *diagnostic)
513
{
514
        struct rose_node *node;
515
        int failed = 0;
516
        int i;
517
 
518
        for (node = rose_node_list; node != NULL; node = node->next) {
519
                if (rosecmpm(addr, &node->address, node->mask) == 0) {
520
                        for (i = 0; i < node->count; i++) {
521
                                if (node->neighbour[i]->ftimer == 0)
522
                                        return node->neighbour[i];
523
                                else
524
                                        failed = 1;
525
                        }
526
                        /* do not accept other node address */
527
                        break;
528
                }
529
        }
530
 
531
        if (failed) {
532
                *cause      = ROSE_OUT_OF_ORDER;
533
                *diagnostic = 0;
534
        } else {
535
                *cause      = ROSE_NOT_OBTAINABLE;
536
                *diagnostic = 0;
537
        }
538
 
539
        return NULL;
540
}
541
 
542
/*
543
 *      Handle the ioctls that control the routing functions.
544
 */
545
int rose_rt_ioctl(unsigned int cmd, void *arg)
546
{
547
        struct rose_route_struct rose_route;
548
        struct device *dev;
549
        int err;
550
 
551
        switch (cmd) {
552
 
553
                case SIOCADDRT:
554
                        if ((err = verify_area(VERIFY_READ, arg, sizeof(struct rose_route_struct))) != 0)
555
                                return err;
556
                        memcpy_fromfs(&rose_route, arg, sizeof(struct rose_route_struct));
557
                        if ((dev = rose_ax25_dev_get(rose_route.device)) == NULL)
558
                                return -EINVAL;
559
                        /* if (rose_dev_get(&rose_route.address) != NULL)       / Can't add routes to ourself /
560
                                return -EINVAL; */
561
                        if (rose_route.mask > 10) /* Mask can't be more than 10 digits */
562
                                return -EINVAL;
563
 
564
                        return rose_add_node(&rose_route, dev);
565
 
566
                case SIOCDELRT:
567
                        if ((err = verify_area(VERIFY_READ, arg, sizeof(struct rose_route_struct))) != 0)
568
                                return err;
569
                        memcpy_fromfs(&rose_route, arg, sizeof(struct rose_route_struct));
570
                        if ((dev = rose_ax25_dev_get(rose_route.device)) == NULL)
571
                                return -EINVAL;
572
                        return rose_del_node(&rose_route, dev);
573
 
574
                case SIOCRSCLRRT:
575
                        return rose_clear_routes();
576
 
577
                default:
578
                        return -EINVAL;
579
        }
580
 
581
        return 0;
582
}
583
 
584
static void rose_del_route_by_neigh(struct rose_neigh *rose_neigh)
585
{
586
        struct rose_route *rose_route, *s;
587
        struct sk_buff    *skb;
588
 
589
        rose_neigh->restarted = 0;
590
        rose_neigh->t0timer   = 0;
591
        rose_neigh->ftimer    = sysctl_rose_link_fail_timeout;
592
 
593
        rose_link_set_timer(rose_neigh);
594
 
595
        while ((skb = skb_dequeue(&rose_neigh->queue)) != NULL)
596
                kfree_skb(skb, FREE_WRITE);
597
 
598
        rose_route = rose_route_list;
599
 
600
        while (rose_route != NULL) {
601
                if ((rose_route->tr1.neigh == rose_neigh && rose_route->tr2.neigh == rose_neigh) ||
602
                    (rose_route->tr1.neigh == rose_neigh && rose_route->tr2.neigh == NULL)       ||
603
                    (rose_route->tr2.neigh == rose_neigh && rose_route->tr1.neigh == NULL)) {
604
                        s = rose_route->next;
605
                        rose_remove_route(rose_route);
606
                        rose_route = s;
607
                        continue;
608
                }
609
 
610
                if (rose_route->tr1.neigh == rose_neigh) {
611
                        rose_route->tr1.neigh->use--;
612
                        rose_route->tr1.neigh = NULL;
613
                        rose_transmit_clear_request(rose_route->tr2.neigh, rose_route->tr2.lci, ROSE_OUT_OF_ORDER, 0);
614
                }
615
 
616
                if (rose_route->tr2.neigh == rose_neigh) {
617
                        rose_route->tr2.neigh->use--;
618
                        rose_route->tr2.neigh = NULL;
619
                        rose_transmit_clear_request(rose_route->tr1.neigh, rose_route->tr1.lci, ROSE_OUT_OF_ORDER, 0);
620
                }
621
 
622
                rose_route = rose_route->next;
623
        }
624
}
625
 
626
/*
627
 *      A level 2 link has timed out, therefore it appears to be a poor link,
628
 *      then don't use that neighbour until it is reset. Blow away all through
629
 *      routes and connections using this route.
630
 */
631
void rose_link_failed(ax25_cb *ax25, int reason)
632
{
633
        struct rose_neigh *rose_neigh;
634
 
635
        for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next)
636
                if (rose_neigh->ax25 == ax25)
637
                        break;
638
 
639
        if (rose_neigh == NULL) return;
640
 
641
        rose_neigh->ax25 = NULL;
642
 
643
        rose_del_route_by_neigh(rose_neigh);
644
        rose_kill_by_neigh(rose_neigh);
645
}
646
 
647
/*
648
 *      A device has been "downed" remove its link status. Blow away all
649
 *      through routes and connections that use this device.
650
 */
651
void rose_link_device_down(struct device *dev)
652
{
653
        struct rose_neigh *rose_neigh;
654
 
655
        for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next) {
656
                if (rose_neigh->dev == dev) {
657
                        rose_del_route_by_neigh(rose_neigh);
658
                        rose_kill_by_neigh(rose_neigh);
659
                }
660
        }
661
}
662
 
663
/*
664
 *      A Restart has occured. Delete all existing routes to this neighbour
665
 */
666
void rose_clean_neighbour(struct rose_neigh *rose_neigh)
667
{
668
        rose_del_route_by_neigh(rose_neigh);
669
        rose_kill_by_neigh(rose_neigh);
670
}
671
 
672
 
673
/*
674
 *      Route a frame to an appropriate AX.25 connection.
675
 */
676
int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
677
{
678
        struct rose_neigh *rose_neigh, *new_neigh;
679
        struct rose_route *rose_route;
680
        struct rose_facilities_struct facilities;
681
        rose_address *src_addr, *dest_addr;
682
        struct sock *sk;
683
        unsigned short frametype;
684
        unsigned int lci, new_lci;
685
        unsigned char cause, diagnostic;
686
        struct device *dev;
687
        unsigned long flags;
688
        int len;
689
        struct sk_buff *skbn;
690
 
691
#ifdef CONFIG_FIREWALL
692
        if (call_in_firewall(PF_ROSE, skb->dev, skb->data, NULL) != FW_ACCEPT)
693
                return 0;
694
#endif
695
 
696
        frametype = skb->data[2];
697
        lci = ((skb->data[0] << 8) & 0xF00) + ((skb->data[1] << 0) & 0x0FF);
698
        src_addr  = (rose_address *)(skb->data + 9);
699
        dest_addr = (rose_address *)(skb->data + 4);
700
 
701
        for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next)
702
                if (ax25cmp(&ax25->dest_addr, &rose_neigh->callsign) == 0 && ax25->device == rose_neigh->dev)
703
                        break;
704
 
705
        if (rose_neigh == NULL) {
706
                printk("rose_route : unknown neighbour or device %s\n", ax2asc(&ax25->dest_addr));
707
                return 0;
708
        }
709
 
710
        /*
711
         *      Obviously the link is working, halt the ftimer.
712
         */
713
        rose_neigh->ftimer = 0;
714
 
715
        /*
716
         *      LCI of zero is always for us, and its always a restart
717
         *      frame.
718
         */
719
        if (lci == 0) {
720
                rose_link_rx_restart(skb, rose_neigh, frametype);
721
                return 0;
722
        }
723
 
724
        /*
725
         *      Find an existing socket.
726
         */
727
        if ((sk = rose_find_socket(lci, rose_neigh)) != NULL) {
728
                if (frametype == ROSE_CALL_REQUEST)
729
                {
730
                        /* F6FBB - Remove an existing unused socket */
731
                        rose_clear_queues(sk);
732
                        sk->protinfo.rose->cause      = ROSE_NETWORK_CONGESTION;
733
                        sk->protinfo.rose->diagnostic = 0;
734
                        sk->protinfo.rose->neighbour->use--;
735
                        sk->protinfo.rose->neighbour = NULL;
736
                        sk->protinfo.rose->state = ROSE_STATE_0;
737
                        sk->state                = TCP_CLOSE;
738
                        sk->err                  = 0;
739
                        sk->shutdown            |= SEND_SHUTDOWN;
740
                        if (!sk->dead)
741
                                sk->state_change(sk);
742
                        sk->dead                 = 1;
743
                }
744
                else
745
                {
746
                        skb->h.raw = skb->data;
747
                        return rose_process_rx_frame(sk, skb);
748
                }
749
        }
750
 
751
        /*
752
         *      Is it a Call Request and is it for us ?
753
         */
754
        if (frametype == ROSE_CALL_REQUEST)
755
                if ((dev = rose_dev_get(dest_addr)) != NULL) {
756
                        return rose_rx_call_request(skb, dev, rose_neigh, lci);
757
                }
758
 
759
        if (!sysctl_rose_routing_control) {
760
                rose_transmit_clear_request(rose_neigh, lci, ROSE_NOT_OBTAINABLE, 0);
761
                return 0;
762
        }
763
 
764
        /*
765
         *      Route it to the next in line if we have an entry for it.
766
         */
767
        for (rose_route = rose_route_list; rose_route != NULL; rose_route = rose_route->next) {
768
                if (rose_route->tr1.lci == lci && rose_route->tr1.neigh == rose_neigh) {
769
                        if (frametype == ROSE_CALL_REQUEST) {
770
                                /* F6FBB - Remove an existing unused route */
771
                                rose_remove_route(rose_route);
772
                                break;
773
                        } else if (rose_route->tr2.neigh != NULL) {
774
                                if ((skbn = skb_copy(skb, GFP_ATOMIC)) != NULL) {
775
                                        kfree_skb(skb, FREE_READ);
776
                                        skb = skbn;
777
                                }
778
                                skb->data[0] &= 0xF0;
779
                                skb->data[0] |= (rose_route->tr2.lci >> 8) & 0x0F;
780
                                skb->data[1]  = (rose_route->tr2.lci >> 0) & 0xFF;
781
                                rose_transmit_link(skb, rose_route->tr2.neigh);
782
                                if (frametype == ROSE_CLEAR_CONFIRMATION)
783
                                        rose_remove_route(rose_route);
784
                                return 1;
785
                        } else {
786
                                if (frametype == ROSE_CLEAR_CONFIRMATION)
787
                                        rose_remove_route(rose_route);
788
                                return 0;
789
                        }
790
                }
791
                if (rose_route->tr2.lci == lci && rose_route->tr2.neigh == rose_neigh) {
792
                        if (frametype == ROSE_CALL_REQUEST) {
793
                                /* F6FBB - Remove an existing unused route */
794
                                rose_remove_route(rose_route);
795
                                break;
796
                        } else if (rose_route->tr1.neigh != NULL) {
797
                                if ((skbn = skb_copy(skb, GFP_ATOMIC)) != NULL) {
798
                                        kfree_skb(skb, FREE_READ);
799
                                        skb = skbn;
800
                                }
801
                                skb->data[0] &= 0xF0;
802
                                skb->data[0] |= (rose_route->tr1.lci >> 8) & 0x0F;
803
                                skb->data[1]  = (rose_route->tr1.lci >> 0) & 0xFF;
804
                                rose_transmit_link(skb, rose_route->tr1.neigh);
805
                                if (frametype == ROSE_CLEAR_CONFIRMATION)
806
                                        rose_remove_route(rose_route);
807
                                return 1;
808
                        } else {
809
                                if (frametype == ROSE_CLEAR_CONFIRMATION)
810
                                        rose_remove_route(rose_route);
811
                                return 0;
812
                        }
813
                }
814
        }
815
 
816
        /*
817
         *      We know that:
818
         *      1. The frame isn't for us,
819
         *      2. It isn't "owned" by any existing route.
820
         */
821
        if (frametype != ROSE_CALL_REQUEST)     { /* Trashed packet */
822
                return 0;
823
        }
824
 
825
        len  = (((skb->data[3] >> 4) & 0x0F) + 1) / 2;
826
        len += (((skb->data[3] >> 0) & 0x0F) + 1) / 2;
827
 
828
        memset(&facilities, 0x00, sizeof(struct rose_facilities_struct));
829
 
830
        if (!rose_parse_facilities(skb->data + len + 4, &facilities)) {
831
                printk("CR : rose_parse_facilities error\n");
832
                rose_transmit_clear_request(rose_neigh, lci, ROSE_INVALID_FACILITY, 76);
833
                return 0;
834
        }
835
 
836
        /*
837
         *      Check for routing loops.
838
         */
839
        for (rose_route = rose_route_list; rose_route != NULL; rose_route = rose_route->next) {
840
                if (rose_route->rand == facilities.rand &&
841
                    rosecmp(src_addr, &rose_route->src_addr) == 0 &&
842
                    ax25cmp(&facilities.dest_call, &rose_route->src_call) == 0 &&
843
                    ax25cmp(&facilities.source_call, &rose_route->dest_call) == 0) {
844
                        rose_transmit_clear_request(rose_neigh, lci, ROSE_NOT_OBTAINABLE, 120);
845
                        return 0;
846
                }
847
        }
848
 
849
        if ((new_neigh = rose_get_neigh(dest_addr, &cause, &diagnostic)) == NULL) {
850
                rose_transmit_clear_request(rose_neigh, lci, cause, diagnostic);
851
                return 0;
852
        }
853
 
854
        if ((new_lci = rose_new_lci(new_neigh)) == 0) {
855
                rose_transmit_clear_request(rose_neigh, lci, ROSE_NETWORK_CONGESTION, 71);
856
                return 0;
857
        }
858
 
859
        if ((rose_route = (struct rose_route *)kmalloc(sizeof(*rose_route), GFP_ATOMIC)) == NULL) {
860
                rose_transmit_clear_request(rose_neigh, lci, ROSE_NETWORK_CONGESTION, 121);
861
                return 0;
862
        }
863
 
864
        rose_route->src_addr  = *src_addr;
865
        rose_route->dest_addr = *dest_addr;
866
        rose_route->src_call  = facilities.dest_call;
867
        rose_route->dest_call = facilities.source_call;
868
        rose_route->rand      = facilities.rand;
869
        rose_route->tr1.lci   = lci;
870
        rose_route->tr1.neigh = rose_neigh;
871
        rose_route->tr2.lci   = new_lci;
872
        rose_route->tr2.neigh = new_neigh;
873
 
874
        rose_route->tr1.neigh->use++;
875
        rose_route->tr2.neigh->use++;
876
 
877
        save_flags(flags); cli();
878
        rose_route->next = rose_route_list;
879
        rose_route_list  = rose_route;
880
        restore_flags(flags);
881
 
882
        if ((skbn = skb_copy(skb, GFP_ATOMIC)) != NULL) {
883
                kfree_skb(skb, FREE_READ);
884
                skb = skbn;
885
        }
886
 
887
        skb->data[0] &= 0xF0;
888
        skb->data[0] |= (rose_route->tr2.lci >> 8) & 0x0F;
889
        skb->data[1]  = (rose_route->tr2.lci >> 0) & 0xFF;
890
 
891
        rose_transmit_link(skb, rose_route->tr2.neigh);
892
 
893
        return 1;
894
}
895
 
896
int rose_nodes_get_info(char *buffer, char **start, off_t offset,
897
                      int length, int dummy)
898
{
899
        struct rose_node *rose_node;
900
        int len     = 0;
901
        off_t pos   = 0;
902
        off_t begin = 0;
903
        int i;
904
 
905
        cli();
906
 
907
        len += sprintf(buffer, "address    mask n neigh neigh neigh\n");
908
 
909
        for (rose_node = rose_node_list; rose_node != NULL; rose_node = rose_node->next) {
910
                len += sprintf(buffer + len, "%-10s %04d %d",
911
                        rose2asc(&rose_node->address),
912
                        rose_node->mask,
913
                        rose_node->count);
914
 
915
                for (i = 0; i < rose_node->count; i++)
916
                        len += sprintf(buffer + len, " %05d",
917
                                rose_node->neighbour[i]->number);
918
 
919
                len += sprintf(buffer + len, "\n");
920
 
921
                pos = begin + len;
922
 
923
                if (pos < offset) {
924
                        len   = 0;
925
                        begin = pos;
926
                }
927
 
928
                if (pos > offset + length)
929
                        break;
930
        }
931
 
932
        sti();
933
 
934
        *start = buffer + (offset - begin);
935
        len   -= (offset - begin);
936
 
937
        if (len > length) len = length;
938
 
939
        return len;
940
}
941
 
942
int rose_neigh_get_info(char *buffer, char **start, off_t offset,
943
                      int length, int dummy)
944
{
945
        struct rose_neigh *rose_neigh;
946
        int len     = 0;
947
        off_t pos   = 0;
948
        off_t begin = 0;
949
        int i;
950
 
951
        cli();
952
 
953
        len += sprintf(buffer, "addr  callsign  dev  count use mode restart  t0  tf digipeaters\n");
954
 
955
        for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next) {
956
                len += sprintf(buffer + len, "%05d %-9s %-4s   %3d %3d  %3s     %3s %3d %3d",
957
                        rose_neigh->number,
958
                        ax2asc(&rose_neigh->callsign),
959
                        rose_neigh->dev ? rose_neigh->dev->name : "???",
960
                        rose_neigh->count,
961
                        rose_neigh->use,
962
                        (rose_neigh->dce_mode) ? "DCE" : "DTE",
963
                        (rose_neigh->restarted) ? "yes" : "no",
964
                        rose_neigh->t0timer / ROSE_SLOWHZ,
965
                        rose_neigh->ftimer  / ROSE_SLOWHZ);
966
 
967
                if (rose_neigh->digipeat != NULL) {
968
                        for (i = 0; i < rose_neigh->digipeat->ndigi; i++)
969
                                len += sprintf(buffer + len, " %s", ax2asc(&rose_neigh->digipeat->calls[i]));
970
                }
971
 
972
                len += sprintf(buffer + len, "\n");
973
 
974
                pos = begin + len;
975
 
976
                if (pos < offset) {
977
                        len   = 0;
978
                        begin = pos;
979
                }
980
 
981
                if (pos > offset + length)
982
                        break;
983
        }
984
 
985
        sti();
986
 
987
        *start = buffer + (offset - begin);
988
        len   -= (offset - begin);
989
 
990
        if (len > length) len = length;
991
 
992
        return len;
993
}
994
 
995
int rose_routes_get_info(char *buffer, char **start, off_t offset,
996
                      int length, int dummy)
997
{
998
        struct rose_route *rose_route;
999
        int len     = 0;
1000
        off_t pos   = 0;
1001
        off_t begin = 0;
1002
 
1003
        cli();
1004
 
1005
        len += sprintf(buffer, "lci  address     callsign   neigh  <-> lci  address     callsign   neigh\n");
1006
 
1007
        for (rose_route = rose_route_list; rose_route != NULL; rose_route = rose_route->next) {
1008
                if (rose_route->tr1.neigh != NULL) {
1009
                        len += sprintf(buffer + len, "%3.3X  %-10s  %-9s  %05d      ",
1010
                                rose_route->tr1.lci,
1011
                                rose2asc(&rose_route->src_addr),
1012
                                ax2asc(&rose_route->src_call),
1013
                                rose_route->tr1.neigh->number);
1014
                } else {
1015
                        len += sprintf(buffer + len, "000  *           *          00000      ");
1016
                }
1017
 
1018
                if (rose_route->tr2.neigh != NULL) {
1019
                        len += sprintf(buffer + len, "%3.3X  %-10s  %-9s  %05d\n",
1020
                                rose_route->tr2.lci,
1021
                                rose2asc(&rose_route->dest_addr),
1022
                                ax2asc(&rose_route->dest_call),
1023
                                rose_route->tr2.neigh->number);
1024
                } else {
1025
                        len += sprintf(buffer + len, "000  *           *          00000\n");
1026
                }
1027
 
1028
                pos = begin + len;
1029
 
1030
                if (pos < offset) {
1031
                        len   = 0;
1032
                        begin = pos;
1033
                }
1034
 
1035
                if (pos > offset + length)
1036
                        break;
1037
        }
1038
 
1039
        sti();
1040
 
1041
        *start = buffer + (offset - begin);
1042
        len   -= (offset - begin);
1043
 
1044
        if (len > length) len = length;
1045
 
1046
        return len;
1047
}
1048
 
1049
#ifdef MODULE
1050
 
1051
/*
1052
 *      Release all memory associated with ROSE routing structures.
1053
 */
1054
void rose_rt_free(void)
1055
{
1056
        struct rose_neigh *s, *rose_neigh = rose_neigh_list;
1057
        struct rose_node  *t, *rose_node  = rose_node_list;
1058
        struct rose_route *u, *rose_route = rose_route_list;
1059
 
1060
        while (rose_neigh != NULL) {
1061
                s          = rose_neigh;
1062
                rose_neigh = rose_neigh->next;
1063
 
1064
                rose_remove_neigh(s);
1065
        }
1066
 
1067
        while (rose_node != NULL) {
1068
                t         = rose_node;
1069
                rose_node = rose_node->next;
1070
 
1071
                rose_remove_node(t);
1072
        }
1073
 
1074
        while (rose_route != NULL) {
1075
                u          = rose_route;
1076
                rose_route = rose_route->next;
1077
 
1078
                rose_remove_route(u);
1079
        }
1080
}
1081
 
1082
#endif
1083
 
1084
#endif

powered by: WebSVN 2.1.0

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