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