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

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

Version: ~ [ linux-5.16 ] ~ [ linux-5.15.13 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.90 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.170 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.224 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.261 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.296 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.298 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * This program is free software; you can redistribute it and/or modify
  3  * it under the terms of the GNU General Public License as published by
  4  * the Free Software Foundation; either version 2 of the License, or
  5  * (at your option) any later version.
  6  *
  7  * Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
  8  * Copyright Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
  9  * Copyright Tomi Manninen OH2BNS (oh2bns@sral.fi)
 10  */
 11 #include <linux/errno.h>
 12 #include <linux/types.h>
 13 #include <linux/socket.h>
 14 #include <linux/in.h>
 15 #include <linux/kernel.h>
 16 #include <linux/timer.h>
 17 #include <linux/string.h>
 18 #include <linux/sockios.h>
 19 #include <linux/net.h>
 20 #include <net/ax25.h>
 21 #include <linux/inet.h>
 22 #include <linux/netdevice.h>
 23 #include <net/arp.h>
 24 #include <linux/if_arp.h>
 25 #include <linux/skbuff.h>
 26 #include <net/sock.h>
 27 #include <asm/uaccess.h>
 28 #include <asm/system.h>
 29 #include <linux/fcntl.h>
 30 #include <linux/termios.h>      /* For TIOCINQ/OUTQ */
 31 #include <linux/mm.h>
 32 #include <linux/interrupt.h>
 33 #include <linux/notifier.h>
 34 #include <linux/netfilter.h>
 35 #include <linux/init.h>
 36 #include <linux/spinlock.h>
 37 #include <net/netrom.h>
 38 #include <linux/seq_file.h>
 39 
 40 static unsigned int nr_neigh_no = 1;
 41 
 42 static HLIST_HEAD(nr_node_list);
 43 static DEFINE_SPINLOCK(nr_node_list_lock);
 44 static HLIST_HEAD(nr_neigh_list);
 45 static DEFINE_SPINLOCK(nr_neigh_list_lock);
 46 
 47 static struct nr_node *nr_node_get(ax25_address *callsign)
 48 {
 49         struct nr_node *found = NULL;
 50         struct nr_node *nr_node;
 51         struct hlist_node *node;
 52 
 53         spin_lock_bh(&nr_node_list_lock);
 54         nr_node_for_each(nr_node, node, &nr_node_list)
 55                 if (ax25cmp(callsign, &nr_node->callsign) == 0) {
 56                         nr_node_hold(nr_node);
 57                         found = nr_node;
 58                         break;
 59                 }
 60         spin_unlock_bh(&nr_node_list_lock);
 61         return found;
 62 }
 63 
 64 static struct nr_neigh *nr_neigh_get_dev(ax25_address *callsign,
 65                                          struct net_device *dev)
 66 {
 67         struct nr_neigh *found = NULL;
 68         struct nr_neigh *nr_neigh;
 69         struct hlist_node *node;
 70 
 71         spin_lock_bh(&nr_neigh_list_lock);
 72         nr_neigh_for_each(nr_neigh, node, &nr_neigh_list)
 73                 if (ax25cmp(callsign, &nr_neigh->callsign) == 0 &&
 74                     nr_neigh->dev == dev) {
 75                         nr_neigh_hold(nr_neigh);
 76                         found = nr_neigh;
 77                         break;
 78                 }
 79         spin_unlock_bh(&nr_neigh_list_lock);
 80         return found;
 81 }
 82 
 83 static void nr_remove_neigh(struct nr_neigh *);
 84 
 85 /*
 86  *      Add a new route to a node, and in the process add the node and the
 87  *      neighbour if it is new.
 88  */
 89 static int __must_check nr_add_node(ax25_address *nr, const char *mnemonic,
 90         ax25_address *ax25, ax25_digi *ax25_digi, struct net_device *dev,
 91         int quality, int obs_count)
 92 {
 93         struct nr_node  *nr_node;
 94         struct nr_neigh *nr_neigh;
 95         struct nr_route nr_route;
 96         int i, found;
 97         struct net_device *odev;
 98 
 99         if ((odev=nr_dev_get(nr)) != NULL) {    /* Can't add routes to ourself */
100                 dev_put(odev);
101                 return -EINVAL;
102         }
103 
104         nr_node = nr_node_get(nr);
105 
106         nr_neigh = nr_neigh_get_dev(ax25, dev);
107 
108         /*
109          * The L2 link to a neighbour has failed in the past
110          * and now a frame comes from this neighbour. We assume
111          * it was a temporary trouble with the link and reset the
112          * routes now (and not wait for a node broadcast).
113          */
114         if (nr_neigh != NULL && nr_neigh->failed != 0 && quality == 0) {
115                 struct nr_node *nr_nodet;
116                 struct hlist_node *node;
117 
118                 spin_lock_bh(&nr_node_list_lock);
119                 nr_node_for_each(nr_nodet, node, &nr_node_list) {
120                         nr_node_lock(nr_nodet);
121                         for (i = 0; i < nr_nodet->count; i++)
122                                 if (nr_nodet->routes[i].neighbour == nr_neigh)
123                                         if (i < nr_nodet->which)
124                                                 nr_nodet->which = i;
125                         nr_node_unlock(nr_nodet);
126                 }
127                 spin_unlock_bh(&nr_node_list_lock);
128         }
129 
130         if (nr_neigh != NULL)
131                 nr_neigh->failed = 0;
132 
133         if (quality == 0 && nr_neigh != NULL && nr_node != NULL) {
134                 nr_neigh_put(nr_neigh);
135                 nr_node_put(nr_node);
136                 return 0;
137         }
138 
139         if (nr_neigh == NULL) {
140                 if ((nr_neigh = kmalloc(sizeof(*nr_neigh), GFP_ATOMIC)) == NULL) {
141                         if (nr_node)
142                                 nr_node_put(nr_node);
143                         return -ENOMEM;
144                 }
145 
146                 nr_neigh->callsign = *ax25;
147                 nr_neigh->digipeat = NULL;
148                 nr_neigh->ax25     = NULL;
149                 nr_neigh->dev      = dev;
150                 nr_neigh->quality  = sysctl_netrom_default_path_quality;
151                 nr_neigh->locked   = 0;
152                 nr_neigh->count    = 0;
153                 nr_neigh->number   = nr_neigh_no++;
154                 nr_neigh->failed   = 0;
155                 atomic_set(&nr_neigh->refcount, 1);
156 
157                 if (ax25_digi != NULL && ax25_digi->ndigi > 0) {
158                         nr_neigh->digipeat = kmemdup(ax25_digi,
159                                                      sizeof(*ax25_digi),
160                                                      GFP_KERNEL);
161                         if (nr_neigh->digipeat == NULL) {
162                                 kfree(nr_neigh);
163                                 if (nr_node)
164                                         nr_node_put(nr_node);
165                                 return -ENOMEM;
166                         }
167                 }
168 
169                 spin_lock_bh(&nr_neigh_list_lock);
170                 hlist_add_head(&nr_neigh->neigh_node, &nr_neigh_list);
171                 nr_neigh_hold(nr_neigh);
172                 spin_unlock_bh(&nr_neigh_list_lock);
173         }
174 
175         if (quality != 0 && ax25cmp(nr, ax25) == 0 && !nr_neigh->locked)
176                 nr_neigh->quality = quality;
177 
178         if (nr_node == NULL) {
179                 if ((nr_node = kmalloc(sizeof(*nr_node), GFP_ATOMIC)) == NULL) {
180                         if (nr_neigh)
181                                 nr_neigh_put(nr_neigh);
182                         return -ENOMEM;
183                 }
184 
185                 nr_node->callsign = *nr;
186                 strcpy(nr_node->mnemonic, mnemonic);
187 
188                 nr_node->which = 0;
189                 nr_node->count = 1;
190                 atomic_set(&nr_node->refcount, 1);
191                 spin_lock_init(&nr_node->node_lock);
192 
193                 nr_node->routes[0].quality   = quality;
194                 nr_node->routes[0].obs_count = obs_count;
195                 nr_node->routes[0].neighbour = nr_neigh;
196 
197                 nr_neigh_hold(nr_neigh);
198                 nr_neigh->count++;
199 
200                 spin_lock_bh(&nr_node_list_lock);
201                 hlist_add_head(&nr_node->node_node, &nr_node_list);
202                 /* refcount initialized at 1 */
203                 spin_unlock_bh(&nr_node_list_lock);
204 
205                 return 0;
206         }
207         nr_node_lock(nr_node);
208 
209         if (quality != 0)
210                 strcpy(nr_node->mnemonic, mnemonic);
211 
212         for (found = 0, i = 0; i < nr_node->count; i++) {
213                 if (nr_node->routes[i].neighbour == nr_neigh) {
214                         nr_node->routes[i].quality   = quality;
215                         nr_node->routes[i].obs_count = obs_count;
216                         found = 1;
217                         break;
218                 }
219         }
220 
221         if (!found) {
222                 /* We have space at the bottom, slot it in */
223                 if (nr_node->count < 3) {
224                         nr_node->routes[2] = nr_node->routes[1];
225                         nr_node->routes[1] = nr_node->routes[0];
226 
227                         nr_node->routes[0].quality   = quality;
228                         nr_node->routes[0].obs_count = obs_count;
229                         nr_node->routes[0].neighbour = nr_neigh;
230 
231                         nr_node->which++;
232                         nr_node->count++;
233                         nr_neigh_hold(nr_neigh);
234                         nr_neigh->count++;
235                 } else {
236                         /* It must be better than the worst */
237                         if (quality > nr_node->routes[2].quality) {
238                                 nr_node->routes[2].neighbour->count--;
239                                 nr_neigh_put(nr_node->routes[2].neighbour);
240 
241                                 if (nr_node->routes[2].neighbour->count == 0 && !nr_node->routes[2].neighbour->locked)
242                                         nr_remove_neigh(nr_node->routes[2].neighbour);
243 
244                                 nr_node->routes[2].quality   = quality;
245                                 nr_node->routes[2].obs_count = obs_count;
246                                 nr_node->routes[2].neighbour = nr_neigh;
247 
248                                 nr_neigh_hold(nr_neigh);
249                                 nr_neigh->count++;
250                         }
251                 }
252         }
253 
254         /* Now re-sort the routes in quality order */
255         switch (nr_node->count) {
256         case 3:
257                 if (nr_node->routes[1].quality > nr_node->routes[0].quality) {
258                         switch (nr_node->which) {
259                                 case 0:  nr_node->which = 1; break;
260                                 case 1:  nr_node->which = 0; break;
261                                 default: break;
262                         }
263                         nr_route           = nr_node->routes[0];
264                         nr_node->routes[0] = nr_node->routes[1];
265                         nr_node->routes[1] = nr_route;
266                 }
267                 if (nr_node->routes[2].quality > nr_node->routes[1].quality) {
268                         switch (nr_node->which) {
269                         case 1:  nr_node->which = 2;
270                                 break;
271 
272                         case 2:  nr_node->which = 1;
273                                 break;
274 
275                         default:
276                                 break;
277                         }
278                         nr_route           = nr_node->routes[1];
279                         nr_node->routes[1] = nr_node->routes[2];
280                         nr_node->routes[2] = nr_route;
281                 }
282         case 2:
283                 if (nr_node->routes[1].quality > nr_node->routes[0].quality) {
284                         switch (nr_node->which) {
285                         case 0:  nr_node->which = 1;
286                                 break;
287 
288                         case 1:  nr_node->which = 0;
289                                 break;
290 
291                         default: break;
292                         }
293                         nr_route           = nr_node->routes[0];
294                         nr_node->routes[0] = nr_node->routes[1];
295                         nr_node->routes[1] = nr_route;
296                         }
297         case 1:
298                 break;
299         }
300 
301         for (i = 0; i < nr_node->count; i++) {
302                 if (nr_node->routes[i].neighbour == nr_neigh) {
303                         if (i < nr_node->which)
304                                 nr_node->which = i;
305                         break;
306                 }
307         }
308 
309         nr_neigh_put(nr_neigh);
310         nr_node_unlock(nr_node);
311         nr_node_put(nr_node);
312         return 0;
313 }
314 
315 static inline void __nr_remove_node(struct nr_node *nr_node)
316 {
317         hlist_del_init(&nr_node->node_node);
318         nr_node_put(nr_node);
319 }
320 
321 #define nr_remove_node_locked(__node) \
322         __nr_remove_node(__node)
323 
324 static void nr_remove_node(struct nr_node *nr_node)
325 {
326         spin_lock_bh(&nr_node_list_lock);
327         __nr_remove_node(nr_node);
328         spin_unlock_bh(&nr_node_list_lock);
329 }
330 
331 static inline void __nr_remove_neigh(struct nr_neigh *nr_neigh)
332 {
333         hlist_del_init(&nr_neigh->neigh_node);
334         nr_neigh_put(nr_neigh);
335 }
336 
337 #define nr_remove_neigh_locked(__neigh) \
338         __nr_remove_neigh(__neigh)
339 
340 static void nr_remove_neigh(struct nr_neigh *nr_neigh)
341 {
342         spin_lock_bh(&nr_neigh_list_lock);
343         __nr_remove_neigh(nr_neigh);
344         spin_unlock_bh(&nr_neigh_list_lock);
345 }
346 
347 /*
348  *      "Delete" a node. Strictly speaking remove a route to a node. The node
349  *      is only deleted if no routes are left to it.
350  */
351 static int nr_del_node(ax25_address *callsign, ax25_address *neighbour, struct net_device *dev)
352 {
353         struct nr_node  *nr_node;
354         struct nr_neigh *nr_neigh;
355         int i;
356 
357         nr_node = nr_node_get(callsign);
358 
359         if (nr_node == NULL)
360                 return -EINVAL;
361 
362         nr_neigh = nr_neigh_get_dev(neighbour, dev);
363 
364         if (nr_neigh == NULL) {
365                 nr_node_put(nr_node);
366                 return -EINVAL;
367         }
368 
369         nr_node_lock(nr_node);
370         for (i = 0; i < nr_node->count; i++) {
371                 if (nr_node->routes[i].neighbour == nr_neigh) {
372                         nr_neigh->count--;
373                         nr_neigh_put(nr_neigh);
374 
375                         if (nr_neigh->count == 0 && !nr_neigh->locked)
376                                 nr_remove_neigh(nr_neigh);
377                         nr_neigh_put(nr_neigh);
378 
379                         nr_node->count--;
380 
381                         if (nr_node->count == 0) {
382                                 nr_remove_node(nr_node);
383                         } else {
384                                 switch (i) {
385                                 case 0:
386                                         nr_node->routes[0] = nr_node->routes[1];
387                                 case 1:
388                                         nr_node->routes[1] = nr_node->routes[2];
389                                 case 2:
390                                         break;
391                                 }
392                                 nr_node_put(nr_node);
393                         }
394                         nr_node_unlock(nr_node);
395 
396                         return 0;
397                 }
398         }
399         nr_neigh_put(nr_neigh);
400         nr_node_unlock(nr_node);
401         nr_node_put(nr_node);
402 
403         return -EINVAL;
404 }
405 
406 /*
407  *      Lock a neighbour with a quality.
408  */
409 static int __must_check nr_add_neigh(ax25_address *callsign,
410         ax25_digi *ax25_digi, struct net_device *dev, unsigned int quality)
411 {
412         struct nr_neigh *nr_neigh;
413 
414         nr_neigh = nr_neigh_get_dev(callsign, dev);
415         if (nr_neigh) {
416                 nr_neigh->quality = quality;
417                 nr_neigh->locked  = 1;
418                 nr_neigh_put(nr_neigh);
419                 return 0;
420         }
421 
422         if ((nr_neigh = kmalloc(sizeof(*nr_neigh), GFP_ATOMIC)) == NULL)
423                 return -ENOMEM;
424 
425         nr_neigh->callsign = *callsign;
426         nr_neigh->digipeat = NULL;
427         nr_neigh->ax25     = NULL;
428         nr_neigh->dev      = dev;
429         nr_neigh->quality  = quality;
430         nr_neigh->locked   = 1;
431         nr_neigh->count    = 0;
432         nr_neigh->number   = nr_neigh_no++;
433         nr_neigh->failed   = 0;
434         atomic_set(&nr_neigh->refcount, 1);
435 
436         if (ax25_digi != NULL && ax25_digi->ndigi > 0) {
437                 nr_neigh->digipeat = kmemdup(ax25_digi, sizeof(*ax25_digi),
438                                              GFP_KERNEL);
439                 if (nr_neigh->digipeat == NULL) {
440                         kfree(nr_neigh);
441                         return -ENOMEM;
442                 }
443         }
444 
445         spin_lock_bh(&nr_neigh_list_lock);
446         hlist_add_head(&nr_neigh->neigh_node, &nr_neigh_list);
447         /* refcount is initialized at 1 */
448         spin_unlock_bh(&nr_neigh_list_lock);
449 
450         return 0;
451 }
452 
453 /*
454  *      "Delete" a neighbour. The neighbour is only removed if the number
455  *      of nodes that may use it is zero.
456  */
457 static int nr_del_neigh(ax25_address *callsign, struct net_device *dev, unsigned int quality)
458 {
459         struct nr_neigh *nr_neigh;
460 
461         nr_neigh = nr_neigh_get_dev(callsign, dev);
462 
463         if (nr_neigh == NULL) return -EINVAL;
464 
465         nr_neigh->quality = quality;
466         nr_neigh->locked  = 0;
467 
468         if (nr_neigh->count == 0)
469                 nr_remove_neigh(nr_neigh);
470         nr_neigh_put(nr_neigh);
471 
472         return 0;
473 }
474 
475 /*
476  *      Decrement the obsolescence count by one. If a route is reduced to a
477  *      count of zero, remove it. Also remove any unlocked neighbours with
478  *      zero nodes routing via it.
479  */
480 static int nr_dec_obs(void)
481 {
482         struct nr_neigh *nr_neigh;
483         struct nr_node  *s;
484         struct hlist_node *node, *nodet;
485         int i;
486 
487         spin_lock_bh(&nr_node_list_lock);
488         nr_node_for_each_safe(s, node, nodet, &nr_node_list) {
489                 nr_node_lock(s);
490                 for (i = 0; i < s->count; i++) {
491                         switch (s->routes[i].obs_count) {
492                         case 0:         /* A locked entry */
493                                 break;
494 
495                         case 1:         /* From 1 -> 0 */
496                                 nr_neigh = s->routes[i].neighbour;
497 
498                                 nr_neigh->count--;
499                                 nr_neigh_put(nr_neigh);
500 
501                                 if (nr_neigh->count == 0 && !nr_neigh->locked)
502                                         nr_remove_neigh(nr_neigh);
503 
504                                 s->count--;
505 
506                                 switch (i) {
507                                         case 0:
508                                                 s->routes[0] = s->routes[1];
509                                         case 1:
510                                                 s->routes[1] = s->routes[2];
511                                         case 2:
512                                                 break;
513                                 }
514                                 break;
515 
516                         default:
517                                 s->routes[i].obs_count--;
518                                 break;
519 
520                         }
521                 }
522 
523                 if (s->count <= 0)
524                         nr_remove_node_locked(s);
525                 nr_node_unlock(s);
526         }
527         spin_unlock_bh(&nr_node_list_lock);
528 
529         return 0;
530 }
531 
532 /*
533  *      A device has been removed. Remove its routes and neighbours.
534  */
535 void nr_rt_device_down(struct net_device *dev)
536 {
537         struct nr_neigh *s;
538         struct hlist_node *node, *nodet, *node2, *node2t;
539         struct nr_node  *t;
540         int i;
541 
542         spin_lock_bh(&nr_neigh_list_lock);
543         nr_neigh_for_each_safe(s, node, nodet, &nr_neigh_list) {
544                 if (s->dev == dev) {
545                         spin_lock_bh(&nr_node_list_lock);
546                         nr_node_for_each_safe(t, node2, node2t, &nr_node_list) {
547                                 nr_node_lock(t);
548                                 for (i = 0; i < t->count; i++) {
549                                         if (t->routes[i].neighbour == s) {
550                                                 t->count--;
551 
552                                                 switch (i) {
553                                                 case 0:
554                                                         t->routes[0] = t->routes[1];
555                                                 case 1:
556                                                         t->routes[1] = t->routes[2];
557                                                 case 2:
558                                                         break;
559                                                 }
560                                         }
561                                 }
562 
563                                 if (t->count <= 0)
564                                         nr_remove_node_locked(t);
565                                 nr_node_unlock(t);
566                         }
567                         spin_unlock_bh(&nr_node_list_lock);
568 
569                         nr_remove_neigh_locked(s);
570                 }
571         }
572         spin_unlock_bh(&nr_neigh_list_lock);
573 }
574 
575 /*
576  *      Check that the device given is a valid AX.25 interface that is "up".
577  *      Or a valid ethernet interface with an AX.25 callsign binding.
578  */
579 static struct net_device *nr_ax25_dev_get(char *devname)
580 {
581         struct net_device *dev;
582 
583         if ((dev = dev_get_by_name(&init_net, devname)) == NULL)
584                 return NULL;
585 
586         if ((dev->flags & IFF_UP) && dev->type == ARPHRD_AX25)
587                 return dev;
588 
589         dev_put(dev);
590         return NULL;
591 }
592 
593 /*
594  *      Find the first active NET/ROM device, usually "nr0".
595  */
596 struct net_device *nr_dev_first(void)
597 {
598         struct net_device *dev, *first = NULL;
599 
600         read_lock(&dev_base_lock);
601         for_each_netdev(&init_net, dev) {
602                 if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM)
603                         if (first == NULL || strncmp(dev->name, first->name, 3) < 0)
604                                 first = dev;
605         }
606         if (first)
607                 dev_hold(first);
608         read_unlock(&dev_base_lock);
609 
610         return first;
611 }
612 
613 /*
614  *      Find the NET/ROM device for the given callsign.
615  */
616 struct net_device *nr_dev_get(ax25_address *addr)
617 {
618         struct net_device *dev;
619 
620         read_lock(&dev_base_lock);
621         for_each_netdev(&init_net, dev) {
622                 if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM && ax25cmp(addr, (ax25_address *)dev->dev_addr) == 0) {
623                         dev_hold(dev);
624                         goto out;
625                 }
626         }
627         dev = NULL;
628 out:
629         read_unlock(&dev_base_lock);
630         return dev;
631 }
632 
633 static ax25_digi *nr_call_to_digi(ax25_digi *digi, int ndigis,
634         ax25_address *digipeaters)
635 {
636         int i;
637 
638         if (ndigis == 0)
639                 return NULL;
640 
641         for (i = 0; i < ndigis; i++) {
642                 digi->calls[i]    = digipeaters[i];
643                 digi->repeated[i] = 0;
644         }
645 
646         digi->ndigi      = ndigis;
647         digi->lastrepeat = -1;
648 
649         return digi;
650 }
651 
652 /*
653  *      Handle the ioctls that control the routing functions.
654  */
655 int nr_rt_ioctl(unsigned int cmd, void __user *arg)
656 {
657         struct nr_route_struct nr_route;
658         struct net_device *dev;
659         ax25_digi digi;
660         int ret;
661 
662         switch (cmd) {
663         case SIOCADDRT:
664                 if (copy_from_user(&nr_route, arg, sizeof(struct nr_route_struct)))
665                         return -EFAULT;
666                 if ((dev = nr_ax25_dev_get(nr_route.device)) == NULL)
667                         return -EINVAL;
668                 if (nr_route.ndigis < 0 || nr_route.ndigis > AX25_MAX_DIGIS) {
669                         dev_put(dev);
670                         return -EINVAL;
671                 }
672                 switch (nr_route.type) {
673                 case NETROM_NODE:
674                         ret = nr_add_node(&nr_route.callsign,
675                                 nr_route.mnemonic,
676                                 &nr_route.neighbour,
677                                 nr_call_to_digi(&digi, nr_route.ndigis,
678                                                 nr_route.digipeaters),
679                                 dev, nr_route.quality,
680                                 nr_route.obs_count);
681                         break;
682                 case NETROM_NEIGH:
683                         ret = nr_add_neigh(&nr_route.callsign,
684                                 nr_call_to_digi(&digi, nr_route.ndigis,
685                                                 nr_route.digipeaters),
686                                 dev, nr_route.quality);
687                         break;
688                 default:
689                         ret = -EINVAL;
690                 }
691                 dev_put(dev);
692                 return ret;
693 
694         case SIOCDELRT:
695                 if (copy_from_user(&nr_route, arg, sizeof(struct nr_route_struct)))
696                         return -EFAULT;
697                 if ((dev = nr_ax25_dev_get(nr_route.device)) == NULL)
698                         return -EINVAL;
699                 switch (nr_route.type) {
700                 case NETROM_NODE:
701                         ret = nr_del_node(&nr_route.callsign,
702                                 &nr_route.neighbour, dev);
703                         break;
704                 case NETROM_NEIGH:
705                         ret = nr_del_neigh(&nr_route.callsign,
706                                 dev, nr_route.quality);
707                         break;
708                 default:
709                         ret = -EINVAL;
710                 }
711                 dev_put(dev);
712                 return ret;
713 
714         case SIOCNRDECOBS:
715                 return nr_dec_obs();
716 
717         default:
718                 return -EINVAL;
719         }
720 
721         return 0;
722 }
723 
724 /*
725  *      A level 2 link has timed out, therefore it appears to be a poor link,
726  *      then don't use that neighbour until it is reset.
727  */
728 void nr_link_failed(ax25_cb *ax25, int reason)
729 {
730         struct nr_neigh *s, *nr_neigh = NULL;
731         struct hlist_node *node;
732         struct nr_node  *nr_node = NULL;
733 
734         spin_lock_bh(&nr_neigh_list_lock);
735         nr_neigh_for_each(s, node, &nr_neigh_list) {
736                 if (s->ax25 == ax25) {
737                         nr_neigh_hold(s);
738                         nr_neigh = s;
739                         break;
740                 }
741         }
742         spin_unlock_bh(&nr_neigh_list_lock);
743 
744         if (nr_neigh == NULL)
745                 return;
746 
747         nr_neigh->ax25 = NULL;
748         ax25_cb_put(ax25);
749 
750         if (++nr_neigh->failed < sysctl_netrom_link_fails_count) {
751                 nr_neigh_put(nr_neigh);
752                 return;
753         }
754         spin_lock_bh(&nr_node_list_lock);
755         nr_node_for_each(nr_node, node, &nr_node_list) {
756                 nr_node_lock(nr_node);
757                 if (nr_node->which < nr_node->count &&
758                     nr_node->routes[nr_node->which].neighbour == nr_neigh)
759                         nr_node->which++;
760                 nr_node_unlock(nr_node);
761         }
762         spin_unlock_bh(&nr_node_list_lock);
763         nr_neigh_put(nr_neigh);
764 }
765 
766 /*
767  *      Route a frame to an appropriate AX.25 connection. A NULL ax25_cb
768  *      indicates an internally generated frame.
769  */
770 int nr_route_frame(struct sk_buff *skb, ax25_cb *ax25)
771 {
772         ax25_address *nr_src, *nr_dest;
773         struct nr_neigh *nr_neigh;
774         struct nr_node  *nr_node;
775         struct net_device *dev;
776         unsigned char *dptr;
777         ax25_cb *ax25s;
778         int ret;
779         struct sk_buff *skbn;
780 
781 
782         nr_src  = (ax25_address *)(skb->data + 0);
783         nr_dest = (ax25_address *)(skb->data + 7);
784 
785         if (ax25 != NULL) {
786                 ret = nr_add_node(nr_src, "", &ax25->dest_addr, ax25->digipeat,
787                                   ax25->ax25_dev->dev, 0,
788                                   sysctl_netrom_obsolescence_count_initialiser);
789                 if (ret)
790                         return ret;
791         }
792 
793         if ((dev = nr_dev_get(nr_dest)) != NULL) {      /* Its for me */
794                 if (ax25 == NULL)                       /* Its from me */
795                         ret = nr_loopback_queue(skb);
796                 else
797                         ret = nr_rx_frame(skb, dev);
798                 dev_put(dev);
799                 return ret;
800         }
801 
802         if (!sysctl_netrom_routing_control && ax25 != NULL)
803                 return 0;
804 
805         /* Its Time-To-Live has expired */
806         if (skb->data[14] == 1) {
807                 return 0;
808         }
809 
810         nr_node = nr_node_get(nr_dest);
811         if (nr_node == NULL)
812                 return 0;
813         nr_node_lock(nr_node);
814 
815         if (nr_node->which >= nr_node->count) {
816                 nr_node_unlock(nr_node);
817                 nr_node_put(nr_node);
818                 return 0;
819         }
820 
821         nr_neigh = nr_node->routes[nr_node->which].neighbour;
822 
823         if ((dev = nr_dev_first()) == NULL) {
824                 nr_node_unlock(nr_node);
825                 nr_node_put(nr_node);
826                 return 0;
827         }
828 
829         /* We are going to change the netrom headers so we should get our
830            own skb, we also did not know until now how much header space
831            we had to reserve... - RXQ */
832         if ((skbn=skb_copy_expand(skb, dev->hard_header_len, 0, GFP_ATOMIC)) == NULL) {
833                 nr_node_unlock(nr_node);
834                 nr_node_put(nr_node);
835                 dev_put(dev);
836                 return 0;
837         }
838         kfree_skb(skb);
839         skb=skbn;
840         skb->data[14]--;
841 
842         dptr  = skb_push(skb, 1);
843         *dptr = AX25_P_NETROM;
844 
845         ax25s = nr_neigh->ax25;
846         nr_neigh->ax25 = ax25_send_frame(skb, 256,
847                                          (ax25_address *)dev->dev_addr,
848                                          &nr_neigh->callsign,
849                                          nr_neigh->digipeat, nr_neigh->dev);
850         if (ax25s)
851                 ax25_cb_put(ax25s);
852 
853         dev_put(dev);
854         ret = (nr_neigh->ax25 != NULL);
855         nr_node_unlock(nr_node);
856         nr_node_put(nr_node);
857 
858         return ret;
859 }
860 
861 #ifdef CONFIG_PROC_FS
862 
863 static void *nr_node_start(struct seq_file *seq, loff_t *pos)
864 {
865         struct nr_node *nr_node;
866         struct hlist_node *node;
867         int i = 1;
868 
869         spin_lock_bh(&nr_node_list_lock);
870         if (*pos == 0)
871                 return SEQ_START_TOKEN;
872 
873         nr_node_for_each(nr_node, node, &nr_node_list) {
874                 if (i == *pos)
875                         return nr_node;
876                 ++i;
877         }
878 
879         return NULL;
880 }
881 
882 static void *nr_node_next(struct seq_file *seq, void *v, loff_t *pos)
883 {
884         struct hlist_node *node;
885         ++*pos;
886 
887         node = (v == SEQ_START_TOKEN)
888                 ? nr_node_list.first
889                 : ((struct nr_node *)v)->node_node.next;
890 
891         return hlist_entry(node, struct nr_node, node_node);
892 }
893 
894 static void nr_node_stop(struct seq_file *seq, void *v)
895 {
896         spin_unlock_bh(&nr_node_list_lock);
897 }
898 
899 static int nr_node_show(struct seq_file *seq, void *v)
900 {
901         char buf[11];
902         int i;
903 
904         if (v == SEQ_START_TOKEN)
905                 seq_puts(seq,
906                          "callsign  mnemonic w n qual obs neigh qual obs neigh qual obs neigh\n");
907         else {
908                 struct nr_node *nr_node = v;
909                 nr_node_lock(nr_node);
910                 seq_printf(seq, "%-9s %-7s  %d %d",
911                         ax2asc(buf, &nr_node->callsign),
912                         (nr_node->mnemonic[0] == '\0') ? "*" : nr_node->mnemonic,
913                         nr_node->which + 1,
914                         nr_node->count);
915 
916                 for (i = 0; i < nr_node->count; i++) {
917                         seq_printf(seq, "  %3d   %d %05d",
918                                 nr_node->routes[i].quality,
919                                 nr_node->routes[i].obs_count,
920                                 nr_node->routes[i].neighbour->number);
921                 }
922                 nr_node_unlock(nr_node);
923 
924                 seq_puts(seq, "\n");
925         }
926         return 0;
927 }
928 
929 static const struct seq_operations nr_node_seqops = {
930         .start = nr_node_start,
931         .next = nr_node_next,
932         .stop = nr_node_stop,
933         .show = nr_node_show,
934 };
935 
936 static int nr_node_info_open(struct inode *inode, struct file *file)
937 {
938         return seq_open(file, &nr_node_seqops);
939 }
940 
941 const struct file_operations nr_nodes_fops = {
942         .owner = THIS_MODULE,
943         .open = nr_node_info_open,
944         .read = seq_read,
945         .llseek = seq_lseek,
946         .release = seq_release,
947 };
948 
949 static void *nr_neigh_start(struct seq_file *seq, loff_t *pos)
950 {
951         struct nr_neigh *nr_neigh;
952         struct hlist_node *node;
953         int i = 1;
954 
955         spin_lock_bh(&nr_neigh_list_lock);
956         if (*pos == 0)
957                 return SEQ_START_TOKEN;
958 
959         nr_neigh_for_each(nr_neigh, node, &nr_neigh_list) {
960                 if (i == *pos)
961                         return nr_neigh;
962         }
963         return NULL;
964 }
965 
966 static void *nr_neigh_next(struct seq_file *seq, void *v, loff_t *pos)
967 {
968         struct hlist_node *node;
969         ++*pos;
970 
971         node = (v == SEQ_START_TOKEN)
972                 ? nr_neigh_list.first
973                 : ((struct nr_neigh *)v)->neigh_node.next;
974 
975         return hlist_entry(node, struct nr_neigh, neigh_node);
976 }
977 
978 static void nr_neigh_stop(struct seq_file *seq, void *v)
979 {
980         spin_unlock_bh(&nr_neigh_list_lock);
981 }
982 
983 static int nr_neigh_show(struct seq_file *seq, void *v)
984 {
985         char buf[11];
986         int i;
987 
988         if (v == SEQ_START_TOKEN)
989                 seq_puts(seq, "addr  callsign  dev  qual lock count failed digipeaters\n");
990         else {
991                 struct nr_neigh *nr_neigh = v;
992 
993                 seq_printf(seq, "%05d %-9s %-4s  %3d    %d   %3d    %3d",
994                         nr_neigh->number,
995                         ax2asc(buf, &nr_neigh->callsign),
996                         nr_neigh->dev ? nr_neigh->dev->name : "???",
997                         nr_neigh->quality,
998                         nr_neigh->locked,
999                         nr_neigh->count,
1000                         nr_neigh->failed);
1001 
1002                 if (nr_neigh->digipeat != NULL) {
1003                         for (i = 0; i < nr_neigh->digipeat->ndigi; i++)
1004                                 seq_printf(seq, " %s",
1005                                            ax2asc(buf, &nr_neigh->digipeat->calls[i]));
1006                 }
1007 
1008                 seq_puts(seq, "\n");
1009         }
1010         return 0;
1011 }
1012 
1013 static const struct seq_operations nr_neigh_seqops = {
1014         .start = nr_neigh_start,
1015         .next = nr_neigh_next,
1016         .stop = nr_neigh_stop,
1017         .show = nr_neigh_show,
1018 };
1019 
1020 static int nr_neigh_info_open(struct inode *inode, struct file *file)
1021 {
1022         return seq_open(file, &nr_neigh_seqops);
1023 }
1024 
1025 const struct file_operations nr_neigh_fops = {
1026         .owner = THIS_MODULE,
1027         .open = nr_neigh_info_open,
1028         .read = seq_read,
1029         .llseek = seq_lseek,
1030         .release = seq_release,
1031 };
1032 
1033 #endif
1034 
1035 /*
1036  *      Free all memory associated with the nodes and routes lists.
1037  */
1038 void __exit nr_rt_free(void)
1039 {
1040         struct nr_neigh *s = NULL;
1041         struct nr_node  *t = NULL;
1042         struct hlist_node *node, *nodet;
1043 
1044         spin_lock_bh(&nr_neigh_list_lock);
1045         spin_lock_bh(&nr_node_list_lock);
1046         nr_node_for_each_safe(t, node, nodet, &nr_node_list) {
1047                 nr_node_lock(t);
1048                 nr_remove_node_locked(t);
1049                 nr_node_unlock(t);
1050         }
1051         nr_neigh_for_each_safe(s, node, nodet, &nr_neigh_list) {
1052                 while(s->count) {
1053                         s->count--;
1054                         nr_neigh_put(s);
1055                 }
1056                 nr_remove_neigh_locked(s);
1057         }
1058         spin_unlock_bh(&nr_node_list_lock);
1059         spin_unlock_bh(&nr_neigh_list_lock);
1060 }
1061 

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

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp