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