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

Subversion Repositories or1k

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

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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