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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [net/] [netrom/] [nr_route.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
 *      NET/ROM release 006
3
 *
4
 *      This code REQUIRES 1.2.1 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
 *      NET/ROM 001     Jonathan(G4KLX) First attempt.
14
 *      NET/ROM 003     Jonathan(G4KLX) Use SIOCADDRT/SIOCDELRT ioctl values
15
 *                                      for NET/ROM routes.
16
 *                                      Use '*' for a blank mnemonic in /proc/net/nr_nodes.
17
 *                                      Change default quality for new neighbour when same
18
 *                                      as node callsign.
19
 *                      Alan Cox(GW4PTS) Added the firewall hooks.
20
 *                      Tomi(OH2BNS)    Routing quality and link failure changes.
21
 */
22
 
23
#include <linux/config.h>
24
#if defined(CONFIG_NETROM) || defined(CONFIG_NETROM_MODULE)
25
#include <linux/errno.h>
26
#include <linux/types.h>
27
#include <linux/socket.h>
28
#include <linux/in.h>
29
#include <linux/kernel.h>
30
#include <linux/sched.h>
31
#include <linux/timer.h>
32
#include <linux/string.h>
33
#include <linux/sockios.h>
34
#include <linux/net.h>
35
#include <net/ax25.h>
36
#include <linux/inet.h>
37
#include <linux/netdevice.h>
38
#include <net/arp.h>
39
#include <linux/if_arp.h>
40
#include <linux/skbuff.h>
41
#include <net/sock.h>
42
#include <asm/segment.h>
43
#include <asm/system.h>
44
#include <linux/fcntl.h>
45
#include <linux/termios.h>      /* For TIOCINQ/OUTQ */
46
#include <linux/mm.h>
47
#include <linux/interrupt.h>
48
#include <linux/notifier.h>
49
#include <linux/firewall.h>
50
#include <net/netrom.h>
51
 
52
static unsigned int nr_neigh_no = 1;
53
 
54
static struct nr_node  *nr_node_list  = NULL;
55
static struct nr_neigh *nr_neigh_list = NULL;
56
 
57
static void nr_remove_neigh(struct nr_neigh *);
58
 
59
/*
60
 *      Add a new route to a node, and in the process add the node and the
61
 *      neighbour if it is new.
62
 */
63
static int nr_add_node(ax25_address *nr, const char *mnemonic, ax25_address *ax25,
64
        ax25_digi *ax25_digi, struct device *dev, int quality, int obs_count)
65
{
66
        struct nr_node  *nr_node;
67
        struct nr_neigh *nr_neigh;
68
        struct nr_route nr_route;
69
        unsigned long flags;
70
        int i, found;
71
 
72
        if (nr_dev_get(nr) != NULL)     /* Can't add routes to ourself */
73
                return -EINVAL;
74
 
75
        for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next)
76
                if (ax25cmp(nr, &nr_node->callsign) == 0)
77
                        break;
78
 
79
        for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next)
80
                if (ax25cmp(ax25, &nr_neigh->callsign) == 0 && nr_neigh->dev == dev)
81
                        break;
82
 
83
        /*
84
         * If the L2 link to a neighbour has failed in the past
85
         * and now a frame comes from this neighbour then reset the routes.
86
         */
87
        if (nr_neigh != NULL && nr_neigh->failed != 0 && quality == 0) {
88
                struct nr_node *node;
89
 
90
                for (node = nr_node_list; node != NULL; node = node->next)
91
                        for (i = 0; i < node->count; i++)
92
                                if (node->routes[i].neighbour == nr_neigh)
93
                                        if (i < node->which)
94
                                                node->which = i;
95
        }
96
 
97
        if (nr_neigh != NULL)
98
                nr_neigh->failed = 0;
99
 
100
        if (quality == 0 && nr_neigh != NULL && nr_node != NULL)
101
                return 0;
102
 
