This source file includes following definitions.
- nr_add_node
- nr_remove_node
- nr_remove_neigh
- nr_del_node
- nr_add_neigh
- nr_del_neigh
- nr_dec_obs
- nr_rt_device_down
- nr_ax25_dev_get
- nr_dev_first
- nr_dev_get
- nr_rt_ioctl
- nr_link_failed
- nr_route_frame
- nr_nodes_get_info
- nr_neigh_get_info
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 #include <linux/config.h>
28 #ifdef CONFIG_NETROM
29 #include <linux/errno.h>
30 #include <linux/types.h>
31 #include <linux/socket.h>
32 #include <linux/in.h>
33 #include <linux/kernel.h>
34 #include <linux/sched.h>
35 #include <linux/timer.h>
36 #include <linux/string.h>
37 #include <linux/sockios.h>
38 #include <linux/net.h>
39 #include <net/ax25.h>
40 #include <linux/inet.h>
41 #include <linux/netdevice.h>
42 #include <net/arp.h>
43 #include <linux/if_arp.h>
44 #include <linux/skbuff.h>
45 #include <net/sock.h>
46 #include <asm/segment.h>
47 #include <asm/system.h>
48 #include <linux/fcntl.h>
49 #include <linux/termios.h>
50 #include <linux/mm.h>
51 #include <linux/interrupt.h>
52 #include <linux/notifier.h>
53 #include <net/netrom.h>
54
55 static int nr_neigh_no = 1;
56 static int nr_route_on = 1;
57
58 static struct nr_node *nr_node_list = NULL;
59 static struct nr_neigh *nr_neigh_list = NULL;
60
61
62
63
64
65 static int nr_add_node(ax25_address *nr, const char *mnemonic, ax25_address *ax25,
66 ax25_digi *ax25_digi, struct device *dev, int quality, int obs_count)
67 {
68 struct nr_node *nr_node;
69 struct nr_neigh *nr_neigh;
70 struct nr_route nr_route;
71 unsigned long flags;
72 int i, found;
73
74 for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next)
75 if (ax25cmp(nr, &nr_node->callsign) == 0)
76 break;
77
78 for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next)
79 if (ax25cmp(ax25, &nr_neigh->callsign) == 0 && nr_neigh->dev == dev)
80 break;
81
82 if (quality == 0 && nr_neigh != NULL && nr_node != NULL)
83 return 0;
84
85 if (nr_neigh == NULL) {
86 if ((nr_neigh = (struct nr_neigh *)kmalloc(sizeof(*nr_neigh), GFP_ATOMIC)) == NULL)
87 return -ENOMEM;
88
89 memcpy(&nr_neigh->callsign, ax25, sizeof(ax25_address));
90
91 nr_neigh->digipeat= NULL;
92 nr_neigh->dev = dev;
93 nr_neigh->quality = nr_default.quality;
94 nr_neigh->locked = 0;
95 nr_neigh->count = 0;
96 nr_neigh->number = nr_neigh_no++;
97
98 if (ax25_digi != NULL) {
99 if ((nr_neigh->digipeat = kmalloc(sizeof(*ax25_digi), GFP_KERNEL)) == NULL) {
100 kfree_s(nr_neigh, sizeof(*nr_neigh));
101 return -ENOMEM;
102 }
103 memcpy(nr_neigh->digipeat, ax25_digi, sizeof(*ax25_digi));
104 }
105
106 save_flags(flags);
107 cli();
108
109 nr_neigh->next = nr_neigh_list;
110 nr_neigh_list = nr_neigh;
111
112 restore_flags(flags);
113 }
114
115 if (nr_node == NULL) {
116 if ((nr_node = (struct nr_node *)kmalloc(sizeof(*nr_node), GFP_ATOMIC)) == NULL)
117 return -ENOMEM;
118
119 memcpy(&nr_node->callsign, nr, sizeof(ax25_address));
120 memcpy(&nr_node->mnemonic, mnemonic, sizeof(nr_node->mnemonic));
121
122 nr_node->which = 0;
123 nr_node->count = 1;
124
125 nr_node->routes[0].quality = quality;
126 nr_node->routes[0].obs_count = obs_count;
127 nr_node->routes[0].neighbour = nr_neigh->number;
128
129 save_flags(flags);
130 cli();
131
132 nr_node->next = nr_node_list;
133 nr_node_list = nr_node;
134
135 restore_flags(flags);
136
137 nr_neigh->count++;
138
139 return 0;
140 }
141
142 for (found = 0, i = 0; i < nr_node->count; i++) {
143 if (nr_node->routes[i].neighbour == nr_neigh->number) {
144 nr_node->routes[i].quality = quality;
145 nr_node->routes[i].obs_count = obs_count;
146 found = 1;
147 break;
148 }
149 }
150
151 if (!found) {
152
153 if (nr_node->count < 3) {
154 nr_node->routes[2] = nr_node->routes[1];
155 nr_node->routes[1] = nr_node->routes[0];
156
157 nr_node->routes[0].quality = quality;
158 nr_node->routes[0].obs_count = obs_count;
159 nr_node->routes[0].neighbour = nr_neigh->number;
160
161 nr_node->count++;
162 nr_neigh->count++;
163 } else {
164
165 if (quality > nr_node->routes[2].quality) {
166 nr_node->routes[2].quality = quality;
167 nr_node->routes[2].obs_count = obs_count;
168 nr_node->routes[2].neighbour = nr_neigh->number;
169
170 nr_neigh->count++;
171 }
172 }
173 }
174
175
176 switch (nr_node->count) {
177 case 3:
178 if (nr_node->routes[1].quality > nr_node->routes[0].quality) {
179 switch (nr_node->which) {
180 case 0: nr_node->which = 1; break;
181 case 1: nr_node->which = 0; break;
182 default: break;
183 }
184 nr_route = nr_node->routes[0];
185 nr_node->routes[0] = nr_node->routes[1];
186 nr_node->routes[1] = nr_route;
187 }
188 if (nr_node->routes[2].quality > nr_node->routes[1].quality) {
189 switch (nr_node->which) {
190 case 1: nr_node->which = 2; break;
191 case 2: nr_node->which = 1; break;
192 default: break;
193 }
194 nr_route = nr_node->routes[1];
195 nr_node->routes[1] = nr_node->routes[2];
196 nr_node->routes[2] = nr_route;
197 }
198 case 2:
199 if (nr_node->routes[1].quality > nr_node->routes[0].quality) {
200 switch (nr_node->which) {
201 case 0: nr_node->which = 1; break;
202 case 1: nr_node->which = 0; break;
203 default: break;
204 }
205 nr_route = nr_node->routes[0];
206 nr_node->routes[0] = nr_node->routes[1];
207 nr_node->routes[1] = nr_route;
208 }
209 case 1:
210 break;
211 }
212
213 for (i = 0; i < nr_node->count; i++) {
214 if (nr_node->routes[i].neighbour == nr_neigh->number) {
215 if (i < nr_node->which)
216 nr_node->which = i;
217 break;
218 }
219 }
220
221 return 0;
222 }
223
224 static void nr_remove_node(struct nr_node *nr_node)
225 {
226 struct nr_node *s;
227 unsigned long flags;
228
229 save_flags(flags);
230 cli();
231
232 if ((s = nr_node_list) == nr_node) {
233 nr_node_list = nr_node->next;
234 restore_flags(flags);
235 kfree_s(nr_node, sizeof(struct nr_node));
236 return;
237 }
238
239 while (s != NULL && s->next != NULL) {
240 if (s->next == nr_node) {
241 s->next = nr_node->next;
242 restore_flags(flags);
243 kfree_s(nr_node, sizeof(struct nr_node));
244 return;
245 }
246
247 s = s->next;
248 }
249
250 restore_flags(flags);
251 }
252
253 static void nr_remove_neigh(struct nr_neigh *nr_neigh)
254 {
255 struct nr_neigh *s;
256 unsigned long flags;
257
258 save_flags(flags);
259 cli();
260
261 if ((s = nr_neigh_list) == nr_neigh) {
262 nr_neigh_list = nr_neigh->next;
263 restore_flags(flags);
264 if (nr_neigh->digipeat != NULL)
265 kfree_s(nr_neigh->digipeat, sizeof(ax25_digi));
266 kfree_s(nr_neigh, sizeof(struct nr_neigh));
267 return;
268 }
269
270 while (s != NULL && s->next != NULL) {
271 if (s->next == nr_neigh) {
272 s->next = nr_neigh->next;
273 restore_flags(flags);
274 if (nr_neigh->digipeat != NULL)
275 kfree_s(nr_neigh->digipeat, sizeof(ax25_digi));
276 kfree_s(nr_neigh, sizeof(struct nr_neigh));
277 return;
278 }
279
280 s = s->next;
281 }
282
283 restore_flags(flags);
284 }
285
286
287
288
289
290 static int nr_del_node(ax25_address *callsign, ax25_address *neighbour, struct device *dev)
291 {
292 struct nr_node *nr_node;
293 struct nr_neigh *nr_neigh;
294 int i;
295
296 for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next)
297 if (ax25cmp(callsign, &nr_node->callsign) == 0)
298 break;
299
300 if (nr_node == NULL) return -EINVAL;
301
302 for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next)
303 if (ax25cmp(neighbour, &nr_neigh->callsign) == 0 && nr_neigh->dev == dev)
304 break;
305
306 if (nr_neigh == NULL) return -EINVAL;
307
308 for (i = 0; i < nr_node->count; i++) {
309 if (nr_node->routes[i].neighbour == nr_neigh->number) {
310 nr_neigh->count--;
311
312 if (nr_neigh->count == 0 && !nr_neigh->locked)
313 nr_remove_neigh(nr_neigh);
314
315 nr_node->count--;
316
317 if (nr_node->count == 0) {
318 nr_remove_node(nr_node);
319 } else {
320 switch (i) {
321 case 0:
322 nr_node->routes[0] = nr_node->routes[1];
323 case 1:
324 nr_node->routes[1] = nr_node->routes[2];
325 case 2:
326 break;
327 }
328 }
329
330 return 0;
331 }
332 }
333
334 return -EINVAL;
335 }
336
337
338
339
340 static int nr_add_neigh(ax25_address *callsign, struct device *dev, unsigned int quality)
341 {
342 struct nr_neigh *nr_neigh;
343 unsigned long flags;
344
345 for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next) {
346 if (ax25cmp(callsign, &nr_neigh->callsign) == 0 && nr_neigh->dev == dev) {
347 nr_neigh->quality = quality;
348 nr_neigh->locked = 1;
349 return 0;
350 }
351 }
352
353 if ((nr_neigh = (struct nr_neigh *)kmalloc(sizeof(*nr_neigh), GFP_ATOMIC)) == NULL)
354 return -ENOMEM;
355
356 memcpy(&nr_neigh->callsign, callsign, sizeof(ax25_address));
357
358 nr_neigh->digipeat= NULL;
359 nr_neigh->dev = dev;
360 nr_neigh->quality = quality;
361 nr_neigh->locked = 1;
362 nr_neigh->count = 0;
363 nr_neigh->number = nr_neigh_no++;
364
365 save_flags(flags);
366 cli();
367
368 nr_neigh->next = nr_neigh_list;
369 nr_neigh_list = nr_neigh;
370
371 restore_flags(flags);
372
373 return 0;
374 }
375
376
377
378
379
380 static int nr_del_neigh(ax25_address *callsign, struct device *dev, unsigned int quality)
381 {
382 struct nr_neigh *nr_neigh;
383
384 for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next)
385 if (ax25cmp(callsign, &nr_neigh->callsign) == 0 && nr_neigh->dev == dev)
386 break;
387
388 if (nr_neigh == NULL) return -EINVAL;
389
390 nr_neigh->quality = quality;
391 nr_neigh->locked = 0;
392
393 if (nr_neigh->count == 0)
394 nr_remove_neigh(nr_neigh);
395
396 return 0;
397 }
398
399
400
401
402
403
404 static int nr_dec_obs(void)
405 {
406 struct nr_neigh *t, *nr_neigh;
407 struct nr_node *s, *nr_node;
408 int i;
409
410 nr_node = nr_node_list;
411
412 while (nr_node != NULL) {
413 s = nr_node;
414 nr_node = nr_node->next;
415
416 for (i = 0; i < s->count; i++) {
417 switch (s->routes[i].obs_count) {
418
419 case 0:
420 break;
421
422 case 1:
423 nr_neigh = nr_neigh_list;
424
425 while (nr_neigh != NULL) {
426 t = nr_neigh;
427 nr_neigh = nr_neigh->next;
428
429 if (t->number == s->routes[i].neighbour) {
430 t->count--;
431
432 if (t->count == 0 && !t->locked)
433 nr_remove_neigh(t);
434
435 break;
436 }
437 }
438
439 s->count--;
440
441 switch (i) {
442 case 0:
443 s->routes[0] = s->routes[1];
444 case 1:
445 s->routes[1] = s->routes[2];
446 case 2:
447 break;
448 }
449 break;
450
451 default:
452 s->routes[i].obs_count--;
453 break;
454
455 }
456 }
457
458 if (s->count <= 0)
459 nr_remove_node(s);
460 }
461
462 return 0;
463 }
464
465
466
467
468 void nr_rt_device_down(struct device *dev)
469 {
470 struct nr_neigh *s, *nr_neigh = nr_neigh_list;
471 struct nr_node *t, *nr_node;
472 int i;
473
474 while (nr_neigh != NULL) {
475 s = nr_neigh;
476 nr_neigh = nr_neigh->next;
477
478 if (s->dev == dev) {
479 nr_node = nr_node_list;
480
481 while (nr_node != NULL) {
482 t = nr_node;
483 nr_node = nr_node->next;
484
485 for (i = 0; i < t->count; i++) {
486 if (t->routes[i].neighbour == s->number) {
487 t->count--;
488
489 switch (i) {
490 case 0:
491 t->routes[0] = t->routes[1];
492 case 1:
493 t->routes[1] = t->routes[2];
494 case 2:
495 break;
496 }
497 }
498 }
499
500 if (t->count <= 0)
501 nr_remove_node(t);
502 }
503
504 nr_remove_neigh(s);
505 }
506 }
507 }
508
509
510
511
512
513 static struct device *nr_ax25_dev_get(char *devname)
514 {
515 struct device *dev;
516 ax25_address callsign;
517
518 if ((dev = dev_get(devname)) == NULL)
519 return NULL;
520
521 if ((dev->flags & IFF_UP) && dev->type == ARPHRD_AX25)
522 return dev;
523
524 if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ETHER)
525 if (arp_query((unsigned char *)&callsign, dev->pa_addr, ARPHRD_AX25))
526 return dev;
527
528 return NULL;
529 }
530
531
532
533
534 struct device *nr_dev_first(void)
535 {
536 struct device *dev, *first = NULL;
537
538 for (dev = dev_base; dev != NULL; dev = dev->next)
539 if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM)
540 if (first == NULL || strncmp(dev->name, first->name, 3) < 0)
541 first = dev;
542
543 return first;
544 }
545
546
547
548
549 struct device *nr_dev_get(ax25_address *addr)
550 {
551 struct device *dev;
552
553 for (dev = dev_base; dev != NULL; dev = dev->next)
554 if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM && ax25cmp(addr, (ax25_address *)dev->dev_addr) == 0)
555 return dev;
556
557 return NULL;
558 }
559
560
561
562
563 int nr_rt_ioctl(unsigned int cmd, void *arg)
564 {
565 struct nr_route_struct nr_route;
566 struct device *dev;
567 int err;
568 long opt = 0;
569
570 switch (cmd) {
571
572 case SIOCADDRT:
573 if ((err = verify_area(VERIFY_READ, arg, sizeof(struct nr_route_struct))) != 0)
574 return err;
575 memcpy_fromfs(&nr_route, arg, sizeof(struct nr_route_struct));
576 if ((dev = nr_ax25_dev_get(nr_route.device)) == NULL)
577 return -EINVAL;
578 switch (nr_route.type) {
579 case NETROM_NODE:
580 return nr_add_node(&nr_route.callsign,
581 nr_route.mnemonic,
582 &nr_route.neighbour,
583 NULL, dev, nr_route.quality,
584 nr_route.obs_count);
585 case NETROM_NEIGH:
586 return nr_add_neigh(&nr_route.callsign,
587 dev, nr_route.quality);
588 default:
589 return -EINVAL;
590 }
591
592 case SIOCDELRT:
593 if ((err = verify_area(VERIFY_READ, arg, sizeof(struct nr_route_struct))) != 0)
594 return err;
595 memcpy_fromfs(&nr_route, arg, sizeof(struct nr_route_struct));
596 if ((dev = nr_ax25_dev_get(nr_route.device)) == NULL)
597 return -EINVAL;
598 switch (nr_route.type) {
599 case NETROM_NODE:
600 return nr_del_node(&nr_route.callsign,
601 &nr_route.neighbour, dev);
602 case NETROM_NEIGH:
603 return nr_del_neigh(&nr_route.callsign,
604 dev, nr_route.quality);
605 default:
606 return -EINVAL;
607 }
608
609 case SIOCNRDECOBS:
610 return nr_dec_obs();
611
612 case SIOCNRRTCTL:
613 if ((err = verify_area(VERIFY_READ, arg, sizeof(int))) != 0)
614 return err;
615 opt = get_fs_long((void *)arg);
616 nr_route_on = opt ? 1 : 0;
617 return 0;
618 }
619
620 return 0;
621 }
622
623
624
625
626
627 void nr_link_failed(ax25_address *callsign, struct device *dev)
628 {
629 struct nr_neigh *nr_neigh;
630 struct nr_node *nr_node;
631
632 for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next)
633 if (ax25cmp(&nr_neigh->callsign, callsign) == 0 && nr_neigh->dev == dev)
634 break;
635
636 if (nr_neigh == NULL) return;
637
638 for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next)
639 if (nr_node->which >= nr_node->count && nr_node->routes[nr_node->which].neighbour == nr_neigh->number)
640 nr_node->which++;
641 }
642
643
644
645
646
647 int nr_route_frame(struct sk_buff *skb, ax25_cb *ax25)
648 {
649 ax25_address *nr_src, *nr_dest;
650 struct nr_neigh *nr_neigh;
651 struct nr_node *nr_node;
652 struct device *dev;
653 unsigned char *dptr;
654
655 nr_src = (ax25_address *)(skb->data + 0);
656 nr_dest = (ax25_address *)(skb->data + 7);
657
658 if (ax25 != NULL)
659 nr_add_node(nr_src, "", &ax25->dest_addr, ax25->digipeat, ax25->device, 0, nr_default.obs_count);
660
661 if ((dev = nr_dev_get(nr_dest)) != NULL)
662 return nr_rx_frame(skb, dev);
663
664 if (!nr_route_on && ax25 != NULL)
665 return 0;
666
667
668 if (--skb->data[14] == 0)
669 return 0;
670
671 for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next)
672 if (ax25cmp(nr_dest, &nr_node->callsign) == 0)
673 break;
674
675 if (nr_node == NULL || nr_node->which >= nr_node->count)
676 return 0;
677
678 for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next)
679 if (nr_neigh->number == nr_node->routes[nr_node->which].neighbour)
680 break;
681
682 if (nr_neigh == NULL)
683 return 0;
684
685 if ((dev = nr_dev_first()) == NULL)
686 return 0;
687
688 dptr = skb_push(skb, 1);
689 *dptr = AX25_P_NETROM;
690
691 ax25_send_frame(skb, (ax25_address *)dev->dev_addr, &nr_neigh->callsign, nr_neigh->digipeat, nr_neigh->dev);
692
693 return 1;
694 }
695
696 int nr_nodes_get_info(char *buffer, char **start, off_t offset,
697 int length, int dummy)
698 {
699 struct nr_node *nr_node;
700 int len = 0;
701 off_t pos = 0;
702 off_t begin = 0;
703 int i;
704
705 cli();
706
707 len += sprintf(buffer, "callsign mnemonic w n qual obs neigh qual obs neigh qual obs neigh\n");
708
709 for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next) {
710 len += sprintf(buffer + len, "%-9s %-7s %d %d",
711 ax2asc(&nr_node->callsign),
712 nr_node->mnemonic,
713 nr_node->which + 1,
714 nr_node->count);
715
716 for (i = 0; i < nr_node->count; i++) {
717 len += sprintf(buffer + len, " %3d %d %05d",
718 nr_node->routes[i].quality,
719 nr_node->routes[i].obs_count,
720 nr_node->routes[i].neighbour);
721 }
722
723 len += sprintf(buffer + len, "\n");
724
725 pos = begin + len;
726
727 if (pos < offset) {
728 len = 0;
729 begin = pos;
730 }
731
732 if (pos > offset + length)
733 break;
734 }
735
736 sti();
737
738 *start = buffer + (offset - begin);
739 len -= (offset - begin);
740
741 if (len > length) len = length;
742
743 return(len);
744 }
745
746 int nr_neigh_get_info(char *buffer, char **start, off_t offset,
747 int length, int dummy)
748 {
749 struct nr_neigh *nr_neigh;
750 int len = 0;
751 off_t pos = 0;
752 off_t begin = 0;
753
754 cli();
755
756 len += sprintf(buffer, "addr callsign dev qual lock count\n");
757
758 for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next) {
759 len += sprintf(buffer + len, "%05d %-9s %-4s %3d %d %3d\n",
760 nr_neigh->number,
761 ax2asc(&nr_neigh->callsign),
762 nr_neigh->dev ? nr_neigh->dev->name : "???",
763 nr_neigh->quality,
764 nr_neigh->locked,
765 nr_neigh->count);
766
767 pos = begin + len;
768
769 if (pos < offset) {
770 len = 0;
771 begin = pos;
772 }
773
774 if (pos > offset + length)
775 break;
776 }
777
778 sti();
779
780 *start = buffer + (offset - begin);
781 len -= (offset - begin);
782
783 if (len > length) len = length;
784
785 return(len);
786 }
787
788 #endif