~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/net/netrom/nr_route.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  *      NET/ROM release 007
  3  *
  4  *      This code REQUIRES 2.1.15 or higher/ NET3.038
  5  *
  6  *      This module:
  7  *              This module is free software; you can redistribute it and/or
  8  *              modify it under the terms of the GNU General Public License
  9  *              as published by the Free Software Foundation; either version
 10  *              2 of the License, or (at your option) any later version.
 11  *
 12  *      History
 13  *      NET/ROM 001     Jonathan(G4KLX) First attempt.
 14  *      NET/ROM 003     Jonathan(G4KLX) Use SIOCADDRT/SIOCDELRT ioctl values
 15  *                                      for NET/ROM routes.
 16  *                                      Use '*' for a blank mnemonic in /proc/net/nr_nodes.
 17  *                                      Change default quality for new neighbour when same
 18  *                                      as node callsign.
 19  *                      Alan Cox(GW4PTS) Added the firewall hooks.
 20  *      NET/ROM 006     Jonathan(G4KLX) Added the setting of digipeated neighbours.
 21  *                      Tomi(OH2BNS)    Routing quality and link failure changes.
 22  */
 23 
 24 #include <linux/errno.h>
 25 #include <linux/types.h>
 26 #include <linux/socket.h>
 27 #include <linux/in.h>
 28 #include <linux/kernel.h>
 29 #include <linux/sched.h>
 30 #include <linux/timer.h>
 31 #include <linux/string.h>
 32 #include <linux/sockios.h>
 33 #include <linux/net.h>
 34 #include <net/ax25.h>
 35 #include <linux/inet.h>
 36 #include <linux/netdevice.h>
 37 #include <net/arp.h>
 38 #include <linux/if_arp.h>
 39 #include <linux/skbuff.h>
 40 #include <net/sock.h>
 41 #include <asm/uaccess.h>
 42 #include <asm/system.h>
 43 #include <linux/fcntl.h>
 44 #include <linux/termios.h>      /* For TIOCINQ/OUTQ */
 45 #include <linux/mm.h>
 46 #include <linux/interrupt.h>
 47 #include <linux/notifier.h>
 48 #include <linux/netfilter.h>
 49 #include <linux/init.h>
 50 #include <net/netrom.h>
 51 
 52 static unsigned int nr_neigh_no = 1;
 53 
 54 static struct nr_node  *nr_node_list;
 55 static struct nr_neigh *nr_neigh_list;
 56 
 57 static void nr_remove_neigh(struct nr_neigh *);
 58 
 59 /*
 60  *      Add a new route to a node, and in the process add the node and the
 61  *      neighbour if it is new.
 62  */
 63 static int nr_add_node(ax25_address *nr, const char *mnemonic, ax25_address *ax25,
 64         ax25_digi *ax25_digi, struct net_device *dev, int quality, int obs_count)
 65 {
 66         struct nr_node  *nr_node;
 67         struct nr_neigh *nr_neigh;
 68         struct nr_route nr_route;
 69         unsigned long flags;
 70         int i, found;
 71 
 72         if (nr_dev_get(nr) != NULL)     /* Can't add routes to ourself */
 73                 return -EINVAL;
 74 
 75         for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next)
 76                 if (ax25cmp(nr, &nr_node->callsign) == 0)
 77                         break;
 78 
 79         for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next)
 80                 if (ax25cmp(ax25, &nr_neigh->callsign) == 0 && nr_neigh->dev == dev)
 81                         break;
 82 
 83         /*
 84          * The L2 link to a neighbour has failed in the past
 85          * and now a frame comes from this neighbour. We assume
 86          * it was a temporary trouble with the link and reset the
 87          * routes now (and not wait for a node broadcast).
 88          */
 89         if (nr_neigh != NULL && nr_neigh->failed != 0 && quality == 0) {
 90                 struct nr_node *node;
 91 
 92                 for (node = nr_node_list; node != NULL; node = node->next)
 93                         for (i = 0; i < node->count; i++)
 94                                 if (node->routes[i].neighbour == nr_neigh)
 95                                         if (i < node->which)
 96                                                 node->which = i;
 97         }
 98 
 99         if (nr_neigh != NULL)