103
        if (nr_neigh == NULL) {
104
                if ((nr_neigh = (struct nr_neigh *)kmalloc(sizeof(*nr_neigh), GFP_ATOMIC)) == NULL)
105
                        return -ENOMEM;
106
 
107
                nr_neigh->callsign = *ax25;
108
                nr_neigh->digipeat = NULL;
109
                nr_neigh->ax25     = NULL;
110
                nr_neigh->dev      = dev;
111
                nr_neigh->quality  = sysctl_netrom_default_path_quality;
112
                nr_neigh->locked   = 0;
113
                nr_neigh->count    = 0;
114
                nr_neigh->number   = nr_neigh_no++;
115
                nr_neigh->failed   = 0;
116
 
117
                if (ax25_digi != NULL && ax25_digi->ndigi > 0) {
118
                        if ((nr_neigh->digipeat = kmalloc(sizeof(*ax25_digi), GFP_KERNEL)) == NULL) {
119
                                kfree_s(nr_neigh, sizeof(*nr_neigh));
120
                                return -ENOMEM;
121
                        }
122
                        *nr_neigh->digipeat = *ax25_digi;
123
                }
124
 
125
                save_flags(flags);
126
                cli();
127
 
128
                nr_neigh->next = nr_neigh_list;
129
                nr_neigh_list  = nr_neigh;
130
 
131
                restore_flags(flags);
132
        }
133
 
134
        if (quality != 0 && ax25cmp(nr, ax25) == 0 && !nr_neigh->locked)
135
                nr_neigh->quality = quality;
136
 
137
        if (nr_node == NULL) {
138
                if ((nr_node = (struct nr_node *)kmalloc(sizeof(*nr_node), GFP_ATOMIC)) == NULL)
139
                        return -ENOMEM;
140
 
141
                nr_node->callsign = *nr;
142
                strcpy(nr_node->mnemonic, mnemonic);
143
 
144
                nr_node->which = 0;
145
                nr_node->count = 1;
146
 
147
                nr_node->routes[0].quality   = quality;
148
                nr_node->routes[0].obs_count = obs_count;
149
                nr_node->routes[0].neighbour = nr_neigh;
150
 
151
                save_flags(flags);
152
                cli();
153
 
154
                nr_node->next = nr_node_list;
155
                nr_node_list  = nr_node;
156
 
157
                restore_flags(flags);
158
 
159
                nr_neigh->count++;
160
 
161
                return 0;
162
        }
163
 
164
        if (quality != 0)
165
                strcpy(nr_node->mnemonic, mnemonic);
166
 
167
        for (found = 0, i = 0; i < nr_node->count; i++) {
168
                if (nr_node->routes[i].neighbour == nr_neigh) {
169
                        nr_node->routes[i].quality   = quality;
170
                        nr_node->routes[i].obs_count = obs_count;
171
                        found = 1;
172
                        break;
173
                }
174
        }
175
 
176
        if (!found) {
177
                /* We have space at the bottom, slot it in */
178
                if (nr_node->count < 3) {
179
                        nr_node->routes[2] = nr_node->routes[1];
180
                        nr_node->routes[1] = nr_node->routes[0];
181
 
182
                        nr_node->routes[0].quality   = quality;
183
                        nr_node->routes[0].obs_count = obs_count;
184
                        nr_node->routes[0].neighbour = nr_neigh;
185
 
186
                        nr_node->which++;
187
                        nr_node->count++;
188
                        nr_neigh->count++;
189
                } else {
190
                        /* It must be better than the worst */
191
                        if (quality > nr_node->routes[2].quality) {
192
                                nr_node->routes[2].neighbour->count--;
193
 
194
                                if (nr_node->routes[2].neighbour->count == 0 && !nr_node->routes[2].neighbour->locked)
195
                                        nr_remove_neigh(nr_node->routes[2].neighbour);
196
 
197
                                nr_node->routes[2].quality   = quality;
198
                                nr_node->routes[2].obs_count = obs_count;
199
                                nr_node->routes[2].neighbour = nr_neigh;
200
 
201
                                nr_neigh->count++;
202
                        }
203
                }
204
        }
