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
519 if ((dev = dev_get(devname)) == NULL)
520 return NULL;
521
522 if ((dev->flags & IFF_UP) && dev->type == ARPHRD_AX25)
523 return dev;
524
525 #ifdef CONFIG_BPQETHER
526 if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ETHER)
527 if (ax25_bpq_get_addr(dev) != NULL)
528 return dev;
529 #endif
530
531 return NULL;
532 }
533
534
535
536
537 struct device *nr_dev_first(void)
538 {
539 struct device *dev, *first = NULL;
540
541 for (dev = dev_base; dev != NULL; dev = dev->next)
542 if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM)
543 if (first == NULL || strncmp(dev->name, first->name, 3) < 0)
544 first = dev;
545
546 return first;
547 }
548
549
550
551
552 struct device *nr_dev_get(ax25_address *addr)
553 {
554 struct device *dev;
555
556 for (dev = dev_base; dev != NULL; dev = dev->next)
557 if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM && ax25cmp(addr, (ax25_address *)dev->dev_addr) == 0)
558 return dev;
559
560 return NULL;
561 }
562
563
564
565
566 int nr_rt_ioctl(unsigned int cmd, void *arg)
567 {
568 struct nr_route_struct nr_route;
569 struct device *dev;
570 int err;
571 long opt = 0;
572
573 switch (cmd) {
574
575 case SIOCADDRT:
576 if ((err = verify_area(VERIFY_READ, arg, sizeof(struct nr_route_struct))) != 0)
577 return err;
578 memcpy_fromfs(&nr_route, arg, sizeof(struct nr_route_struct));
579 if ((dev = nr_ax25_dev_get(nr_route.device)) == NULL)
580 return -EINVAL;
581 switch (nr_route.type) {
582 case NETROM_NODE:
583 return nr_add_node(&nr_route.callsign,
584 nr_route.mnemonic,
585 &nr_route.neighbour,
586 NULL, dev, nr_route.quality,
587 nr_route.obs_count);
588 case NETROM_NEIGH:
589 return nr_add_neigh(&nr_route.callsign,
590 dev, nr_route.quality);
591 default:
592 return -EINVAL;
593 }
594
595 case SIOCDELRT:
596 if ((err = verify_area(VERIFY_READ, arg, sizeof(struct nr_route_struct))) != 0)
597 return err;
598 memcpy_fromfs(&nr_route, arg, sizeof(struct nr_route_struct));
599 if ((dev = nr_ax25_dev_get(nr_route.device)) == NULL)
600 return -EINVAL;
601 switch (nr_route.type) {
602 case NETROM_NODE:
603 return nr_del_node(&nr_route.callsign,
604 &nr_route.neighbour, dev);
605 case NETROM_NEIGH:
606 return nr_del_neigh(&nr_route.callsign,
607 dev, nr_route.quality);
608 default:
609 return -EINVAL;
610 }
611
612 case SIOCNRDECOBS:
613 return nr_dec_obs();
614
615 case SIOCNRRTCTL:
616 if ((err = verify_area(VERIFY_READ, arg, sizeof(int))) != 0)
617 return err;
618 opt = get_fs_long((void *)arg);
619 nr_route_on = opt ? 1 : 0;
620 return 0;
621 }
622
623 return 0;
624 }
625
626
627
628
629
630 void nr_link_failed(ax25_address *callsign, struct device *dev)
631 {
632 struct nr_neigh *nr_neigh;
633 struct nr_node *nr_node;
634
635 for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next)
636 if (ax25cmp(&nr_neigh->callsign, callsign) == 0 && nr_neigh->dev == dev)
637 break;
638
639 if (nr_neigh == NULL) return;
640
641 for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next)
642 if (nr_node->which >= nr_node->count && nr_node->routes[nr_node->which].neighbour == nr_neigh->number)
643 nr_node->which++;
644 }
645
646
647
648
649
650
651 int nr_route_frame(struct sk_buff *skb, ax25_cb *ax25)
652 {
653 ax25_address *nr_src, *nr_dest;
654 struct nr_neigh *nr_neigh;
655 struct nr_node *nr_node;
656 struct device *dev;
657 unsigned char *dptr;
658
659 #ifdef CONFIG_FIREWALL
660
661 if(ax25 && call_in_firewall(PF_NETROM, skb, skb->data)!=FW_ACCEPT)
662 return 0;
663 if(!ax25 && call_out_firewall(PF_NETROM, skb, skb->data)!=FW_ACCEPT)
664 return 0;
665 #endif
666 nr_src = (ax25_address *)(skb->data + 0);
667 nr_dest = (ax25_address *)(skb->data + 7);
668
669 if (ax25 != NULL)
670 nr_add_node(nr_src, "", &ax25->dest_addr, ax25->digipeat, ax25->device, 0, nr_default.obs_count);
671
672 if ((dev = nr_dev_get(nr_dest)) != NULL)
673 return nr_rx_frame(skb, dev);
674
675 if (!nr_route_on && ax25 != NULL)
676 return 0;
677
678
679 if (--skb->data[14] == 0)
680 return 0;
681
682 for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next)
683 if (ax25cmp(nr_dest, &nr_node->callsign) == 0)
684 break;
685
686 if (nr_node == NULL || nr_node->which >= nr_node->count)
687 return 0;
688
689 for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next)
690 if (nr_neigh->number == nr_node->routes[nr_node->which].neighbour)
691 break;
692
693 if (nr_neigh == NULL)
694 return 0;
695
696 if ((dev = nr_dev_first()) == NULL)
697 return 0;
698
699 #ifdef CONFIG_FIREWALL
700 if(ax25 && call_fw_firewall(PF_NETROM, skb, skb->data)!=FW_ACCEPT)
701 return 0;
702 #endif
703
704 dptr = skb_push(skb, 1);
705 *dptr = AX25_P_NETROM;
706
707 ax25_send_frame(skb, (ax25_address *)dev->dev_addr, &nr_neigh->callsign, nr_neigh->digipeat, nr_neigh->dev);
708
709 return 1;
710 }
711
712 int nr_nodes_get_info(char *buffer, char **start, off_t offset,
713 int length, int dummy)
714 {
715 struct nr_node *nr_node;
716 int len = 0;
717 off_t pos = 0;
718 off_t begin = 0;
719 int i;
720
721 cli();
722
723 len += sprintf(buffer, "callsign mnemonic w n qual obs neigh qual obs neigh qual obs neigh\n");
724
725 for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next) {
726 len += sprintf(buffer + len, "%-9s %-7s %d %d",
727 ax2asc(&nr_node->callsign),
728 nr_node->mnemonic,
729 nr_node->which + 1,
730 nr_node->count);
731
732 for (i = 0; i < nr_node->count; i++) {
733 len += sprintf(buffer + len, " %3d %d %05d",
734 nr_node->routes[i].quality,
735 nr_node->routes[i].obs_count,
736 nr_node->routes[i].neighbour);
737 }
738
739 len += sprintf(buffer + len, "\n");
740
741 pos = begin + len;
742
743 if (pos < offset) {
744 len = 0;
745 begin = pos;
746 }
747
748 if (pos > offset + length)
749 break;
750 }
751
752 sti();
753
754 *start = buffer + (offset - begin);
755 len -= (offset - begin);
756
757 if (len > length) len = length;
758
759 return(len);
760 }
761
762 int nr_neigh_get_info(char *buffer, char **start, off_t offset,
763 int length, int dummy)
764 {
765 struct nr_neigh *nr_neigh;
766 int len = 0;
767 off_t pos = 0;
768 off_t begin = 0;
769
770 cli();
771
772 len += sprintf(buffer, "addr callsign dev qual lock count\n");
773
774 for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next) {
775 len += sprintf(buffer + len, "%05d %-9s %-4s %3d %d %3d\n",
776 nr_neigh->number,
777 ax2asc(&nr_neigh->callsign),
778 nr_neigh->dev ? nr_neigh->dev->name : "???",
779 nr_neigh->quality,
780 nr_neigh->locked,
781 nr_neigh->count);
782
783 pos = begin + len;
784
785 if (pos < offset) {
786 len = 0;
787 begin = pos;
788 }
789
790 if (pos > offset + length)
791 break;
792 }
793
794 sti();
795
796 *start = buffer + (offset - begin);
797 len -= (offset - begin);
798
799 if (len > length) len = length;
800
801 return(len);
802 }
803
804 #endif