blob: e2e2d33cafdf6f98dfdc2fb47acfa39e736bb90d [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070016#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
40static unsigned int nr_neigh_no = 1;
41
42static HLIST_HEAD(nr_node_list);
43static DEFINE_SPINLOCK(nr_node_list_lock);
44static HLIST_HEAD(nr_neigh_list);
45static DEFINE_SPINLOCK(nr_neigh_list_lock);
46
47static 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
64static 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
83static 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 */
Ralf Baechlec9266b92006-12-14 15:49:28 -080089static 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)
Linus Torvalds1da177e2005-04-16 15:20:36 -070092{
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) {
Arnaldo Carvalho de Meloeafff862006-11-17 13:05:04 -0200158 nr_neigh->digipeat = kmemdup(ax25_digi,
159 sizeof(*ax25_digi),
160 GFP_KERNEL);
161 if (nr_neigh->digipeat == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 kfree(nr_neigh);
163 if (nr_node)
164 nr_node_put(nr_node);
165 return -ENOMEM;
166 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 }
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
315static 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
324static 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
331static 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
340static 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 */
351static 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 */
Ralf Baechlec9266b92006-12-14 15:49:28 -0800409static int __must_check nr_add_neigh(ax25_address *callsign,
410 ax25_digi *ax25_digi, struct net_device *dev, unsigned int quality)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411{
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) {
Arnaldo Carvalho de Meloeafff862006-11-17 13:05:04 -0200437 nr_neigh->digipeat = kmemdup(ax25_digi, sizeof(*ax25_digi),
438 GFP_KERNEL);
439 if (nr_neigh->digipeat == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 kfree(nr_neigh);
441 return -ENOMEM;
442 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 }
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 */
457static 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 */
480static 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 */
535void 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 */
579static struct net_device *nr_ax25_dev_get(char *devname)
580{
581 struct net_device *dev;
582
Eric W. Biederman881d9662007-09-17 11:56:21 -0700583 if ((dev = dev_get_by_name(&init_net, devname)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 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 */
596struct net_device *nr_dev_first(void)
597{
598 struct net_device *dev, *first = NULL;
599
Eric Dumazetc6d14c82009-11-04 05:43:23 -0800600 rcu_read_lock();
601 for_each_netdev_rcu(&init_net, dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 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);
Eric Dumazetc6d14c82009-11-04 05:43:23 -0800608 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609
610 return first;
611}
612
613/*
614 * Find the NET/ROM device for the given callsign.
615 */
616struct net_device *nr_dev_get(ax25_address *addr)
617{
618 struct net_device *dev;
619
Eric Dumazetc6d14c82009-11-04 05:43:23 -0800620 rcu_read_lock();
621 for_each_netdev_rcu(&init_net, dev) {
622 if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM &&
623 ax25cmp(addr, (ax25_address *)dev->dev_addr) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 dev_hold(dev);
625 goto out;
626 }
627 }
Pavel Emelianov7562f872007-05-03 15:13:45 -0700628 dev = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629out:
Eric Dumazetc6d14c82009-11-04 05:43:23 -0800630 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 return dev;
632}
633
Ralf Baechlec6ba9732009-08-17 18:05:32 -0700634static ax25_digi *nr_call_to_digi(ax25_digi *digi, int ndigis,
635 ax25_address *digipeaters)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 int i;
638
639 if (ndigis == 0)
640 return NULL;
641
642 for (i = 0; i < ndigis; i++) {
Ralf Baechlec6ba9732009-08-17 18:05:32 -0700643 digi->calls[i] = digipeaters[i];
644 digi->repeated[i] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 }
646
Ralf Baechlec6ba9732009-08-17 18:05:32 -0700647 digi->ndigi = ndigis;
648 digi->lastrepeat = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649
Ralf Baechlec6ba9732009-08-17 18:05:32 -0700650 return digi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651}
652
653/*
654 * Handle the ioctls that control the routing functions.
655 */
656int nr_rt_ioctl(unsigned int cmd, void __user *arg)
657{
658 struct nr_route_struct nr_route;
659 struct net_device *dev;
Ralf Baechlec6ba9732009-08-17 18:05:32 -0700660 ax25_digi digi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 int ret;
662
663 switch (cmd) {
664 case SIOCADDRT:
665 if (copy_from_user(&nr_route, arg, sizeof(struct nr_route_struct)))
666 return -EFAULT;
667 if ((dev = nr_ax25_dev_get(nr_route.device)) == NULL)
668 return -EINVAL;
669 if (nr_route.ndigis < 0 || nr_route.ndigis > AX25_MAX_DIGIS) {
670 dev_put(dev);
671 return -EINVAL;
672 }
673 switch (nr_route.type) {
674 case NETROM_NODE:
675 ret = nr_add_node(&nr_route.callsign,
676 nr_route.mnemonic,
677 &nr_route.neighbour,
Ralf Baechlec6ba9732009-08-17 18:05:32 -0700678 nr_call_to_digi(&digi, nr_route.ndigis,
679 nr_route.digipeaters),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 dev, nr_route.quality,
681 nr_route.obs_count);
682 break;
683 case NETROM_NEIGH:
684 ret = nr_add_neigh(&nr_route.callsign,
Ralf Baechlec6ba9732009-08-17 18:05:32 -0700685 nr_call_to_digi(&digi, nr_route.ndigis,
686 nr_route.digipeaters),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 dev, nr_route.quality);
688 break;
689 default:
690 ret = -EINVAL;
691 }
692 dev_put(dev);
693 return ret;
694
695 case SIOCDELRT:
696 if (copy_from_user(&nr_route, arg, sizeof(struct nr_route_struct)))
697 return -EFAULT;
698 if ((dev = nr_ax25_dev_get(nr_route.device)) == NULL)
699 return -EINVAL;
700 switch (nr_route.type) {
701 case NETROM_NODE:
702 ret = nr_del_node(&nr_route.callsign,
703 &nr_route.neighbour, dev);
704 break;
705 case NETROM_NEIGH:
706 ret = nr_del_neigh(&nr_route.callsign,
707 dev, nr_route.quality);
708 break;
709 default:
710 ret = -EINVAL;
711 }
712 dev_put(dev);
713 return ret;
714
715 case SIOCNRDECOBS:
716 return nr_dec_obs();
717
718 default:
719 return -EINVAL;
720 }
721
722 return 0;
723}
724
725/*
726 * A level 2 link has timed out, therefore it appears to be a poor link,
727 * then don't use that neighbour until it is reset.
728 */
729void nr_link_failed(ax25_cb *ax25, int reason)
730{
731 struct nr_neigh *s, *nr_neigh = NULL;
732 struct hlist_node *node;
733 struct nr_node *nr_node = NULL;
734
735 spin_lock_bh(&nr_neigh_list_lock);
Ralf Baechle52383672006-06-26 00:05:23 -0700736 nr_neigh_for_each(s, node, &nr_neigh_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 if (s->ax25 == ax25) {
738 nr_neigh_hold(s);
739 nr_neigh = s;
740 break;
741 }
Ralf Baechle52383672006-06-26 00:05:23 -0700742 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 spin_unlock_bh(&nr_neigh_list_lock);
744
Ralf Baechle52383672006-06-26 00:05:23 -0700745 if (nr_neigh == NULL)
746 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747
748 nr_neigh->ax25 = NULL;
749 ax25_cb_put(ax25);
750
751 if (++nr_neigh->failed < sysctl_netrom_link_fails_count) {
752 nr_neigh_put(nr_neigh);
753 return;
754 }
755 spin_lock_bh(&nr_node_list_lock);
Ralf Baechle52383672006-06-26 00:05:23 -0700756 nr_node_for_each(nr_node, node, &nr_node_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 nr_node_lock(nr_node);
Ralf Baechle52383672006-06-26 00:05:23 -0700758 if (nr_node->which < nr_node->count &&
759 nr_node->routes[nr_node->which].neighbour == nr_neigh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 nr_node->which++;
761 nr_node_unlock(nr_node);
Ralf Baechle52383672006-06-26 00:05:23 -0700762 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 spin_unlock_bh(&nr_node_list_lock);
764 nr_neigh_put(nr_neigh);
765}
766
767/*
768 * Route a frame to an appropriate AX.25 connection. A NULL ax25_cb
769 * indicates an internally generated frame.
770 */
771int nr_route_frame(struct sk_buff *skb, ax25_cb *ax25)
772{
773 ax25_address *nr_src, *nr_dest;
774 struct nr_neigh *nr_neigh;
775 struct nr_node *nr_node;
776 struct net_device *dev;
777 unsigned char *dptr;
778 ax25_cb *ax25s;
779 int ret;
780 struct sk_buff *skbn;
781
782
783 nr_src = (ax25_address *)(skb->data + 0);
784 nr_dest = (ax25_address *)(skb->data + 7);
785
Ralf Baechle58bc5742006-12-14 15:50:58 -0800786 if (ax25 != NULL) {
787 ret = nr_add_node(nr_src, "", &ax25->dest_addr, ax25->digipeat,
YOSHIFUJI Hideaki5f8f59d2007-02-09 23:25:09 +0900788 ax25->ax25_dev->dev, 0,
789 sysctl_netrom_obsolescence_count_initialiser);
Ralf Baechle58bc5742006-12-14 15:50:58 -0800790 if (ret)
791 return ret;
792 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793
794 if ((dev = nr_dev_get(nr_dest)) != NULL) { /* Its for me */
795 if (ax25 == NULL) /* Its from me */
796 ret = nr_loopback_queue(skb);
797 else
798 ret = nr_rx_frame(skb, dev);
799 dev_put(dev);
800 return ret;
801 }
802
803 if (!sysctl_netrom_routing_control && ax25 != NULL)
804 return 0;
805
806 /* Its Time-To-Live has expired */
807 if (skb->data[14] == 1) {
808 return 0;
809 }
810
811 nr_node = nr_node_get(nr_dest);
812 if (nr_node == NULL)
813 return 0;
814 nr_node_lock(nr_node);
815
816 if (nr_node->which >= nr_node->count) {
817 nr_node_unlock(nr_node);
818 nr_node_put(nr_node);
819 return 0;
820 }
821
822 nr_neigh = nr_node->routes[nr_node->which].neighbour;
823
824 if ((dev = nr_dev_first()) == NULL) {
825 nr_node_unlock(nr_node);
826 nr_node_put(nr_node);
827 return 0;
828 }
829
830 /* We are going to change the netrom headers so we should get our
831 own skb, we also did not know until now how much header space
832 we had to reserve... - RXQ */
833 if ((skbn=skb_copy_expand(skb, dev->hard_header_len, 0, GFP_ATOMIC)) == NULL) {
834 nr_node_unlock(nr_node);
835 nr_node_put(nr_node);
836 dev_put(dev);
837 return 0;
838 }
839 kfree_skb(skb);
840 skb=skbn;
841 skb->data[14]--;
842
843 dptr = skb_push(skb, 1);
844 *dptr = AX25_P_NETROM;
845
Jarek Poplawskid00c3622010-01-16 01:04:04 -0800846 ax25s = nr_neigh->ax25;
847 nr_neigh->ax25 = ax25_send_frame(skb, 256,
848 (ax25_address *)dev->dev_addr,
849 &nr_neigh->callsign,
850 nr_neigh->digipeat, nr_neigh->dev);
851 if (ax25s)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 ax25_cb_put(ax25s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853
854 dev_put(dev);
855 ret = (nr_neigh->ax25 != NULL);
856 nr_node_unlock(nr_node);
857 nr_node_put(nr_node);
Ralf Baechle58bc5742006-12-14 15:50:58 -0800858
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 return ret;
860}
861
862#ifdef CONFIG_PROC_FS
863
864static void *nr_node_start(struct seq_file *seq, loff_t *pos)
865{
866 struct nr_node *nr_node;
867 struct hlist_node *node;
868 int i = 1;
YOSHIFUJI Hideaki5f8f59d2007-02-09 23:25:09 +0900869
870 spin_lock_bh(&nr_node_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 if (*pos == 0)
872 return SEQ_START_TOKEN;
873
874 nr_node_for_each(nr_node, node, &nr_node_list) {
875 if (i == *pos)
876 return nr_node;
877 ++i;
878 }
879
880 return NULL;
881}
882
883static void *nr_node_next(struct seq_file *seq, void *v, loff_t *pos)
884{
885 struct hlist_node *node;
886 ++*pos;
YOSHIFUJI Hideaki5f8f59d2007-02-09 23:25:09 +0900887
888 node = (v == SEQ_START_TOKEN)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 ? nr_node_list.first
890 : ((struct nr_node *)v)->node_node.next;
891
892 return hlist_entry(node, struct nr_node, node_node);
893}
894
895static void nr_node_stop(struct seq_file *seq, void *v)
896{
897 spin_unlock_bh(&nr_node_list_lock);
898}
899
900static int nr_node_show(struct seq_file *seq, void *v)
901{
Ralf Baechlef75268c2005-09-06 15:49:39 -0700902 char buf[11];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 int i;
904
905 if (v == SEQ_START_TOKEN)
906 seq_puts(seq,
907 "callsign mnemonic w n qual obs neigh qual obs neigh qual obs neigh\n");
908 else {
909 struct nr_node *nr_node = v;
910 nr_node_lock(nr_node);
911 seq_printf(seq, "%-9s %-7s %d %d",
Ralf Baechlef75268c2005-09-06 15:49:39 -0700912 ax2asc(buf, &nr_node->callsign),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 (nr_node->mnemonic[0] == '\0') ? "*" : nr_node->mnemonic,
914 nr_node->which + 1,
915 nr_node->count);
916
917 for (i = 0; i < nr_node->count; i++) {
918 seq_printf(seq, " %3d %d %05d",
919 nr_node->routes[i].quality,
920 nr_node->routes[i].obs_count,
921 nr_node->routes[i].neighbour->number);
922 }
923 nr_node_unlock(nr_node);
924
925 seq_puts(seq, "\n");
926 }
927 return 0;
928}
929
Philippe De Muyter56b3d972007-07-10 23:07:31 -0700930static const struct seq_operations nr_node_seqops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 .start = nr_node_start,
932 .next = nr_node_next,
933 .stop = nr_node_stop,
934 .show = nr_node_show,
935};
936
937static int nr_node_info_open(struct inode *inode, struct file *file)
938{
939 return seq_open(file, &nr_node_seqops);
940}
941
Arjan van de Venda7071d2007-02-12 00:55:36 -0800942const struct file_operations nr_nodes_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 .owner = THIS_MODULE,
944 .open = nr_node_info_open,
945 .read = seq_read,
946 .llseek = seq_lseek,
947 .release = seq_release,
948};
949
950static void *nr_neigh_start(struct seq_file *seq, loff_t *pos)
951{
952 struct nr_neigh *nr_neigh;
953 struct hlist_node *node;
954 int i = 1;
955
956 spin_lock_bh(&nr_neigh_list_lock);
957 if (*pos == 0)
958 return SEQ_START_TOKEN;
959
960 nr_neigh_for_each(nr_neigh, node, &nr_neigh_list) {
961 if (i == *pos)
962 return nr_neigh;
963 }
964 return NULL;
965}
966
967static void *nr_neigh_next(struct seq_file *seq, void *v, loff_t *pos)
968{
969 struct hlist_node *node;
970 ++*pos;
YOSHIFUJI Hideaki5f8f59d2007-02-09 23:25:09 +0900971
972 node = (v == SEQ_START_TOKEN)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 ? nr_neigh_list.first
974 : ((struct nr_neigh *)v)->neigh_node.next;
975
976 return hlist_entry(node, struct nr_neigh, neigh_node);
977}
978
979static void nr_neigh_stop(struct seq_file *seq, void *v)
980{
981 spin_unlock_bh(&nr_neigh_list_lock);
982}
983
984static int nr_neigh_show(struct seq_file *seq, void *v)
985{
Ralf Baechlef75268c2005-09-06 15:49:39 -0700986 char buf[11];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 int i;
988
989 if (v == SEQ_START_TOKEN)
990 seq_puts(seq, "addr callsign dev qual lock count failed digipeaters\n");
991 else {
992 struct nr_neigh *nr_neigh = v;
993
994 seq_printf(seq, "%05d %-9s %-4s %3d %d %3d %3d",
995 nr_neigh->number,
Ralf Baechlef75268c2005-09-06 15:49:39 -0700996 ax2asc(buf, &nr_neigh->callsign),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 nr_neigh->dev ? nr_neigh->dev->name : "???",
998 nr_neigh->quality,
999 nr_neigh->locked,
1000 nr_neigh->count,
1001 nr_neigh->failed);
1002
1003 if (nr_neigh->digipeat != NULL) {
1004 for (i = 0; i < nr_neigh->digipeat->ndigi; i++)
YOSHIFUJI Hideaki5f8f59d2007-02-09 23:25:09 +09001005 seq_printf(seq, " %s",
Ralf Baechlef75268c2005-09-06 15:49:39 -07001006 ax2asc(buf, &nr_neigh->digipeat->calls[i]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 }
1008
1009 seq_puts(seq, "\n");
1010 }
1011 return 0;
1012}
1013
Philippe De Muyter56b3d972007-07-10 23:07:31 -07001014static const struct seq_operations nr_neigh_seqops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015 .start = nr_neigh_start,
1016 .next = nr_neigh_next,
1017 .stop = nr_neigh_stop,
1018 .show = nr_neigh_show,
1019};
1020
1021static int nr_neigh_info_open(struct inode *inode, struct file *file)
1022{
1023 return seq_open(file, &nr_neigh_seqops);
1024}
1025
Arjan van de Venda7071d2007-02-12 00:55:36 -08001026const struct file_operations nr_neigh_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 .owner = THIS_MODULE,
1028 .open = nr_neigh_info_open,
1029 .read = seq_read,
1030 .llseek = seq_lseek,
1031 .release = seq_release,
1032};
1033
1034#endif
1035
1036/*
1037 * Free all memory associated with the nodes and routes lists.
1038 */
1039void __exit nr_rt_free(void)
1040{
1041 struct nr_neigh *s = NULL;
1042 struct nr_node *t = NULL;
1043 struct hlist_node *node, *nodet;
1044
1045 spin_lock_bh(&nr_neigh_list_lock);
1046 spin_lock_bh(&nr_node_list_lock);
1047 nr_node_for_each_safe(t, node, nodet, &nr_node_list) {
1048 nr_node_lock(t);
1049 nr_remove_node_locked(t);
1050 nr_node_unlock(t);
1051 }
1052 nr_neigh_for_each_safe(s, node, nodet, &nr_neigh_list) {
1053 while(s->count) {
1054 s->count--;
1055 nr_neigh_put(s);
1056 }
1057 nr_remove_neigh_locked(s);
1058 }
1059 spin_unlock_bh(&nr_node_list_lock);
1060 spin_unlock_bh(&nr_neigh_list_lock);
1061}