205
 
206
        /* Now re-sort the routes in quality order */
207
        switch (nr_node->count) {
208
                case 3:
209
                        if (nr_node->routes[1].quality > nr_node->routes[0].quality) {
210
                                switch (nr_node->which) {
211
                                        case 0:  nr_node->which = 1; break;
212
                                        case 1:  nr_node->which = 0; break;
213
                                        default: break;
214
                                }
215
                                nr_route           = nr_node->routes[0];
216
                                nr_node->routes[0] = nr_node->routes[1];
217
                                nr_node->routes[1] = nr_route;
218
                        }
219
                        if (nr_node->routes[2].quality > nr_node->routes[1].quality) {
220
                                switch (nr_node->which) {
221
                                        case 1:  nr_node->which = 2; break;
222
                                        case 2:  nr_node->which = 1; break;
223
                                        default: break;
224
                                }
225
                                nr_route           = nr_node->routes[1];
226
                                nr_node->routes[1] = nr_node->routes[2];
227
                                nr_node->routes[2] = nr_route;
228
                        }
229
                case 2:
230
                        if (nr_node->routes[1].quality > nr_node->routes[0].quality) {
231
                                switch (nr_node->which) {
232
                                        case 0:  nr_node->which = 1; break;
233
                                        case 1:  nr_node->which = 0; break;
234
                                        default: break;
235
                                }
236
                                nr_route           = nr_node->routes[0];
237
                                nr_node->routes[0] = nr_node->routes[1];
238
                                nr_node->routes[1] = nr_route;
239
                        }
240
                case 1:
241
                        break;
242
        }
243
 
244
        for (i = 0; i < nr_node->count; i++) {
245
                if (nr_node->routes[i].neighbour == nr_neigh) {
246
                        if (i < nr_node->which)
247
                                nr_node->which = i;
248
                        break;
249
                }
250
        }
251
 
252
        return 0;
253
}
254
 
255
static void nr_remove_node(struct nr_node *nr_node)
256
{
257
        struct nr_node *s;
258
        unsigned long flags;
259
 
260
        save_flags(flags);
261
        cli();
262
 
263
        if ((s = nr_node_list) == nr_node) {
264
                nr_node_list = nr_node->next;
265
                restore_flags(flags);
266
                kfree_s(nr_node, sizeof(struct nr_node));
267
                return;
268
        }
269
 
270
        while (s != NULL && s->next != NULL) {
271
                if (s->next == nr_node) {
272
                        s->next = nr_node->next;
273
                        restore_flags(flags);
274
                        kfree_s(nr_node, sizeof(struct nr_node));
275
                        return;
276
                }
277
 
278
                s = s->next;
279
        }
280
 
281
        restore_flags(flags);
282
}
283
 
284
static void nr_remove_neigh(struct nr_neigh *nr_neigh)
285
{
286
        struct nr_neigh *s;
287
        unsigned long flags;
288
 
289
        save_flags(flags);
290
        cli();
291
 
292
        if ((s = nr_neigh_list) == nr_neigh) {
293
                nr_neigh_list = nr_neigh->next;
294
                restore_flags(flags);
295
                if (nr_neigh->digipeat != NULL)
296
                        kfree_s(nr_neigh->digipeat, sizeof(ax25_digi));
297
                kfree_s(nr_neigh, sizeof(struct nr_neigh));
298
                return;
299
        }
300
 
301
        while (s != NULL && s->next != NULL) {
302
                if (s->next == nr_neigh) {
303
                        s->next = nr_neigh->next;
304
                        restore_flags(flags);
305
                        if (nr_neigh->digipeat != NULL)
306
                                kfree_s(nr_neigh->digipeat, sizeof(ax25_digi));
307
                        kfree_s(nr_neigh, sizeof(struct nr_neigh));
308
                        return;
309
                }
310
 
311
                s = s->next;
312
        }
313
 
314
        restore_flags(flags);
315
}
316
 