100                 nr_neigh->failed = 0;
101 
102         if (quality == 0 && nr_neigh != NULL && nr_node != NULL)
103                 return 0;
104 
105         if (nr_neigh == NULL) {
106                 if ((nr_neigh = kmalloc(sizeof(*nr_neigh), GFP_ATOMIC)) == NULL)
107                         return -ENOMEM;
108 
109                 nr_neigh->callsign = *ax25;
110                 nr_neigh->digipeat = NULL;
111                 nr_neigh->ax25     = NULL;
112                 nr_neigh->dev      = dev;
113                 nr_neigh->quality  = sysctl_netrom_default_path_quality;
114                 nr_neigh->locked   = 0;
115                 nr_neigh->count    = 0;
116                 nr_neigh->number   = nr_neigh_no++;
117                 nr_neigh->failed   = 0;
118 
119                 if (ax25_digi != NULL && ax25_digi->ndigi > 0) {
120                         if ((nr_neigh->digipeat = kmalloc(sizeof(*ax25_digi), GFP_KERNEL)) == NULL) {
121                                 kfree(nr_neigh);
122                                 return -ENOMEM;
123                         }
124                         memcpy(nr_neigh->digipeat, ax25_digi, sizeof(ax25_digi));
125                 }
126 
127                 save_flags(flags);
128                 cli();
129 
130                 nr_neigh->next = nr_neigh_list;
131                 nr_neigh_list  = nr_neigh;
132 
133                 restore_flags(flags);
134         }
135 
136         if (quality != 0 && ax25cmp(nr, ax25) == 0 && !nr_neigh->locked)
137                 nr_neigh->quality = quality;
138 
139         if (nr_node == NULL) {
140                 if ((nr_node = kmalloc(sizeof(*nr_node), GFP_ATOMIC)) == NULL)
141                         return -ENOMEM;
142 
143                 nr_node->callsign = *nr;
144                 strcpy(nr_node->mnemonic, mnemonic);
145 
146                 nr_node->which = 0;
147                 nr_node->count = 1;
148 
149                 nr_node->routes[0].quality   = quality;
150                 nr_node->routes[0].obs_count = obs_count;
151                 nr_node->routes[0].neighbour = nr_neigh;
152 
153                 save_flags(flags);
154                 cli();
155 
156                 nr_node->next = nr_node_list;
157                 nr_node_list  = nr_node;
158 
159                 restore_flags(flags);
160 
161                 nr_neigh->count++;
162 
163                 return 0;
164         }
165 
166         if (quality != 0)
167                 strcpy(nr_node->mnemonic, mnemonic);
168 
169         for (found = 0, i = 0; i < nr_node->count; i++) {
170                 if (nr_node->routes[i].neighbour == nr_neigh) {
171                         nr_node->routes[i].quality   = quality;
172                         nr_node->routes[i].obs_count = obs_count;
173                         found = 1;
174                         break;
175                 }
176         }
177 
178         if (!found) {
179                 /* We have space at the bottom, slot it in */
180                 if (nr_node->count < 3) {
181                         nr_node->routes[2] = nr_node->routes[1];
182                         nr_node->routes[1] = nr_node->routes[0];
183 
184                         nr_node->routes[0].quality   = quality;
185                         nr_node->routes[0].obs_count = obs_count;
186                         nr_node->routes[0].neighbour = nr_neigh;
187 
188                         nr_node->which++;
189                         nr_node->count++;
190                         nr_neigh->count++;
191                 } else {
192                         /* It must be better than the worst */
193                         if (quality > nr_node->routes[2].quality) {
194                                 nr_node->routes[2].neighbour->count--;
195 
196                                 if (nr_node->routes[2].neighbour->count == 0 && !nr_node->routes[2].neighbour->locked)
197                                         nr_remove_neigh(nr_node->routes[2].neighbour);
198 
199                                 nr_node->routes[2].quality   = quality;
200                                 nr_node->routes[2].obs_count = obs_count;
201                                 nr_node->routes[2].neighbour = nr_neigh;
202 
203                                 nr_neigh->count++;
204                         }
205                 }
206         }
207 
208         /* Now re-sort the routes in quality order */
209         switch (nr_node->count) {
210                 case 3:
211                         if (nr_node->routes[1].quality > nr_node->routes[0].quality) {
212                                 switch (nr_node->which) {
213                                         case 0:  nr_node->which = 1; break;
214                                         case 1:  nr_node->which = 0; break;
215                                         default: break;
216                                 }
217                                 nr_route           = nr_node->routes[0];
218                                 nr_node->routes[0] = nr_node->routes[1];
219                                 nr_node->routes[1] = nr_route;
220                         }
221                         if (nr_node->routes[2].quality > nr_node->routes[1].quality) {
222                                 switch (nr_node->which) {
223                                         case 1:  nr_node->which = 2; break;
224                                         case 2:  nr_node->which = 1; break;
225                                         default: break;
226                                 }
227                                 nr_route           = nr_node->routes[1];
228                                 nr_node->routes[1] = nr_node->routes[2];
229                                 nr_node->routes[2] = nr_route;
230                         }
231                 case 2:
232                         if (nr_node->routes[1].quality > nr_node->routes[0].quality) {
233                                 switch (nr_node->which) {
234                                         case 0:  nr_node->which = 1; break;
235                                         case 1:  nr_node->which = 0; break;
236                                         default: break;
237                                 }
238                                 nr_route           = nr_node->routes[0];
239                                 nr_node->routes[0] = nr_node->routes[1];
240                                 nr_node->routes[1] = nr_route;
241                         }
242                 case 1:
243                         break;
244         }
245 
246         for (i = 0; i < nr_node->count; i++) {
247                 if (nr_node->routes[i].neighbour == nr_neigh) {
248                         if (i < nr_node->which)
249                                 nr_node->which = i;
250                         break;
251                 }
252         }
253 
254         return 0;
255 }
256 
257 static void nr_remove_node(struct nr_node *nr_node)
258 {
259         struct nr_node *s;
260         unsigned long flags;
261 
262         save_flags(flags);
263         cli();
264 
265         if ((s = nr_node_list) == nr_node) {
266                 nr_node_list = nr_node->next;
267                 restore_flags(flags);
268                 kfree(nr_node);
269                 return;
270         }
271 
272         while (s != NULL && s->next != NULL) {
273                 if (s->next == nr_node) {
274                         s->next = nr_node->next;
275                         restore_flags(flags);
276                         kfree(nr_node);
277                         return;
278                 }
279 
280                 s = s->next;
281         }
282 
283         restore_flags(flags);
284 }
285 
286 static void nr_remove_neigh(struct nr_neigh *nr_neigh)
287 {
288         struct nr_neigh *s;
289         unsigned long flags;
290         
291         save_flags(flags);
292         cli();
293 
294         if ((s = nr_neigh_list) == nr_neigh) {
295                 nr_neigh_list = nr_neigh->next;
296                 restore_flags(flags);
297                 if (nr_neigh->digipeat != NULL)
298                         kfree(nr_neigh->digipeat);
299                 kfree(nr_neigh);
300                 return;
301         }
302 
303         while (s != NULL && s->next != NULL) {
304                 if (s->next == nr_neigh) {
305                         s->next = nr_neigh->next;
306                         restore_flags(flags);
307                         if (nr_neigh->digipeat != NULL)
308                                 kfree(nr_neigh->digipeat);
309                         kfree(nr_neigh);
310                         return;
311                 }
312 
313                 s = s->next;
314         }
315 
316         restore_flags(flags);
317 }
318 
319 /*
320  *      "Delete" a node. Strictly speaking remove a route to a node. The node
321  *      is only deleted if no routes are left to it.
322  */
323 static int nr_del_node(ax25_address *callsign, ax25_address *neighbour, struct net_device *dev)
324 {
325         struct nr_node  *nr_node;
326         struct nr_neigh *nr_neigh;
327         int i;
328 
329         for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next)
330                 if (ax25cmp(callsign, &nr_node->callsign) == 0)
331                         break;
332 
333         if (nr_node == NULL) return -EINVAL;
334 
335         for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next)
336                 if (ax25cmp(neighbour, &nr_neigh->callsign) == 0 && nr_neigh->dev == dev)
337                         break;
338 
339         if (nr_neigh == NULL) return -EINVAL;
340 
341         for (i = 0; i < nr_node->count; i++) {
342                 if (nr_node->routes[i].neighbour == nr_neigh) {
343                         nr_neigh->count--;
344 
345                         if (nr_neigh->count == 0 && !nr_neigh->locked)
346                                 nr_remove_neigh(nr_neigh);
347 
348                         nr_node->count--;
349 
350                         if (nr_node->count == 0) {
351                                 nr_remove_node(nr_node);
352                         } else {
353                                 switch (i) {
354                                         case 0:
355                                                 nr_node->routes[0] = nr_node->routes[1];
356                                         case 1:
357                                                 nr_node->routes[1] = nr_node->routes[2];
358                                         case 2:
359                                                 break;
360                                 }
361                         }
362 
363                         return 0;
364                 }
365         }
366 
367         return -EINVAL;
368 }
369 
370 /*
371  *      Lock a neighbour with a quality.
372  */
373 static int nr_add_neigh(ax25_address *callsign, ax25_digi *ax25_digi, struct net_device *dev, unsigned int quality)
374 {
375         struct nr_neigh *nr_neigh;
376         unsigned long flags;
377 
378         for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next) {
379                 if (ax25cmp(callsign, &nr_neigh->callsign) == 0 && nr_neigh->dev == dev) {
380                         nr_neigh->quality = quality;
381                         nr_neigh->locked  = 1;
382                         return 0;
383                 }
384         }
385 
386         if ((nr_neigh = kmalloc(sizeof(*nr_neigh), GFP_ATOMIC)) == NULL)
387                 return -ENOMEM;
388 
389         nr_neigh->callsign = *callsign;
390         nr_neigh->digipeat = NULL;
391         nr_neigh->ax25     = NULL;
392         nr_neigh->dev      = dev;
393         nr_neigh->quality  = quality;
394         nr_neigh->locked   = 1;
395         nr_neigh->count    = 0;
396         nr_neigh->number   = nr_neigh_no++;
397         nr_neigh->failed   = 0;
398 
399         if (ax25_digi != NULL && ax25_digi->ndigi > 0) {
400                 if ((nr_neigh->digipeat = kmalloc(sizeof(*ax25_digi), GFP_KERNEL)) == NULL) {
401                         kfree(nr_neigh);
402                         return -ENOMEM;
403                 }
404                 memcpy(nr_neigh->digipeat, ax25_digi, sizeof(ax25_digi));
405         }
406 
407         save_flags(flags);
408         cli();
409 
410         nr_neigh->next = nr_neigh_list;
411         nr_neigh_list  = nr_neigh;
412 
413         restore_flags(flags);
414 
415         return 0;       
416 }
417 
418 /*
419  *      "Delete" a neighbour. The neighbour is only removed if the number
420  *      of nodes that may use it is zero.
421  */
422 static int nr_del_neigh(ax25_address *callsign, struct net_device *dev, unsigned int quality)
423 {
424         struct nr_neigh *nr_neigh;
425 
426         for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next)
427                 if (ax25cmp(callsign, &nr_neigh->callsign) == 0 && nr_neigh->dev == dev)
428                         break;
429 
430         if (nr_neigh == NULL) return -EINVAL;
431 
432         nr_neigh->quality = quality;
433         nr_neigh->locked  = 0;
434 
435         if (nr_neigh->count == 0)
436                 nr_remove_neigh(nr_neigh);
437 
438         return 0;
439 }
440 
441 /*
442  *      Decrement the obsolescence count by one. If a route is reduced to a
443  *      count of zero, remove it. Also remove any unlocked neighbours with
444  *      zero nodes routing via it.
445  */
446 static int nr_dec_obs(void)
447 {
448         struct nr_neigh *nr_neigh;
449         struct nr_node  *s, *nr_node;
450         int i;
451 
452         nr_node = nr_node_list;
453 
454         while (nr_node != NULL) {
455                 s       = nr_node;
456                 nr_node = nr_node->next;
457 
458                 for (i = 0; i < s->count; i++) {
459                         switch (s->routes[i].obs_count) {
460 
461                         case 0:         /* A locked entry */
462                                 break;
463 
464                         case 1:         /* From 1 -> 0 */
465                                 nr_neigh = s->routes[i].neighbour;
466 
467                                 nr_neigh->count--;
468 
469                                 if (nr_neigh->count == 0 && !nr_neigh->locked)
470                                         nr_remove_neigh(nr_neigh);
471 
472                                 s->count--;
473 
474                                 switch (i) {
475                                         case 0:
476                                                 s->routes[0] = s->routes[1];
477                                         case 1:
478                                                 s->routes[1] = s->routes[2];
479                                         case 2:
480                                                 break;
481                                 }
482                                 break;
483 
484                         default:
485                                 s->routes[i].obs_count--;
486                                 break;
487 
488                         }
489                 }
490 
491                 if (s->count <= 0)
492                         nr_remove_node(s);
493         }
494 
495         return 0;
496 }
497 
498 /*
499  *      A device has been removed. Remove its routes and neighbours.
500  */
501 void nr_rt_device_down(struct net_device *dev)
502 {
503         struct nr_neigh *s, *nr_neigh = nr_neigh_list;
504         struct nr_node  *t, *nr_node;
505         int i;
506 
507         while (nr_neigh != NULL) {
508                 s        = nr_neigh;
509                 nr_neigh = nr_neigh->next;
510 
511                 if (s->dev == dev) {
512                         nr_node = nr_node_list;
513 
514                         while (nr_node != NULL) {
515                                 t       = nr_node;
516                                 nr_node = nr_node->next;
517 
518                                 for (i = 0; i < t->count; i++) {
519                                         if (t->routes[i].neighbour == s) {
520                                                 t->count--;
521 
522                                                 switch (i) {
523                                                         case 0:
524                                                                 t->routes[0] = t->routes[1];
525                                                         case 1:
526                                                                 t->routes[1] = t->routes[2];
527                                                         case 2:
528                                                                 break;
529                                                 }
530                                         }
531                                 }
532 
533                                 if (t->count <= 0)
534                                         nr_remove_node(t);
535                         }
536 
537                         nr_remove_neigh(s);
538                 }
539         }
540 }
541 
542 /*
543  *      Check that the device given is a valid AX.25 interface that is "up".
544  *      Or a valid ethernet interface with an AX.25 callsign binding.
545  */
546 static struct net_device *nr_ax25_dev_get(char *devname)
547 {
548         struct net_device *dev;
549 
550         if ((dev = dev_get_by_name(devname)) == NULL)
551                 return NULL;
552 
553         if ((dev->flags & IFF_UP) && dev->type == ARPHRD_AX25)
554                 return dev;
555 
556         dev_put(dev);
557         return NULL;
558 }
559 
560 /*
561  *      Find the first active NET/ROM device, usually "nr0".
562  */
563 struct net_device *nr_dev_first(void)
564 {
565         struct net_device *dev, *first = NULL;
566 
567         read_lock(&dev_base_lock);
568         for (dev = dev_base; dev != NULL; dev = dev->next) {
569                 if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM)
570                         if (first == NULL || strncmp(dev->name, first->name, 3) < 0)
571                                 first = dev;
572         }
573         read_unlock(&dev_base_lock);
574 
575         return first;
576 }
577 
578 /*
579  *      Find the NET/ROM device for the given callsign.
580  */
581 struct net_device *nr_dev_get(ax25_address *addr)
582 {
583         struct net_device *dev;
584 
585         read_lock(&dev_base_lock);
586         for (dev = dev_base; dev != NULL; dev = dev->next) {
587                 if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM && ax25cmp(addr, (ax25_address *)dev->dev_addr) == 0) {
588                         dev_hold(dev);
589                         goto out;
590                 }
591         }
592 out:
593         read_unlock(&dev_base_lock);
594         return dev;
595 }
596 
597 static ax25_digi *nr_call_to_digi(int ndigis, ax25_address *digipeaters)
598 {
599         static ax25_digi ax25_digi;
600         int i;
601 
602         if (ndigis == 0)
603                 return NULL;
604 
605         for (i = 0; i < ndigis; i++) {
606                 ax25_digi.calls[i]    = digipeaters[i];
607                 ax25_digi.repeated[i] = 0;
608         }
609 
610         ax25_digi.ndigi      = ndigis;
611         ax25_digi.lastrepeat = -1;
612 
613         return &ax25_digi;
614 }
615 
616 /*
617  *      Handle the ioctls that control the routing functions.
618  */
619 int nr_rt_ioctl(unsigned int cmd, void *arg)
620 {
621         struct nr_route_struct nr_route;
622         struct net_device *dev;
623 
624         switch (cmd) {
625 
626                 case SIOCADDRT:
627                         if (copy_from_user(&nr_route, arg, sizeof(struct nr_route_struct)))
628                                 return -EFAULT;
629                         if ((dev = nr_ax25_dev_get(nr_route.device)) == NULL)
630                                 return -EINVAL;
631                         if (nr_route.ndigis < 0 || nr_route.ndigis > AX25_MAX_DIGIS)
632                                 return -EINVAL;
633                         switch (nr_route.type) {
634                                 case NETROM_NODE:
635                                         return nr_add_node(&nr_route.callsign,
636                                                 nr_route.mnemonic,
637                                                 &nr_route.neighbour,
638                                                 nr_call_to_digi(nr_route.ndigis, nr_route.digipeaters),
639                                                 dev, nr_route.quality,
640                                                 nr_route.obs_count);
641                                 case NETROM_NEIGH:
642                                         return nr_add_neigh(&nr_route.callsign,
643                                                 nr_call_to_digi(nr_route.ndigis, nr_route.digipeaters),
644                                                 dev, nr_route.quality);
645                                 default:
646                                         return -EINVAL;
647                         }
648 
649                 case SIOCDELRT:
650                         if (copy_from_user(&nr_route, arg, sizeof(struct nr_route_struct)))
651                                 return -EFAULT;
652                         if ((dev = nr_ax25_dev_get(nr_route.device)) == NULL)
653                                 return -EINVAL;
654                         switch (nr_route.type) {
655                                 case NETROM_NODE:
656                                         return nr_del_node(&nr_route.callsign,
657                                                 &nr_route.neighbour, dev);
658                                 case NETROM_NEIGH:
659                                         return nr_del_neigh(&nr_route.callsign,
660                                                 dev, nr_route.quality);
661                                 default:
662                                         return -EINVAL;
663                         }
664 
665                 case SIOCNRDECOBS:
666                         return nr_dec_obs();
667 
668                 default:
669                         return -EINVAL;
670         }
671 
672         return 0;
673 }
674 
675 /*
676  *      A level 2 link has timed out, therefore it appears to be a poor link,
677  *      then don't use that neighbour until it is reset.
678  */
679 void nr_link_failed(ax25_cb *ax25, int reason)
680 {
681         struct nr_neigh *nr_neigh;
682         struct nr_node  *nr_node;
683 
684         for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next)
685                 if (nr_neigh->ax25 == ax25)
686                         break;
687 
688         if (nr_neigh == NULL) return;
689 
690         nr_neigh->ax25 = NULL;
691 
692         if (++nr_neigh->failed < sysctl_netrom_link_fails_count) return;
693 
694         for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next)
695                 if (nr_node->which < nr_node->count && nr_node->routes[nr_node->which].neighbour == nr_neigh)
696                         nr_node->which++;
697 }
698 
699 /*
700  *      Route a frame to an appropriate AX.25 connection. A NULL ax25_cb
701  *      indicates an internally generated frame.
702  */
703 int nr_route_frame(struct sk_buff *skb, ax25_cb *ax25)
704 {
705         ax25_address *nr_src, *nr_dest;
706         struct nr_neigh *nr_neigh;
707         struct nr_node  *nr_node;
708         struct net_device *dev;
709         unsigned char *dptr;
710 
711 
712         nr_src  = (ax25_address *)(skb->data + 0);
713         nr_dest = (ax25_address *)(skb->data + 7);
714 
715         if (ax25 != NULL)
716                 nr_add_node(nr_src, "", &ax25->dest_addr, ax25->digipeat,
717                             ax25->ax25_dev->dev, 0, sysctl_netrom_obsolescence_count_initialiser);
718 
719         if ((dev = nr_dev_get(nr_dest)) != NULL) {      /* Its for me */
720                 if (ax25 == NULL)                       /* Its from me */
721                         return nr_loopback_queue(skb);
722                 else
723                         return nr_rx_frame(skb, dev);
724         }
725 
726         if (!sysctl_netrom_routing_control && ax25 != NULL)
727                 return 0;
728 
729         /* Its Time-To-Live has expired */
730         if (--skb->data[14] == 0)
731                 return 0;
732 
733         for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next)
734                 if (ax25cmp(nr_dest, &nr_node->callsign) == 0)
735                         break;
736 
737         if (nr_node == NULL || nr_node->which >= nr_node->count)
738                 return 0;
739 
740         nr_neigh = nr_node->routes[nr_node->which].neighbour;
741 
742         if ((dev = nr_dev_first()) == NULL)
743                 return 0;
744 
745         dptr  = skb_push(skb, 1);
746         *dptr = AX25_P_NETROM;
747 
748         nr_neigh->ax25 = ax25_send_frame(skb, 256, (ax25_address *)dev->dev_addr, &nr_neigh->callsign, nr_neigh->digipeat, nr_neigh->dev);
749 
750         return (nr_neigh->ax25 != NULL);
751 }
752 
753 int nr_nodes_get_info(char *buffer, char **start, off_t offset, int length)
754 {
755         struct nr_node *nr_node;
756         int len     = 0;
757         off_t pos   = 0;
758         off_t begin = 0;
759         int i;
760 
761         cli();
762 
763         len += sprintf(buffer, "callsign  mnemonic w n qual obs neigh qual obs neigh qual obs neigh\n");
764 
765         for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next) {
766                 len += sprintf(buffer + len, "%-9s %-7s  %d %d",
767                         ax2asc(&nr_node->callsign),
768                         (nr_node->mnemonic[0] == '\0') ? "*" : nr_node->mnemonic,
769                         nr_node->which + 1,
770                         nr_node->count);                        
771 
772                 for (i = 0; i < nr_node->count; i++) {
773                         len += sprintf(buffer + len, "  %3d   %d %05d",
774                                 nr_node->routes[i].quality,
775                                 nr_node->routes[i].obs_count,
776                                 nr_node->routes[i].neighbour->number);
777                 }
778 
779                 len += sprintf(buffer + len, "\n");
780 
781                 pos = begin + len;
782 
783                 if (pos < offset) {
784                         len   = 0;
785                         begin = pos;
786                 }
787 
788                 if (pos > offset + length)
789                         break;
790         }
791 
792         sti();
793 
794         *start = buffer + (offset - begin);
795         len   -= (offset - begin);
796 
797         if (len > length) len = length;
798 
799         return len;
800 } 
801 
802 int nr_neigh_get_info(char *buffer, char **start, off_t offset, int length)
803 {
804         struct nr_neigh *nr_neigh;
805         int len     = 0;
806         off_t pos   = 0;
807         off_t begin = 0;
808         int i;
809 
810         cli();
811 
812         len += sprintf(buffer, "addr  callsign  dev  qual lock count failed digipeaters\n");
813 
814         for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next) {
815                 len += sprintf(buffer + len, "%05d %-9s %-4s  %3d    %d   %3d    %3d",
816                         nr_neigh->number,
817                         ax2asc(&nr_neigh->callsign),
818                         nr_neigh->dev ? nr_neigh->dev->name : "???",
819                         nr_neigh->quality,
820                         nr_neigh->locked,
821                         nr_neigh->count,
822                         nr_neigh->failed);
823 
824                 if (nr_neigh->digipeat != NULL) {
825                         for (i = 0; i < nr_neigh->digipeat->ndigi; i++)
826                                 len += sprintf(buffer + len, " %s", ax2asc(&nr_neigh->digipeat->calls[i]));
827                 }
828 
829                 len += sprintf(buffer + len, "\n");
830 
831                 pos = begin + len;
832 
833                 if (pos < offset) {
834                         len   = 0;
835                         begin = pos;
836                 }
837 
838                 if (pos > offset + length)
839                         break;
840         }
841 
842         sti();
843 
844         *start = buffer + (offset - begin);
845         len   -= (offset - begin);
846 
847         if (len > length) len = length;
848 
849         return len;
850 } 
851 
852 /*
853  *      Free all memory associated with the nodes and routes lists.
854  */
855 void __exit nr_rt_free(void)
856 {
857         struct nr_neigh *s, *nr_neigh = nr_neigh_list;
858         struct nr_node  *t, *nr_node  = nr_node_list;
859 
860         while (nr_node != NULL) {
861                 t       = nr_node;
862                 nr_node = nr_node->next;
863 
864                 nr_remove_node(t);
865         }
866 
867         while (nr_neigh != NULL) {
868                 s        = nr_neigh;
869                 nr_neigh = nr_neigh->next;
870 
871                 nr_remove_neigh(s);
872         }
873 }
874 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.