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