317
/*
318
 *      "Delete" a node. Strictly speaking remove a route to a node. The node
319
 *      is only deleted if no routes are left to it.
320
 */
321
static int nr_del_node(ax25_address *callsign, ax25_address *neighbour, struct device *dev)
322
{
323
        struct nr_node  *nr_node;
324
        struct nr_neigh *nr_neigh;
325
        int i;
326
 
327
        for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next)
328
                if (ax25cmp(callsign, &nr_node->callsign) == 0)
329
                        break;
330
 
331
        if (nr_node == NULL) return -EINVAL;
332
 
333
        for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next)
334
                if (ax25cmp(neighbour, &nr_neigh->callsign) == 0 && nr_neigh->dev == dev)
335
                        break;
336
 
337
        if (nr_neigh == NULL) return -EINVAL;
338
 
339
        for (i = 0; i < nr_node->count; i++) {
340
                if (nr_node->routes[i].neighbour == nr_neigh) {
341
                        nr_neigh->count--;
342
 
343
                        if (nr_neigh->count == 0 && !nr_neigh->locked)
344
                                nr_remove_neigh(nr_neigh);
345
 
346
                        nr_node->count--;
347
 
348
                        if (nr_node->count == 0) {
349
                                nr_remove_node(nr_node);
350
                        } else {
351
                                switch (i) {
352
                                        case 0:
353
                                                nr_node->routes[0] = nr_node->routes[1];
354
                                        case 1:
355
                                                nr_node->routes[1] = nr_node->routes[2];
356
                                        case 2:
357
                                                break;
358
                                }
359
                        }
360
 
361
                        return 0;
362
                }
363
        }
364
 
365
        return -EINVAL;
366
}
367
 
368
/*
369
 *      Lock a neighbour with a quality.
370
 */
371
static int nr_add_neigh(ax25_address *callsign, ax25_digi *ax25_digi, struct device *dev, unsigned int quality)
372
{
373
        struct nr_neigh *nr_neigh;
374
        unsigned long flags;
375
 
376
        for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next) {
377
                if (ax25cmp(callsign, &nr_neigh->callsign) == 0 && nr_neigh->dev == dev) {
378
                        nr_neigh->quality = quality;
379
                        nr_neigh->locked  = 1;
380
                        return 0;
381
                }
382
        }
383
 
384
        if ((nr_neigh = (struct nr_neigh *)kmalloc(sizeof(*nr_neigh), GFP_ATOMIC)) == NULL)
385
                return -ENOMEM;
386
 
387
        nr_neigh->callsign = *callsign;
388
        nr_neigh->digipeat = NULL;
389
        nr_neigh->ax25     = NULL;
390
        nr_neigh->dev      = dev;
391
        nr_neigh->quality  = quality;
392
        nr_neigh->locked   = 1;
393
        nr_neigh->count    = 0;
394
        nr_neigh->number   = nr_neigh_no++;
395
        nr_neigh->failed   = 0;
396
 
397
        if (ax25_digi != NULL && ax25_digi->ndigi > 0) {
398
                if ((nr_neigh->digipeat = kmalloc(sizeof(*ax25_digi), GFP_KERNEL)) == NULL) {
399
                        kfree_s(nr_neigh, sizeof(*nr_neigh));
400
                        return -ENOMEM;
401
                }
402
                *nr_neigh->digipeat = *ax25_digi;
403
        }
404
 
405
        save_flags(flags);
406
        cli();
407
 
408
        nr_neigh->next = nr_neigh_list;
409
        nr_neigh_list  = nr_neigh;
410
 
411
        restore_flags(flags);
412
 
413
        return 0;
414
}
415
 
416
/*
417
 *      "Delete" a neighbour. The neighbour is only removed if the number
418
 *      of nodes that may use it is zero.
419
 */
420
static int nr_del_neigh(ax25_address *callsign, struct device *dev, unsigned int quality)
421
{
422
        struct nr_neigh *nr_neigh;
423
 
424
        for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next)
