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

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

Version: ~ [ linux-5.5-rc1 ] ~ [ linux-5.4.2 ] ~ [ linux-5.3.15 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.88 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.158 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.206 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.206 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.78 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ 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 <linux/slab.h>
 21 #include <net/ax25.h>
 22 #include <linux/inet.h>
 23 #include <linux/netdevice.h>
 24 #include <net/arp.h>
 25 #include <linux/if_arp.h>
 26 #include <linux/skbuff.h>
 27 #include <net/sock.h>
 28 #include <linux/uaccess.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/init.h>
 35 #include <linux/spinlock.h>
 36 #include <net/netrom.h>
 37 #include <linux/seq_file.h>
 38 #include <linux/export.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 
 52         spin_lock_bh(&nr_node_list_lock);
 53         nr_node_for_each(nr_node, &nr_node_list)
 54                 if (ax25cmp(callsign, &nr_node->callsign) == 0) {
 55                         nr_node_hold(nr_node);
 56                         found = nr_node;
 57                         break;
 58                 }
 59         spin_unlock_bh(&nr_node_list_lock);
 60         return found;
 61 }
 62 
 63 static struct nr_neigh *nr_neigh_get_dev(ax25_address *callsign,
 64                                          struct net_device *dev)
 65 {
 66         struct nr_neigh *found = NULL;
 67         struct nr_neigh *nr_neigh;
 68 
 69         spin_lock_bh(&nr_neigh_list_lock);
 70         nr_neigh_for_each(nr_neigh, &nr_neigh_list)
 71                 if (ax25cmp(callsign, &nr_neigh->callsign) == 0 &&
 72                     nr_neigh->dev == dev) {
 73                         nr_neigh_hold(nr_neigh);
 74                         found = nr_neigh;
 75                         break;
 76                 }
 77         spin_unlock_bh(&nr_neigh_list_lock);
 78         return found;
 79 }
 80 
 81 static void nr_remove_neigh(struct nr_neigh *);
 82 
 83 /*
 84  *      Add a new route to a node, and in the process add the node and the
 85  *      neighbour if it is new.
 86  */
 87 static int __must_check nr_add_node(ax25_address *nr, const char *mnemonic,
 88         ax25_address *ax25, ax25_digi *ax25_digi, struct net_device *dev,
 89         int quality, int obs_count)
 90 {
 91         struct nr_node  *nr_node;
 92         struct nr_neigh *nr_neigh;
 93         struct nr_route nr_route;
 94         int i, found;
 95         struct net_device *odev;
 96 
 97         if ((odev=nr_dev_get(nr)) != NULL) {    /* Can't add routes to ourself */
 98                 dev_put(odev);
 99                 return -EINVAL;
100         }
101 
102         nr_node = nr_node_get(nr);
103 
104         nr_neigh = nr_neigh_get_dev(ax25, dev);
105 
106         /*
107          * The L2 link to a neighbour has failed in the past
108          * and now a frame comes from this neighbour. We assume
109          * it was a temporary trouble with the link and reset the
110          * routes now (and not wait for a node broadcast).
111          */
112         if (nr_neigh != NULL && nr_neigh->failed != 0 && quality == 0) {
113                 struct nr_node *nr_nodet;
114 
115                 spin_lock_bh(&nr_node_list_lock);
116                 nr_node_for_each(nr_nodet, &nr_node_list) {
117                         nr_node_lock(nr_nodet);
118                         for (i = 0; i < nr_nodet->count; i++)
119                                 if (nr_nodet->routes[i].neighbour == nr_neigh)
120                                         if (i < nr_nodet->which)
121                                                 nr_nodet->which = i;
122                         nr_node_unlock(nr_nodet);
123                 }
124                 spin_unlock_bh(&nr_node_list_lock);
125         }
126 
127         if (nr_neigh != NULL)
128                 nr_neigh->failed = 0;
129 
130         if (quality == 0 && nr_neigh != NULL && nr_node != NULL) {
131                 nr_neigh_put(nr_neigh);
132                 nr_node_put(nr_node);
133                 return 0;
134         }
135 
136         if (nr_neigh == NULL) {
137                 if ((nr_neigh = kmalloc(sizeof(*nr_neigh), GFP_ATOMIC)) == NULL) {
138                         if (nr_node)
139                                 nr_node_put(nr_node);
140                         return -ENOMEM;
141                 }
142 
143                 nr_neigh->callsign = *ax25;
144                 nr_neigh->digipeat = NULL;
145                 nr_neigh->ax25     = NULL;
146                 nr_neigh->dev      = dev;
147                 nr_neigh->quality  = sysctl_netrom_default_path_quality;
148                 nr_neigh->locked   = 0;
149                 nr_neigh->count    = 0;
150                 nr_neigh->number   = nr_neigh_no++;
151                 nr_neigh->failed   = 0;
152                 atomic_set(&nr_neigh->refcount, 1);
153 
154                 if (ax25_digi != NULL && ax25_digi->ndigi > 0) {
155                         nr_neigh->digipeat = kmemdup(ax25_digi,
156                                                      sizeof(*ax25_digi),
157                                                      GFP_KERNEL);
158                         if (nr_neigh->digipeat == NULL) {
159                                 kfree(nr_neigh);
160                                 if (nr_node)
161                                         nr_node_put(nr_node);
162                                 return -ENOMEM;
163                         }
164                 }
165 
166                 spin_lock_bh(&nr_neigh_list_lock);
167                 hlist_add_head(&nr_neigh->neigh_node, &nr_neigh_list);
168                 nr_neigh_hold(nr_neigh);
169                 spin_unlock_bh(&nr_neigh_list_lock);
170         }
171 
172         if (quality != 0 && ax25cmp(nr, ax25) == 0 && !nr_neigh->locked)
173                 nr_neigh->quality = quality;
174 
175         if (nr_node == NULL) {
176                 if ((nr_node = kmalloc(sizeof(*nr_node), GFP_ATOMIC)) == NULL) {
177                         if (nr_neigh)
178                                 nr_neigh_put(nr_neigh);
179                         return -ENOMEM;
180                 }
181 
182                 nr_node->callsign = *nr;
183                 strcpy(nr_node->mnemonic, mnemonic);
184 
185                 nr_node->which = 0;
186                 nr_node->count = 1;
187                 atomic_set(&nr_node->refcount, 1);
188                 spin_lock_init(&nr_node->node_lock);
189 
190                 nr_node->routes[0].quality   = quality;
191                 nr_node->routes[0].obs_count = obs_count;
192                 nr_node->routes[0].neighbour = nr_neigh;
193 
194                 nr_neigh_hold(nr_neigh);
195                 nr_neigh->count++;
196 
197                 spin_lock_bh(&nr_node_list_lock);
198                 hlist_add_head(&nr_node->node_node, &nr_node_list);
199                 /* refcount initialized at 1 */
200                 spin_unlock_bh(&nr_node_list_lock);
201 
202                 return 0;
203         }
204         nr_node_lock(nr_node);
205 
206         if (quality != 0)
207                 strcpy(nr_node->mnemonic, mnemonic);
208 
209         for (found = 0, i = 0; i < nr_node->count; i++) {
210                 if (nr_node->routes[i].neighbour == nr_neigh) {
211                         nr_node->routes[i].quality   = quality;
212                         nr_node->routes[i].obs_count = obs_count;
213                         found = 1;
214                         break;
215                 }
216         }
217 
218         if (!found) {
219                 /* We have space at the bottom, slot it in */
220                 if (nr_node->count < 3) {
221                         nr_node->routes[2] = nr_node->routes[1];
222                         nr_node->routes[1] = nr_node->routes[0];
223 
224                         nr_node->routes[0].quality   = quality;
225                         nr_node->routes[0].obs_count = obs_count;
226                         nr_node->routes[0].neighbour = nr_neigh;
227 
228                         nr_node->which++;
229                         nr_node->count++;
230                         nr_neigh_hold(nr_neigh);
231                         nr_neigh->count++;
232                 } else {
233                         /* It must be better than the worst */
234                         if (quality > nr_node->routes[2].quality) {
235                                 nr_node->routes[2].neighbour->count--;
236                                 nr_neigh_put(nr_node->routes[2].neighbour);
237 
238                                 if (nr_node->routes[2].neighbour->count == 0 && !nr_node->routes[2].neighbour->locked)
239                                         nr_remove_neigh(nr_node->routes[2].neighbour);
240 
241                                 nr_node->routes[2].quality   = quality;
242                                 nr_node->routes[2].obs_count = obs_count;
243                                 nr_node->routes[2].neighbour = nr_neigh;
244 
245                                 nr_neigh_hold(nr_neigh);
246                                 nr_neigh->count++;
247                         }
248                 }
249         }
250 
251         /* Now re-sort the routes in quality order */
252         switch (nr_node->count) {
253         case 3:
254                 if (nr_node->routes[1].quality > nr_node->routes[0].quality) {
255                         switch (nr_node->which) {
256                         case 0:
257                                 nr_node->which = 1;
258                                 break;
259                         case 1:
260                                 nr_node->which = 0;
261                                 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 *nodet;
485         int i;
486 
487         spin_lock_bh(&nr_node_list_lock);
488         nr_node_for_each_safe(s, 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                                         /* Fallthrough */
510                                 case 1:
511                                         s->routes[1] = s->routes[2];
512                                 case 2:
513                                         break;
514                                 }
515                                 break;
516 
517                         default:
518                                 s->routes[i].obs_count--;
519                                 break;
520 
521                         }
522                 }
523 
524                 if (s->count <= 0)
525                         nr_remove_node_locked(s);
526                 nr_node_unlock(s);
527         }
528         spin_unlock_bh(&nr_node_list_lock);
529 
530         return 0;
531 }
532 
533 /*
534  *      A device has been removed. Remove its routes and neighbours.
535  */
536 void nr_rt_device_down(struct net_device *dev)
537 {
538         struct nr_neigh *s;
539         struct hlist_node *nodet, *node2t;
540         struct nr_node  *t;
541         int i;
542 
543         spin_lock_bh(&nr_neigh_list_lock);
544         nr_neigh_for_each_safe(s, nodet, &nr_neigh_list) {
545                 if (s->dev == dev) {
546                         spin_lock_bh(&nr_node_list_lock);
547                         nr_node_for_each_safe(t, node2t, &nr_node_list) {
548                                 nr_node_lock(t);
549                                 for (i = 0; i < t->count; i++) {
550                                         if (t->routes[i].neighbour == s) {
551                                                 t->count--;
552 
553                                                 switch (i) {
554                                                 case 0:
555                                                         t->routes[0] = t->routes[1];
556                                                 case 1:
557                                                         t->routes[1] = t->routes[2];
558                                                 case 2:
559                                                         break;
560                                                 }
561                                         }
562                                 }
563 
564                                 if (t->count <= 0)
565                                         nr_remove_node_locked(t);
566                                 nr_node_unlock(t);
567                         }
568                         spin_unlock_bh(&nr_node_list_lock);
569 
570                         nr_remove_neigh_locked(s);
571                 }
572         }
573         spin_unlock_bh(&nr_neigh_list_lock);
574 }
575 
576 /*
577  *      Check that the device given is a valid AX.25 interface that is "up".
578  *      Or a valid ethernet interface with an AX.25 callsign binding.
579  */
580 static struct net_device *nr_ax25_dev_get(char *devname)
581 {
582         struct net_device *dev;
583 
584         if ((dev = dev_get_by_name(&init_net, devname)) == NULL)
585                 return NULL;
586 
587         if ((dev->flags & IFF_UP) && dev->type == ARPHRD_AX25)
588                 return dev;
589 
590         dev_put(dev);
591         return NULL;
592 }
593 
594 /*
595  *      Find the first active NET/ROM device, usually "nr0".
596  */
597 struct net_device *nr_dev_first(void)
598 {
599         struct net_device *dev, *first = NULL;
600 
601         rcu_read_lock();
602         for_each_netdev_rcu(&init_net, dev) {
603                 if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM)
604                         if (first == NULL || strncmp(dev->name, first->name, 3) < 0)
605                                 first = dev;
606         }
607         if (first)
608                 dev_hold(first);
609         rcu_read_unlock();
610 
611         return first;
612 }
613 
614 /*
615  *      Find the NET/ROM device for the given callsign.
616  */
617 struct net_device *nr_dev_get(ax25_address *addr)
618 {
619         struct net_device *dev;
620 
621         rcu_read_lock();
622         for_each_netdev_rcu(&init_net, dev) {
623                 if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM &&
624                     ax25cmp(addr, (ax25_address *)dev->dev_addr) == 0) {
625                         dev_hold(dev);
626                         goto out;
627                 }
628         }
629         dev = NULL;
630 out:
631         rcu_read_unlock();
632         return dev;
633 }
634 
635 static ax25_digi *nr_call_to_digi(ax25_digi *digi, int ndigis,
636         ax25_address *digipeaters)
637 {
638         int i;
639 
640         if (ndigis == 0)
641                 return NULL;
642 
643         for (i = 0; i < ndigis; i++) {
644                 digi->calls[i]    = digipeaters[i];
645                 digi->repeated[i] = 0;
646         }
647 
648         digi->ndigi      = ndigis;
649         digi->lastrepeat = -1;
650 
651         return digi;
652 }
653 
654 /*
655  *      Handle the ioctls that control the routing functions.
656  */
657 int nr_rt_ioctl(unsigned int cmd, void __user *arg)
658 {
659         struct nr_route_struct nr_route;
660         struct net_device *dev;
661         ax25_digi digi;
662         int ret;
663 
664         switch (cmd) {
665         case SIOCADDRT:
666                 if (copy_from_user(&nr_route, arg, sizeof(struct nr_route_struct)))
667                         return -EFAULT;
668                 if (nr_route.ndigis > AX25_MAX_DIGIS)
669                         return -EINVAL;
670                 if ((dev = nr_ax25_dev_get(nr_route.device)) == NULL)
671                         return -EINVAL;
672                 switch (nr_route.type) {
673                 case NETROM_NODE:
674                         if (strnlen(nr_route.mnemonic, 7) == 7) {
675                                 ret = -EINVAL;
676                                 break;
677                         }
678 
679                         ret = nr_add_node(&nr_route.callsign,
680                                 nr_route.mnemonic,
681                                 &nr_route.neighbour,
682                                 nr_call_to_digi(&digi, nr_route.ndigis,
683                                                 nr_route.digipeaters),
684                                 dev, nr_route.quality,
685                                 nr_route.obs_count);
686                         break;
687                 case NETROM_NEIGH:
688                         ret = nr_add_neigh(&nr_route.callsign,
689                                 nr_call_to_digi(&digi, nr_route.ndigis,
690                                                 nr_route.digipeaters),
691                                 dev, nr_route.quality);
692                         break;
693                 default:
694                         ret = -EINVAL;
695                 }
696                 dev_put(dev);
697                 return ret;
698 
699         case SIOCDELRT:
700                 if (copy_from_user(&nr_route, arg, sizeof(struct nr_route_struct)))
701                         return -EFAULT;
702                 if ((dev = nr_ax25_dev_get(nr_route.device)) == NULL)
703                         return -EINVAL;
704                 switch (nr_route.type) {
705                 case NETROM_NODE:
706                         ret = nr_del_node(&nr_route.callsign,
707                                 &nr_route.neighbour, dev);
708                         break;
709                 case NETROM_NEIGH:
710                         ret = nr_del_neigh(&nr_route.callsign,
711                                 dev, nr_route.quality);
712                         break;
713                 default:
714                         ret = -EINVAL;
715                 }
716                 dev_put(dev);
717                 return ret;
718 
719         case SIOCNRDECOBS:
720                 return nr_dec_obs();
721 
722         default:
723                 return -EINVAL;
724         }
725 
726         return 0;
727 }
728 
729 /*
730  *      A level 2 link has timed out, therefore it appears to be a poor link,
731  *      then don't use that neighbour until it is reset.
732  */
733 void nr_link_failed(ax25_cb *ax25, int reason)
734 {
735         struct nr_neigh *s, *nr_neigh = NULL;
736         struct nr_node  *nr_node = NULL;
737 
738         spin_lock_bh(&nr_neigh_list_lock);
739         nr_neigh_for_each(s, &nr_neigh_list) {
740                 if (s->ax25 == ax25) {
741                         nr_neigh_hold(s);
742                         nr_neigh = s;
743                         break;
744                 }
745         }
746         spin_unlock_bh(&nr_neigh_list_lock);
747 
748         if (nr_neigh == NULL)
749                 return;
750 
751         nr_neigh->ax25 = NULL;
752         ax25_cb_put(ax25);
753 
754         if (++nr_neigh->failed < sysctl_netrom_link_fails_count) {
755                 nr_neigh_put(nr_neigh);
756                 return;
757         }
758         spin_lock_bh(&nr_node_list_lock);
759         nr_node_for_each(nr_node, &nr_node_list) {
760                 nr_node_lock(nr_node);
761                 if (nr_node->which < nr_node->count &&
762                     nr_node->routes[nr_node->which].neighbour == nr_neigh)
763                         nr_node->which++;
764                 nr_node_unlock(nr_node);
765         }
766         spin_unlock_bh(&nr_node_list_lock);
767         nr_neigh_put(nr_neigh);
768 }
769 
770 /*
771  *      Route a frame to an appropriate AX.25 connection. A NULL ax25_cb
772  *      indicates an internally generated frame.
773  */
774 int nr_route_frame(struct sk_buff *skb, ax25_cb *ax25)
775 {
776         ax25_address *nr_src, *nr_dest;
777         struct nr_neigh *nr_neigh;
778         struct nr_node  *nr_node;
779         struct net_device *dev;
780         unsigned char *dptr;
781         ax25_cb *ax25s;
782         int ret;
783         struct sk_buff *skbn;
784 
785 
786         nr_src  = (ax25_address *)(skb->data + 0);
787         nr_dest = (ax25_address *)(skb->data + 7);
788 
789         if (ax25 != NULL) {
790                 ret = nr_add_node(nr_src, "", &ax25->dest_addr, ax25->digipeat,
791                                   ax25->ax25_dev->dev, 0,
792                                   sysctl_netrom_obsolescence_count_initialiser);
793                 if (ret)
794                         return ret;
795         }
796 
797         if ((dev = nr_dev_get(nr_dest)) != NULL) {      /* Its for me */
798                 if (ax25 == NULL)                       /* Its from me */
799                         ret = nr_loopback_queue(skb);
800                 else
801                         ret = nr_rx_frame(skb, dev);
802                 dev_put(dev);
803                 return ret;
804         }
805 
806         if (!sysctl_netrom_routing_control && ax25 != NULL)
807                 return 0;
808 
809         /* Its Time-To-Live has expired */
810         if (skb->data[14] == 1) {
811                 return 0;
812         }
813 
814         nr_node = nr_node_get(nr_dest);
815         if (nr_node == NULL)
816                 return 0;
817         nr_node_lock(nr_node);
818 
819         if (nr_node->which >= nr_node->count) {
820                 nr_node_unlock(nr_node);
821                 nr_node_put(nr_node);
822                 return 0;
823         }
824 
825         nr_neigh = nr_node->routes[nr_node->which].neighbour;
826 
827         if ((dev = nr_dev_first()) == NULL) {
828                 nr_node_unlock(nr_node);
829                 nr_node_put(nr_node);
830                 return 0;
831         }
832 
833         /* We are going to change the netrom headers so we should get our
834            own skb, we also did not know until now how much header space
835            we had to reserve... - RXQ */
836         if ((skbn=skb_copy_expand(skb, dev->hard_header_len, 0, GFP_ATOMIC)) == NULL) {
837                 nr_node_unlock(nr_node);
838                 nr_node_put(nr_node);
839                 dev_put(dev);
840                 return 0;
841         }
842         kfree_skb(skb);
843         skb=skbn;
844         skb->data[14]--;
845 
846         dptr  = skb_push(skb, 1);
847         *dptr = AX25_P_NETROM;
848 
849         ax25s = nr_neigh->ax25;
850         nr_neigh->ax25 = ax25_send_frame(skb, 256,
851                                          (ax25_address *)dev->dev_addr,
852                                          &nr_neigh->callsign,
853                                          nr_neigh->digipeat, nr_neigh->dev);
854         if (ax25s)
855                 ax25_cb_put(ax25s);
856 
857         dev_put(dev);
858         ret = (nr_neigh->ax25 != NULL);
859         nr_node_unlock(nr_node);
860         nr_node_put(nr_node);
861 
862         return ret;
863 }
864 
865 #ifdef CONFIG_PROC_FS
866 
867 static void *nr_node_start(struct seq_file *seq, loff_t *pos)
868 {
869         spin_lock_bh(&nr_node_list_lock);
870         return seq_hlist_start_head(&nr_node_list, *pos);
871 }
872 
873 static void *nr_node_next(struct seq_file *seq, void *v, loff_t *pos)
874 {
875         return seq_hlist_next(v, &nr_node_list, pos);
876 }
877 
878 static void nr_node_stop(struct seq_file *seq, void *v)
879 {
880         spin_unlock_bh(&nr_node_list_lock);
881 }
882 
883 static int nr_node_show(struct seq_file *seq, void *v)
884 {
885         char buf[11];
886         int i;
887 
888         if (v == SEQ_START_TOKEN)
889                 seq_puts(seq,
890                          "callsign  mnemonic w n qual obs neigh qual obs neigh qual obs neigh\n");
891         else {
892                 struct nr_node *nr_node = hlist_entry(v, struct nr_node,
893                                                       node_node);
894 
895                 nr_node_lock(nr_node);
896                 seq_printf(seq, "%-9s %-7s  %d %d",
897                         ax2asc(buf, &nr_node->callsign),
898                         (nr_node->mnemonic[0] == '\0') ? "*" : nr_node->mnemonic,
899                         nr_node->which + 1,
900                         nr_node->count);
901 
902                 for (i = 0; i < nr_node->count; i++) {
903                         seq_printf(seq, "  %3d   %d %05d",
904                                 nr_node->routes[i].quality,
905                                 nr_node->routes[i].obs_count,
906                                 nr_node->routes[i].neighbour->number);
907                 }
908                 nr_node_unlock(nr_node);
909 
910                 seq_puts(seq, "\n");
911         }
912         return 0;
913 }
914 
915 static const struct seq_operations nr_node_seqops = {
916         .start = nr_node_start,
917         .next = nr_node_next,
918         .stop = nr_node_stop,
919         .show = nr_node_show,
920 };
921 
922 static int nr_node_info_open(struct inode *inode, struct file *file)
923 {
924         return seq_open(file, &nr_node_seqops);
925 }
926 
927 const struct file_operations nr_nodes_fops = {
928         .owner = THIS_MODULE,
929         .open = nr_node_info_open,
930         .read = seq_read,
931         .llseek = seq_lseek,
932         .release = seq_release,
933 };
934 
935 static void *nr_neigh_start(struct seq_file *seq, loff_t *pos)
936 {
937         spin_lock_bh(&nr_neigh_list_lock);
938         return seq_hlist_start_head(&nr_neigh_list, *pos);
939 }
940 
941 static void *nr_neigh_next(struct seq_file *seq, void *v, loff_t *pos)
942 {
943         return seq_hlist_next(v, &nr_neigh_list, pos);
944 }
945 
946 static void nr_neigh_stop(struct seq_file *seq, void *v)
947 {
948         spin_unlock_bh(&nr_neigh_list_lock);
949 }
950 
951 static int nr_neigh_show(struct seq_file *seq, void *v)
952 {
953         char buf[11];
954         int i;
955 
956         if (v == SEQ_START_TOKEN)
957                 seq_puts(seq, "addr  callsign  dev  qual lock count failed digipeaters\n");
958         else {
959                 struct nr_neigh *nr_neigh;
960 
961                 nr_neigh = hlist_entry(v, struct nr_neigh, neigh_node);
962                 seq_printf(seq, "%05d %-9s %-4s  %3d    %d   %3d    %3d",
963                         nr_neigh->number,
964                         ax2asc(buf, &nr_neigh->callsign),
965                         nr_neigh->dev ? nr_neigh->dev->name : "???",
966                         nr_neigh->quality,
967                         nr_neigh->locked,
968                         nr_neigh->count,
969                         nr_neigh->failed);
970 
971                 if (nr_neigh->digipeat != NULL) {
972                         for (i = 0; i < nr_neigh->digipeat->ndigi; i++)
973                                 seq_printf(seq, " %s",
974                                            ax2asc(buf, &nr_neigh->digipeat->calls[i]));
975                 }
976 
977                 seq_puts(seq, "\n");
978         }
979         return 0;
980 }
981 
982 static const struct seq_operations nr_neigh_seqops = {
983         .start = nr_neigh_start,
984         .next = nr_neigh_next,
985         .stop = nr_neigh_stop,
986         .show = nr_neigh_show,
987 };
988 
989 static int nr_neigh_info_open(struct inode *inode, struct file *file)
990 {
991         return seq_open(file, &nr_neigh_seqops);
992 }
993 
994 const struct file_operations nr_neigh_fops = {
995         .owner = THIS_MODULE,
996         .open = nr_neigh_info_open,
997         .read = seq_read,
998         .llseek = seq_lseek,
999         .release = seq_release,
1000 };
1001 
1002 #endif
1003 
1004 /*
1005  *      Free all memory associated with the nodes and routes lists.
1006  */
1007 void __exit nr_rt_free(void)
1008 {
1009         struct nr_neigh *s = NULL;
1010         struct nr_node  *t = NULL;
1011         struct hlist_node *nodet;
1012 
1013         spin_lock_bh(&nr_neigh_list_lock);
1014         spin_lock_bh(&nr_node_list_lock);
1015         nr_node_for_each_safe(t, nodet, &nr_node_list) {
1016                 nr_node_lock(t);
1017                 nr_remove_node_locked(t);
1018                 nr_node_unlock(t);
1019         }
1020         nr_neigh_for_each_safe(s, nodet, &nr_neigh_list) {
1021                 while(s->count) {
1022                         s->count--;
1023                         nr_neigh_put(s);
1024                 }
1025                 nr_remove_neigh_locked(s);
1026         }
1027         spin_unlock_bh(&nr_node_list_lock);
1028         spin_unlock_bh(&nr_neigh_list_lock);
1029 }
1030 

~ [ 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