425
                if (ax25cmp(callsign, &nr_neigh->callsign) == 0 && nr_neigh->dev == dev)
426
                        break;
427
 
428
        if (nr_neigh == NULL) return -EINVAL;
429
 
430
        nr_neigh->quality = quality;
431
        nr_neigh->locked  = 0;
432
 
433
        if (nr_neigh->count == 0)
434
                nr_remove_neigh(nr_neigh);
435
 
436
        return 0;
437
}
438
 
439
/*
440
 *      Decrement the obsolescence count by one. If a route is reduced to a
441
 *      count of zero, remove it. Also remove any unlocked neighbours with
442
 *      zero nodes routing via it.
443
 */
444
static int nr_dec_obs(void)
445
{
446
        struct nr_neigh *nr_neigh;
447
        struct nr_node  *s, *nr_node;
448
        int i;
449
 
450
        nr_node = nr_node_list;
451
 
452
        while (nr_node != NULL) {
453
                s       = nr_node;
454
                nr_node = nr_node->next;
455
 
456
                for (i = 0; i < s->count; i++) {
457
                        switch (s->routes[i].obs_count) {
458
 
459
                        case 0:          /* A locked entry */
460
                                break;
461
 
462
                        case 1:         /* From 1 -> 0 */
463
                                nr_neigh = s->routes[i].neighbour;
464
 
465
                                nr_neigh->count--;
466
 
467
                                if (nr_neigh->count == 0 && !nr_neigh->locked)
468
                                        nr_remove_neigh(nr_neigh);
469
 
470
                                s->count--;
471
 
472
                                switch (i) {
473
                                        case 0:
474
                                                s->routes[0] = s->routes[1];
475
                                        case 1:
476
                                                s->routes[1] = s->routes[2];
477
                                        case 2:
478
                                                break;
479
                                }
480
                                break;
481
 
482
                        default:
483
                                s->routes[i].obs_count--;
484
                                break;
485
 
486
                        }
487
                }
488
 
489
                if (s->count <= 0)
490
                        nr_remove_node(s);
491
        }
492
 
493
        return 0;
494
}
495
 
496
/*
497
 *      A device has been removed. Remove its routes and neighbours.
498
 */
499
void nr_rt_device_down(struct device *dev)
500
{
501
        struct nr_neigh *s, *nr_neigh = nr_neigh_list;
502
        struct nr_node  *t, *nr_node;
503
        int i;
504
 
505
        while (nr_neigh != NULL) {
506
                s        = nr_neigh;
507
                nr_neigh = nr_neigh->next;
508
 
509
                if (s->dev == dev) {
510
                        nr_node = nr_node_list;
511
 
512
                        while (nr_node != NULL) {
513
                                t       = nr_node;
514
                                nr_node = nr_node->next;
515
 
516
                                for (i = 0; i < t->count; i++) {
517
                                        if (t->routes[i].neighbour == s) {
518
                                                t->count--;
519
 
520
                                                switch (i) {
521
                                                        case 0:
522
                                                                t->routes[0] = t->routes[1];
523
                                                        case 1:
524
                                                                t->routes[1] = t->routes[2];
525
                                                        case 2:
526
                                                                break;
527
                                                }
528
                                        }
529
                                }
530
 
531
                                if (t->count <= 0)
532
                                        nr_remove_node(t);
533
                        }
534
 
535
                        nr_remove_neigh(s);
536
                }
537
        }
538
}
539
 
540
/*
541
 *      Check that the device given is a valid AX.25 interface that is "up".
542
 *      Or a valid ethernet interface with an AX.25 callsign binding.
543
 */
544
static struct device *nr_ax25_dev_get(char *devname)
545
{
546
        struct device *dev;
547
 
548
        if ((dev = dev_get(devname)) == NULL)
549
                return NULL;
550
 
551
        if ((dev->flags & IFF_UP) && dev->type == ARPHRD_AX25)
552
                return dev;
553
 
554
        return NULL;
555
}
556
 
557
/*
558
 *      Find the first active NET/ROM device, usually "nr0".
559
 */
560
struct device *nr_dev_first(void)
561
{
562
        struct device *dev, *first = NULL;
563
 
564
        for (dev = dev_base; dev != NULL; dev = dev->next)
565
                if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM)
566
                        if (first == NULL || strncmp(dev->name, first->name, 3) < 0)
567
                                first = dev;
568
 
569
        return first;
570
}
571
 
572
/*
573
 *      Find the NET/ROM device for the given callsign.
574
 */
575
struct device *nr_dev_get(ax25_address *addr)
576
{
577
        struct device *dev;
578
 
579
        for (dev = dev_base; dev != NULL; dev = dev->next)
580
                if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM && ax25cmp(addr, (ax25_address *)dev->dev_addr) == 0)
581
                        return dev;
582
 
583
        return NULL;
584
}
585
 
586
static ax25_digi *nr_call_to_digi(int ndigis, ax25_address *digipeaters)
587
{
588
        static ax25_digi ax25_digi;
589
        int i;
590
 
591
        if (ndigis == 0)
592
                return NULL;
593
 
594
        for (i = 0; i < ndigis; i++) {
595
                ax25_digi.calls[i]    = digipeaters[i];
596
                ax25_digi.repeated[i] = 0;
597
        }
598
 
599
        ax25_digi.ndigi      = ndigis;
600
        ax25_digi.lastrepeat = -1;
601
 
602
        return &ax25_digi;
603
}
604
 
605
/*
606
 *      Handle the ioctls that control the routing functions.
607
 */
608
int nr_rt_ioctl(unsigned int cmd, void *arg)
609
{
610
        struct nr_route_struct nr_route;
611
        struct device *dev;
612
        int err;
613
 
614
        switch (cmd) {
615
 
616
                case SIOCADDRT:
617
                        if ((err = verify_area(VERIFY_READ, arg, sizeof(struct nr_route_struct))) != 0)
618
                                return err;
619
                        memcpy_fromfs(&nr_route, arg, sizeof(struct nr_route_struct));
620
                        if ((dev = nr_ax25_dev_get(nr_route.device)) == NULL)
621
                                return -EINVAL;
622
                        if (nr_route.ndigis < 0 || nr_route.ndigis > AX25_MAX_DIGIS)
623
                                return -EINVAL;
624
                        switch (nr_route.type) {
625
                                case NETROM_NODE:
626
                                        return nr_add_node(&nr_route.callsign,
627
                                                nr_route.mnemonic,
628
                                                &nr_route.neighbour,
629
                                                nr_call_to_digi(nr_route.ndigis, nr_route.digipeaters),
630
                                                dev, nr_route.quality,
631
                                                nr_route.obs_count);
632
                                case NETROM_NEIGH:
633
                                        return nr_add_neigh(&nr_route.callsign,
634
                                                nr_call_to_digi(nr_route.ndigis, nr_route.digipeaters),
635
                                                dev, nr_route.quality);
636
                                default:
637
                                        return -EINVAL;
638
                        }
639
 
640
                case SIOCDELRT:
641
                        if ((err = verify_area(VERIFY_READ, arg, sizeof(struct nr_route_struct))) != 0)
642
                                return err;
643
                        memcpy_fromfs(&nr_route, arg, sizeof(struct nr_route_struct));
644
                        if ((dev = nr_ax25_dev_get(nr_route.device)) == NULL)
645
                                return -EINVAL;
646
                        switch (nr_route.type) {
647
                                case NETROM_NODE:
648
                                        return nr_del_node(&nr_route.callsign,
649
                                                &nr_route.neighbour, dev);
650
                                case NETROM_NEIGH:
651
                                        return nr_del_neigh(&nr_route.callsign,
652
                                                dev, nr_route.quality);
653
                                default:
654
                                        return -EINVAL;
655
                        }
656
 
657
                case SIOCNRDECOBS:
658
                        return nr_dec_obs();
659
 
660
                default:
661
                        return -EINVAL;
662
        }
663
 
664
        return 0;
665
}
666
 
667
/*
668
 *      A level 2 link has timed out, therefore it appears to be a poor link,
669
 *      then don't use that neighbour until it is reset.
670
 */
671
void nr_link_failed(ax25_cb *ax25, int reason)
672
{
673
        struct nr_neigh *nr_neigh;
674
        struct nr_node  *nr_node;
675
 
676
        for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next)
677
                if (nr_neigh->ax25 == ax25)
678
                        break;
679
 
680
        if (nr_neigh == NULL) return;
681
 
682
        nr_neigh->ax25 = NULL;
683
 
684
        if (++nr_neigh->failed < sysctl_netrom_link_fails_count) return;
685
 
686
        for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next)
687
                if (nr_node->which < nr_node->count && nr_node->routes[nr_node->which].neighbour == nr_neigh)
688
                        nr_node->which++;
689
}
690
 
691
/*
692
 *      Route a frame to an appropriate AX.25 connection. A NULL ax25_cb
693
 *      indicates an internally generated frame.
694
 */
695
int nr_route_frame(struct sk_buff *skb, ax25_cb *ax25)
696
{
697
        ax25_address *nr_src, *nr_dest;
698
        struct nr_neigh *nr_neigh;
699
        struct nr_node  *nr_node;
700
        struct device *dev;
701
        unsigned char *dptr;
702
 
703
#ifdef CONFIG_FIREWALL
704
        if (ax25 != NULL && call_in_firewall(PF_NETROM, skb->dev, skb->data, NULL) != FW_ACCEPT)
705
                return 0;
706
        if (ax25 == NULL && call_out_firewall(PF_NETROM, skb->dev, skb->data, NULL) != FW_ACCEPT)
707
                return 0;
708
#endif
709
 
710
        nr_src  = (ax25_address *)(skb->data + 0);
711
        nr_dest = (ax25_address *)(skb->data + 7);
712
 
713
        if (ax25 != NULL)
714
                nr_add_node(nr_src, "", &ax25->dest_addr, ax25->digipeat,
715
                            ax25->device, 0, sysctl_netrom_obsolescence_count_initialiser);
716
 
717
        if ((dev = nr_dev_get(nr_dest)) != NULL) {      /* Its for me */
718
                if (ax25 == NULL)                       /* Its from me */
719
                        return nr_loopback_queue(skb);
720
                else
721
                        return nr_rx_frame(skb, dev);
722
        }
723
 
724
        if (!sysctl_netrom_routing_control && ax25 != NULL)
725
                return 0;
726
 
727
        /* Its Time-To-Live has expired */
728
        if (--skb->data[14] == 0)
729
                return 0;
730
 
731
        for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next)
732
                if (ax25cmp(nr_dest, &nr_node->callsign) == 0)
733
                        break;
734
 
735
        if (nr_node == NULL || nr_node->which >= nr_node->count)
736
                return 0;
737
 
738
        nr_neigh = nr_node->routes[nr_node->which].neighbour;
739
 
740
        if ((dev = nr_dev_first()) == NULL)
741
                return 0;
742
 
743
#ifdef CONFIG_FIREWALL
744
        if (ax25 != NULL && call_fw_firewall(PF_NETROM, skb->dev, skb->data, NULL) != FW_ACCEPT)
745
                return 0;
746
#endif
747
 
748
        dptr  = skb_push(skb, 1);
749
        *dptr = AX25_P_NETROM;
750
 
751
        nr_neigh->ax25 = ax25_send_frame(skb, 256, (ax25_address *)dev->dev_addr, &nr_neigh->callsign, nr_neigh->digipeat, nr_neigh->dev);
752
 
753
        return (nr_neigh->ax25 != NULL);
754
}
755
 
756
int nr_nodes_get_info(char *buffer, char **start, off_t offset,
757
                      int length, int dummy)
758
{
759
        struct nr_node *nr_node;
760
        int len     = 0;
761
        off_t pos   = 0;
762
        off_t begin = 0;
763
        int i;
764
 
765
        cli();
766
 
767
        len += sprintf(buffer, "callsign  mnemonic w n qual obs neigh qual obs neigh qual obs neigh\n");
768
 
769
        for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next) {
770
                len += sprintf(buffer + len, "%-9s %-7s  %d %d",
771
                        ax2asc(&nr_node->callsign),
772
                        (nr_node->mnemonic[0] == '\0') ? "*" : nr_node->mnemonic,
773
                        nr_node->which + 1,
774
                        nr_node->count);
775
 
776
                for (i = 0; i < nr_node->count; i++) {
777
                        len += sprintf(buffer + len, "  %3d   %d %05d",
778
                                nr_node->routes[i].quality,
779
                                nr_node->routes[i].obs_count,
780
                                nr_node->routes[i].neighbour->number);
781
                }
782
 
783
                len += sprintf(buffer + len, "\n");
784
 
785
                pos = begin + len;
786
 
787
                if (pos < offset) {
788
                        len   = 0;
789
                        begin = pos;
790
                }
791
 
792
                if (pos > offset + length)
793
                        break;
794
        }
795
 
796
        sti();
797
 
798
        *start = buffer + (offset - begin);
799
        len   -= (offset - begin);
800
 
801
        if (len > length) len = length;
802
 
803
        return len;
804
}
805
 
806
int nr_neigh_get_info(char *buffer, char **start, off_t offset,
807
                      int length, int dummy)
808
{
809
        struct nr_neigh *nr_neigh;
810
        int len     = 0;
811
        off_t pos   = 0;
812
        off_t begin = 0;
813
        int i;
814
 
815
        cli();
816
 
817
        len += sprintf(buffer, "addr  callsign  dev  qual lock count failed digipeaters\n");
818
 
819
        for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next) {
820
                len += sprintf(buffer + len, "%05d %-9s %-4s  %3d    %d   %3d    %3d",
821
                        nr_neigh->number,
822
                        ax2asc(&nr_neigh->callsign),
823
                        nr_neigh->dev ? nr_neigh->dev->name : "???",
824
                        nr_neigh->quality,
825
                        nr_neigh->locked,
826
                        nr_neigh->count,
827
                        nr_neigh->failed);
828
 
829
                if (nr_neigh->digipeat != NULL) {
830
                        for (i = 0; i < nr_neigh->digipeat->ndigi; i++)
831
                                len += sprintf(buffer + len, " %s", ax2asc(&nr_neigh->digipeat->calls[i]));
832
                }
833
 
834
                len += sprintf(buffer + len, "\n");
835
 
836
                pos = begin + len;
837
 
838
                if (pos < offset) {
839
                        len   = 0;
840
                        begin = pos;
841
                }
842
 
843
                if (pos > offset + length)
844
                        break;
845
        }
846
 
847
        sti();
848
 
849
        *start = buffer + (offset - begin);
850
        len   -= (offset - begin);
851
 
852
        if (len > length) len = length;
853
 
854
        return len;
855
}
856
 
857
#ifdef MODULE
858
 
859
/*
860
 *      Free all memory associated with the nodes and routes lists.
861
 */
862
void nr_rt_free(void)
863
{
864
        struct nr_neigh *s, *nr_neigh = nr_neigh_list;
865
        struct nr_node  *t, *nr_node  = nr_node_list;
866
 
867
        while (nr_node != NULL) {
868
                t       = nr_node;
869
                nr_node = nr_node->next;
870
 
871
                nr_remove_node(t);
872
        }
873
 
874
        while (nr_neigh != NULL) {
875
                s        = nr_neigh;
876
                nr_neigh = nr_neigh->next;
877
 
878
                nr_remove_neigh(s);
879
        }
880
}
881
 
882
#endif
883
 
884
#endif

powered by: WebSVN 2.1.0

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