blob: 44059d0c8dd1dceb831a60a71447aa6e8aacb6df [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>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090020#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#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 <asm/uaccess.h>
29#include <asm/system.h>
30#include <linux/fcntl.h>
31#include <linux/termios.h> /* For TIOCINQ/OUTQ */
32#include <linux/mm.h>
33#include <linux/interrupt.h>
34#include <linux/notifier.h>
35#include <linux/netfilter.h>
36#include <linux/init.h>
37#include <linux/spinlock.h>
38#include <net/netrom.h>
39#include <linux/seq_file.h>
40
41static unsigned int nr_neigh_no = 1;
42
43static HLIST_HEAD(nr_node_list);
44static DEFINE_SPINLOCK(nr_node_list_lock);
45static HLIST_HEAD(nr_neigh_list);
46static DEFINE_SPINLOCK(nr_neigh_list_lock);
47
48static struct nr_node *nr_node_get(ax25_address *callsign)
49{
50 struct nr_node *found = NULL;
51 struct nr_node *nr_node;
52 struct hlist_node *node;
53
54 spin_lock_bh(&nr_node_list_lock);
55 nr_node_for_each(nr_node, node, &nr_node_list)
56 if (ax25cmp(callsign, &nr_node->callsign) == 0) {
57 nr_node_hold(nr_node);
58 found = nr_node;
59 break;
60 }
61 spin_unlock_bh(&nr_node_list_lock);
62 return found;
63}
64
65static struct nr_neigh *nr_neigh_get_dev(ax25_address *callsign,
66 struct net_device *dev)
67{
68 struct nr_neigh *found = NULL;
69 struct nr_neigh *nr_neigh;
70 struct hlist_node *node;
71
72 spin_lock_bh(&nr_neigh_list_lock);
73 nr_neigh_for_each(nr_neigh, node, &nr_neigh_list)
74 if (ax25cmp(callsign, &nr_neigh->callsign) == 0 &&
75 nr_neigh->dev == dev) {
76 nr_neigh_hold(nr_neigh);
77 found = nr_neigh;
78 break;
79 }
80 spin_unlock_bh(&nr_neigh_list_lock);
81 return found;
82}
83
84static void nr_remove_neigh(struct nr_neigh *);
85
86/*
87 * Add a new route to a node, and in the process add the node and the
88 * neighbour if it is new.
89 */
Ralf Baechlec9266b92006-12-14 15:49:28 -080090static int __must_check nr_add_node(ax25_address *nr, const char *mnemonic,
91 ax25_address *ax25, ax25_digi *ax25_digi, struct net_device *dev,
92 int quality, int obs_count)
Linus Torvalds1da177e2005-04-16 15:20:36 -070093{
94 struct nr_node *nr_node;
95 struct nr_neigh *nr_neigh;
96 struct nr_route nr_route;
97 int i, found;
98 struct net_device *odev;
99
100 if ((odev=nr_dev_get(nr)) != NULL) { /* Can't add routes to ourself */
101 dev_put(odev);
102 return -EINVAL;
103 }
104
105 nr_node = nr_node_get(nr);
106
107 nr_neigh = nr_neigh_get_dev(ax25, dev);
108
109 /*
110 * The L2 link to a neighbour has failed in the past
111 * and now a frame comes from this neighbour. We assume
112 * it was a temporary trouble with the link and reset the
113 * routes now (and not wait for a node broadcast).
114 */
115 if (nr_neigh != NULL && nr_neigh->failed != 0 && quality == 0) {
116 struct nr_node *nr_nodet;
117 struct hlist_node *node;
118
119 spin_lock_bh(&nr_node_list_lock);
120 nr_node_for_each(nr_nodet, node, &nr_node_list) {
121 nr_node_lock(nr_nodet);
122 for (i = 0; i < nr_nodet->count; i++)
123 if (nr_nodet->routes[i].neighbour == nr_neigh)
124 if (i < nr_nodet->which)
125 nr_nodet->which = i;
126 nr_node_unlock(nr_nodet);
127 }
128 spin_unlock_bh(&nr_node_list_lock);
129 }
130
131 if (nr_neigh != NULL)
132 nr_neigh->failed = 0;
133
134 if (quality == 0 && nr_neigh != NULL && nr_node != NULL) {
135 nr_neigh_put(nr_neigh);
136 nr_node_put(nr_node);
137 return 0;
138 }
139
140 if (nr_neigh == NULL) {
141 if ((nr_neigh = kmalloc(sizeof(*nr_neigh), GFP_ATOMIC)) == NULL) {
142 if (nr_node)
143 nr_node_put(nr_node);
144 return -ENOMEM;
145 }
146
147 nr_neigh->callsign = *ax25;
148 nr_neigh->digipeat = NULL;
149 nr_neigh->ax25 = NULL;
150 nr_neigh->dev = dev;
151 nr_neigh->quality = sysctl_netrom_default_path_quality;
152 nr_neigh->locked = 0;
153 nr_neigh->count = 0;
154 nr_neigh->number = nr_neigh_no++;
155 nr_neigh->failed = 0;
156 atomic_set(&nr_neigh->refcount, 1);
157
158 if (ax25_digi != NULL && ax25_digi->ndigi > 0) {
Arnaldo Carvalho de Meloeafff862006-11-17 13:05:04 -0200159 nr_neigh->digipeat = kmemdup(ax25_digi,
160 sizeof(*ax25_digi),
161 GFP_KERNEL);
162 if (nr_neigh->digipeat == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163 kfree(nr_neigh);
164 if (nr_node)
165 nr_node_put(nr_node);
166 return -ENOMEM;
167 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 }
169
170 spin_lock_bh(&nr_neigh_list_lock);
171 hlist_add_head(&nr_neigh->neigh_node, &nr_neigh_list);
172 nr_neigh_hold(nr_neigh);
173 spin_unlock_bh(&nr_neigh_list_lock);
174 }
175
176 if (quality != 0 && ax25cmp(nr, ax25) == 0 && !nr_neigh->locked)
177 nr_neigh->quality = quality;
178
179 if (nr_node == NULL) {
180 if ((nr_node = kmalloc(sizeof(*nr_node), GFP_ATOMIC)) == NULL) {
181 if (nr_neigh)
182 nr_neigh_put(nr_neigh);
183 return -ENOMEM;
184 }
185
186 nr_node->callsign = *nr;
187 strcpy(nr_node->mnemonic, mnemonic);
188
189 nr_node->which = 0;
190 nr_node->count = 1;
191 atomic_set(&nr_node->refcount, 1);
192 spin_lock_init(&nr_node->node_lock);
193
194 nr_node->routes[0].quality = quality;
195 nr_node->routes[0].obs_count = obs_count;
196 nr_node->routes[0].neighbour = nr_neigh;
197
198 nr_neigh_hold(nr_neigh);
199 nr_neigh->count++;
200
201 spin_lock_bh(&nr_node_list_lock);
202 hlist_add_head(&nr_node->node_node, &nr_node_list);
203 /* refcount initialized at 1 */
204 spin_unlock_bh(&nr_node_list_lock);
205
206 return 0;
207 }
208 nr_node_lock(nr_node);
209
210 if (quality != 0)
211 strcpy(nr_node->mnemonic, mnemonic);
212
213 for (found = 0, i = 0; i < nr_node->count; i++) {
214 if (nr_node->routes[i].neighbour == nr_neigh) {
215 nr_node->routes[i].quality = quality;
216 nr_node->routes[i].obs_count = obs_count;
217 found = 1;
218 break;
219 }
220 }
221
222 if (!found) {
223 /* We have space at the bottom, slot it in */
224 if (nr_node->count < 3) {
225 nr_node->routes[2] = nr_node->routes[1];
226 nr_node->routes[1] = nr_node->routes[0];
227
228 nr_node->routes[0].quality = quality;
229 nr_node->routes[0].obs_count = obs_count;
230 nr_node->routes[0].neighbour = nr_neigh;
231
232 nr_node->which++;
233 nr_node->count++;
234 nr_neigh_hold(nr_neigh);
235 nr_neigh->count++;
236 } else {
237 /* It must be better than the worst */
238 if (quality > nr_node->routes[2].quality) {
239 nr_node->routes[2].neighbour->count--;
240 nr_neigh_put(nr_node->routes[2].neighbour);
241
242 if (nr_node->routes[2].neighbour->count == 0 && !nr_node->routes[2].neighbour->locked)
243 nr_remove_neigh(nr_node->routes[2].neighbour);
244
245 nr_node->routes[2].quality = quality;
246 nr_node->routes[2].obs_count = obs_count;
247 nr_node->routes[2].neighbour = nr_neigh;
248
249 nr_neigh_hold(nr_neigh);
250 nr_neigh->count++;
251 }
252 }
253 }
254
255 /* Now re-sort the routes in quality order */
256 switch (nr_node->count) {
257 case 3:
258 if (nr_node->routes[1].quality > nr_node->routes[0].quality) {
259 switch (nr_node->which) {
260 case 0: nr_node->which = 1; break;
261 case 1: nr_node->which = 0; break;
262 default: break;
263 }
264 nr_route = nr_node->routes[0];
265 nr_node->routes[0] = nr_node->routes[1];
266 nr_node->routes[1] = nr_route;
267 }
268 if (nr_node->routes[2].quality > nr_node->routes[1].quality) {
269 switch (nr_node->which) {
270 case 1: nr_node->which = 2;
271 break;
272
273 case 2: nr_node->which = 1;
274 break;
275
276 default:
277 break;
278 }
279 nr_route = nr_node->routes[1];
280 nr_node->routes[1] = nr_node->routes[2];
281 nr_node->routes[2] = nr_route;
282 }
283 case 2:
284 if (nr_node->routes[1].quality > nr_node->routes[0].quality) {
285 switch (nr_node->which) {
286 case 0: nr_node->which = 1;
287 break;
288
289 case 1: nr_node->which = 0;
290 break;
291
292 default: break;
293 }
294 nr_route = nr_node->routes[0];
295 nr_node->routes[0] = nr_node->routes[1];
296 nr_node->routes[1] = nr_route;
297 }
298 case 1:
299 break;
300 }
301
302 for (i = 0; i < nr_node->count; i++) {
303 if (nr_node->routes[i].neighbour == nr_neigh) {
304 if (i < nr_node->which)
305 nr_node->which = i;
306 break;
307 }
308 }
309
310 nr_neigh_put(nr_neigh);
311 nr_node_unlock(nr_node);
312 nr_node_put(nr_node);
313 return 0;
314}
315
316static inline void __nr_remove_node(struct nr_node *nr_node)
317{
318 hlist_del_init(&nr_node->node_node);
319 nr_node_put(nr_node);
320}
321
322#define nr_remove_node_locked(__node) \
323 __nr_remove_node(__node)
324
325static void nr_remove_node(struct nr_node *nr_node)
326{
327 spin_lock_bh(&nr_node_list_lock);
328 __nr_remove_node(nr_node);
329 spin_unlock_bh(&nr_node_list_lock);
330}
331
332static inline void __nr_remove_neigh(struct nr_neigh *nr_neigh)
333{
334 hlist_del_init(&nr_neigh->neigh_node);
335 nr_neigh_put(nr_neigh);
336}
337
338#define nr_remove_neigh_locked(__neigh) \
339 __nr_remove_neigh(__neigh)
340
341static void nr_remove_neigh(struct nr_neigh *nr_neigh)
342{
343 spin_lock_bh(&nr_neigh_list_lock);
344 __nr_remove_neigh(nr_neigh);
345 spin_unlock_bh(&nr_neigh_list_lock);
346}
347
348/*
349 * "Delete" a node. Strictly speaking remove a route to a node. The node
350 * is only deleted if no routes are left to it.
351 */
352static int nr_del_node(ax25_address *callsign, ax25_address *neighbour, struct net_device *dev)
353{
354 struct nr_node *nr_node;
355 struct nr_neigh *nr_neigh;
356 int i;
357
358 nr_node = nr_node_get(callsign);
359
360 if (nr_node == NULL)
361 return -EINVAL;
362
363 nr_neigh = nr_neigh_get_dev(neighbour, dev);
364
365 if (nr_neigh == NULL) {
366 nr_node_put(nr_node);
367 return -EINVAL;
368 }
369
370 nr_node_lock(nr_node);
371 for (i = 0; i < nr_node->count; i++) {
372 if (nr_node->routes[i].neighbour == nr_neigh) {
373 nr_neigh->count--;
374 nr_neigh_put(nr_neigh);
375
376 if (nr_neigh->count == 0 && !nr_neigh->locked)
377 nr_remove_neigh(nr_neigh);
378 nr_neigh_put(nr_neigh);
379
380 nr_node->count--;
381
382 if (nr_node->count == 0) {
383 nr_remove_node(nr_node);
384 } else {
385 switch (i) {
386 case 0:
387 nr_node->routes[0] = nr_node->routes[1];
388 case 1:
389 nr_node->routes[1] = nr_node->routes[2];
390 case 2:
391 break;
392 }
393 nr_node_put(nr_node);
394 }
395 nr_node_unlock(nr_node);
396
397 return 0;
398 }
399 }
400 nr_neigh_put(nr_neigh);
401 nr_node_unlock(nr_node);
402 nr_node_put(nr_node);
403
404 return -EINVAL;
405}
406
407/*
408 * Lock a neighbour with a quality.
409 */
Ralf Baechlec9266b92006-12-14 15:49:28 -0800410static int __must_check nr_add_neigh(ax25_address *callsign,
411 ax25_digi *ax25_digi, struct net_device *dev, unsigned int quality)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412{
413 struct nr_neigh *nr_neigh;
414
415 nr_neigh = nr_neigh_get_dev(callsign, dev);
416 if (nr_neigh) {
417 nr_neigh->quality = quality;
418 nr_neigh->locked = 1;
419 nr_neigh_put(nr_neigh);
420 return 0;
421 }
422
423 if ((nr_neigh = kmalloc(sizeof(*nr_neigh), GFP_ATOMIC)) == NULL)
424 return -ENOMEM;
425
426 nr_neigh->callsign = *callsign;
427 nr_neigh->digipeat = NULL;
428 nr_neigh->ax25 = NULL;
429 nr_neigh->dev = dev;
430 nr_neigh->quality = quality;
431 nr_neigh->locked = 1;
432 nr_neigh->count = 0;
433 nr_neigh->number = nr_neigh_no++;
434 nr_neigh->failed = 0;
435 atomic_set(&nr_neigh->refcount, 1);
436
437 if (ax25_digi != NULL && ax25_digi->ndigi > 0) {
Arnaldo Carvalho de Meloeafff862006-11-17 13:05:04 -0200438 nr_neigh->digipeat = kmemdup(ax25_digi, sizeof(*ax25_digi),
439 GFP_KERNEL);
440 if (nr_neigh->digipeat == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 kfree(nr_neigh);
442 return -ENOMEM;
443 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 }
445
446 spin_lock_bh(&nr_neigh_list_lock);
447 hlist_add_head(&nr_neigh->neigh_node, &nr_neigh_list);
448 /* refcount is initialized at 1 */
449 spin_unlock_bh(&nr_neigh_list_lock);
450
451 return 0;
452}
453
454/*
455 * "Delete" a neighbour. The neighbour is only removed if the number
456 * of nodes that may use it is zero.
457 */
458static int nr_del_neigh(ax25_address *callsign, struct net_device *dev, unsigned int quality)
459{
460 struct nr_neigh *nr_neigh;
461
462 nr_neigh = nr_neigh_get_dev(callsign, dev);
463
464 if (nr_neigh == NULL) return -EINVAL;
465
466 nr_neigh->quality = quality;
467 nr_neigh->locked = 0;
468
469 if (nr_neigh->count == 0)
470 nr_remove_neigh(nr_neigh);
471 nr_neigh_put(nr_neigh);
472
473 return 0;
474}
475
476/*
477 * Decrement the obsolescence count by one. If a route is reduced to a
478 * count of zero, remove it. Also remove any unlocked neighbours with
479 * zero nodes routing via it.
480 */
481static int nr_dec_obs(void)
482{
483 struct nr_neigh *nr_neigh;
484 struct nr_node *s;
485 struct hlist_node *node, *nodet;
486 int i;
487
488 spin_lock_bh(&nr_node_list_lock);
489 nr_node_for_each_safe(s, node, nodet, &nr_node_list) {
490 nr_node_lock(s);
491 for (i = 0; i < s->count; i++) {
492 switch (s->routes[i].obs_count) {
493 case 0: /* A locked entry */
494 break;
495
496 case 1: /* From 1 -> 0 */
497 nr_neigh = s->routes[i].neighbour;
498
499 nr_neigh->count--;
500 nr_neigh_put(nr_neigh);
501
502 if (nr_neigh->count == 0 && !nr_neigh->locked)
503 nr_remove_neigh(nr_neigh);
504
505 s->count--;
506
507 switch (i) {
508 case 0:
509 s->routes[0] = s->routes[1];
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 */
536void nr_rt_device_down(struct net_device *dev)
537{
538 struct nr_neigh *s;
539 struct hlist_node *node, *nodet, *node2, *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, node, nodet, &nr_neigh_list) {
545 if (s->dev == dev) {
546 spin_lock_bh(&nr_node_list_lock);
547 nr_node_for_each_safe(t, node2, 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 */
580static struct net_device *nr_ax25_dev_get(char *devname)
581{
582 struct net_device *dev;
583
Eric W. Biederman881d9662007-09-17 11:56:21 -0700584 if ((dev = dev_get_by_name(&init_net, devname)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 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 */
597struct net_device *nr_dev_first(void)
598{
599 struct net_device *dev, *first = NULL;
600
Eric Dumazetc6d14c82009-11-04 05:43:23 -0800601 rcu_read_lock();
602 for_each_netdev_rcu(&init_net, dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 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);
Eric Dumazetc6d14c82009-11-04 05:43:23 -0800609 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610
611 return first;
612}
613
614/*
615 * Find the NET/ROM device for the given callsign.
616 */
617struct net_device *nr_dev_get(ax25_address *addr)
618{
619 struct net_device *dev;
620
Eric Dumazetc6d14c82009-11-04 05:43:23 -0800621 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) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 dev_hold(dev);
626 goto out;
627 }
628 }
Pavel Emelianov7562f872007-05-03 15:13:45 -0700629 dev = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630out:
Eric Dumazetc6d14c82009-11-04 05:43:23 -0800631 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 return dev;
633}
634
Ralf Baechlec6ba9732009-08-17 18:05:32 -0700635static ax25_digi *nr_call_to_digi(ax25_digi *digi, int ndigis,
636 ax25_address *digipeaters)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 int i;
639
640 if (ndigis == 0)
641 return NULL;
642
643 for (i = 0; i < ndigis; i++) {
Ralf Baechlec6ba9732009-08-17 18:05:32 -0700644 digi->calls[i] = digipeaters[i];
645 digi->repeated[i] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 }
647
Ralf Baechlec6ba9732009-08-17 18:05:32 -0700648 digi->ndigi = ndigis;
649 digi->lastrepeat = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650
Ralf Baechlec6ba9732009-08-17 18:05:32 -0700651 return digi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652}
653
654/*
655 * Handle the ioctls that control the routing functions.
656 */
657int nr_rt_ioctl(unsigned int cmd, void __user *arg)
658{
659 struct nr_route_struct nr_route;
660 struct net_device *dev;
Ralf Baechlec6ba9732009-08-17 18:05:32 -0700661 ax25_digi digi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 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 ((dev = nr_ax25_dev_get(nr_route.device)) == NULL)
669 return -EINVAL;
670 if (nr_route.ndigis < 0 || nr_route.ndigis > AX25_MAX_DIGIS) {
671 dev_put(dev);
672 return -EINVAL;
673 }
674 switch (nr_route.type) {
675 case NETROM_NODE:
676 ret = nr_add_node(&nr_route.callsign,
677 nr_route.mnemonic,
678 &nr_route.neighbour,
Ralf Baechlec6ba9732009-08-17 18:05:32 -0700679 nr_call_to_digi(&digi, nr_route.ndigis,
680 nr_route.digipeaters),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 dev, nr_route.quality,
682 nr_route.obs_count);
683 break;
684 case NETROM_NEIGH:
685 ret = nr_add_neigh(&nr_route.callsign,
Ralf Baechlec6ba9732009-08-17 18:05:32 -0700686 nr_call_to_digi(&digi, nr_route.ndigis,
687 nr_route.digipeaters),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 dev, nr_route.quality);
689 break;
690 default:
691 ret = -EINVAL;
692 }
693 dev_put(dev);
694 return ret;
695
696 case SIOCDELRT:
697 if (copy_from_user(&nr_route, arg, sizeof(struct nr_route_struct)))
698 return -EFAULT;
699 if ((dev = nr_ax25_dev_get(nr_route.device)) == NULL)
700 return -EINVAL;
701 switch (nr_route.type) {
702 case NETROM_NODE:
703 ret = nr_del_node(&nr_route.callsign,
704 &nr_route.neighbour, dev);
705 break;
706 case NETROM_NEIGH:
707 ret = nr_del_neigh(&nr_route.callsign,
708 dev, nr_route.quality);
709 break;
710 default:
711 ret = -EINVAL;
712 }
713 dev_put(dev);
714 return ret;
715
716 case SIOCNRDECOBS:
717 return nr_dec_obs();
718
719 default:
720 return -EINVAL;
721 }
722
723 return 0;
724}
725
726/*
727 * A level 2 link has timed out, therefore it appears to be a poor link,
728 * then don't use that neighbour until it is reset.
729 */
730void nr_link_failed(ax25_cb *ax25, int reason)
731{
732 struct nr_neigh *s, *nr_neigh = NULL;
733 struct hlist_node *node;
734 struct nr_node *nr_node = NULL;
735
736 spin_lock_bh(&nr_neigh_list_lock);
Ralf Baechle52383672006-06-26 00:05:23 -0700737 nr_neigh_for_each(s, node, &nr_neigh_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 if (s->ax25 == ax25) {
739 nr_neigh_hold(s);
740 nr_neigh = s;
741 break;
742 }
Ralf Baechle52383672006-06-26 00:05:23 -0700743 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 spin_unlock_bh(&nr_neigh_list_lock);
745
Ralf Baechle52383672006-06-26 00:05:23 -0700746 if (nr_neigh == NULL)
747 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748
749 nr_neigh->ax25 = NULL;
750 ax25_cb_put(ax25);
751
752 if (++nr_neigh->failed < sysctl_netrom_link_fails_count) {
753 nr_neigh_put(nr_neigh);
754 return;
755 }
756 spin_lock_bh(&nr_node_list_lock);
Ralf Baechle52383672006-06-26 00:05:23 -0700757 nr_node_for_each(nr_node, node, &nr_node_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 nr_node_lock(nr_node);
Ralf Baechle52383672006-06-26 00:05:23 -0700759 if (nr_node->which < nr_node->count &&
760 nr_node->routes[nr_node->which].neighbour == nr_neigh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 nr_node->which++;
762 nr_node_unlock(nr_node);
Ralf Baechle52383672006-06-26 00:05:23 -0700763 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 spin_unlock_bh(&nr_node_list_lock);
765 nr_neigh_put(nr_neigh);
766}
767
768/*
769 * Route a frame to an appropriate AX.25 connection. A NULL ax25_cb
770 * indicates an internally generated frame.
771 */
772int nr_route_frame(struct sk_buff *skb, ax25_cb *ax25)
773{
774 ax25_address *nr_src, *nr_dest;
775 struct nr_neigh *nr_neigh;
776 struct nr_node *nr_node;
777 struct net_device *dev;
778 unsigned char *dptr;
779 ax25_cb *ax25s;
780 int ret;
781 struct sk_buff *skbn;
782
783
784 nr_src = (ax25_address *)(skb->data + 0);
785 nr_dest = (ax25_address *)(skb->data + 7);
786
Ralf Baechle58bc5742006-12-14 15:50:58 -0800787 if (ax25 != NULL) {
788 ret = nr_add_node(nr_src, "", &ax25->dest_addr, ax25->digipeat,
YOSHIFUJI Hideaki5f8f59d2007-02-09 23:25:09 +0900789 ax25->ax25_dev->dev, 0,
790 sysctl_netrom_obsolescence_count_initialiser);
Ralf Baechle58bc5742006-12-14 15:50:58 -0800791 if (ret)
792 return ret;
793 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794
795 if ((dev = nr_dev_get(nr_dest)) != NULL) { /* Its for me */
796 if (ax25 == NULL) /* Its from me */
797 ret = nr_loopback_queue(skb);
798 else
799 ret = nr_rx_frame(skb, dev);
800 dev_put(dev);
801 return ret;
802 }
803
804 if (!sysctl_netrom_routing_control && ax25 != NULL)
805 return 0;
806
807 /* Its Time-To-Live has expired */
808 if (skb->data[14] == 1) {
809 return 0;
810 }
811
812 nr_node = nr_node_get(nr_dest);
813 if (nr_node == NULL)
814 return 0;
815 nr_node_lock(nr_node);
816
817 if (nr_node->which >= nr_node->count) {
818 nr_node_unlock(nr_node);
819 nr_node_put(nr_node);
820 return 0;
821 }
822
823 nr_neigh = nr_node->routes[nr_node->which].neighbour;
824
825 if ((dev = nr_dev_first()) == NULL) {
826 nr_node_unlock(nr_node);
827 nr_node_put(nr_node);
828 return 0;
829 }
830
831 /* We are going to change the netrom headers so we should get our
832 own skb, we also did not know until now how much header space
833 we had to reserve... - RXQ */
834 if ((skbn=skb_copy_expand(skb, dev->hard_header_len, 0, GFP_ATOMIC)) == NULL) {
835 nr_node_unlock(nr_node);
836 nr_node_put(nr_node);
837 dev_put(dev);
838 return 0;
839 }
840 kfree_skb(skb);
841 skb=skbn;
842 skb->data[14]--;
843
844 dptr = skb_push(skb, 1);
845 *dptr = AX25_P_NETROM;
846
Jarek Poplawskid00c3622010-01-16 01:04:04 -0800847 ax25s = nr_neigh->ax25;
848 nr_neigh->ax25 = ax25_send_frame(skb, 256,
849 (ax25_address *)dev->dev_addr,
850 &nr_neigh->callsign,
851 nr_neigh->digipeat, nr_neigh->dev);
852 if (ax25s)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 ax25_cb_put(ax25s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854
855 dev_put(dev);
856 ret = (nr_neigh->ax25 != NULL);
857 nr_node_unlock(nr_node);
858 nr_node_put(nr_node);
Ralf Baechle58bc5742006-12-14 15:50:58 -0800859
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 return ret;
861}
862
863#ifdef CONFIG_PROC_FS
864
865static void *nr_node_start(struct seq_file *seq, loff_t *pos)
866{
YOSHIFUJI Hideaki5f8f59d2007-02-09 23:25:09 +0900867 spin_lock_bh(&nr_node_list_lock);
Li Zefan90dd7f52010-02-08 23:19:42 +0000868 return seq_hlist_start_head(&nr_node_list, *pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869}
870
871static void *nr_node_next(struct seq_file *seq, void *v, loff_t *pos)
872{
Li Zefan90dd7f52010-02-08 23:19:42 +0000873 return seq_hlist_next(v, &nr_node_list, pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874}
875
876static void nr_node_stop(struct seq_file *seq, void *v)
877{
878 spin_unlock_bh(&nr_node_list_lock);
879}
880
881static int nr_node_show(struct seq_file *seq, void *v)
882{
Ralf Baechlef75268c2005-09-06 15:49:39 -0700883 char buf[11];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 int i;
885
886 if (v == SEQ_START_TOKEN)
887 seq_puts(seq,
888 "callsign mnemonic w n qual obs neigh qual obs neigh qual obs neigh\n");
889 else {
Li Zefan90dd7f52010-02-08 23:19:42 +0000890 struct nr_node *nr_node = hlist_entry(v, struct nr_node,
891 node_node);
892
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 nr_node_lock(nr_node);
894 seq_printf(seq, "%-9s %-7s %d %d",
Ralf Baechlef75268c2005-09-06 15:49:39 -0700895 ax2asc(buf, &nr_node->callsign),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 (nr_node->mnemonic[0] == '\0') ? "*" : nr_node->mnemonic,
897 nr_node->which + 1,
898 nr_node->count);
899
900 for (i = 0; i < nr_node->count; i++) {
901 seq_printf(seq, " %3d %d %05d",
902 nr_node->routes[i].quality,
903 nr_node->routes[i].obs_count,
904 nr_node->routes[i].neighbour->number);
905 }
906 nr_node_unlock(nr_node);
907
908 seq_puts(seq, "\n");
909 }
910 return 0;
911}
912
Philippe De Muyter56b3d972007-07-10 23:07:31 -0700913static const struct seq_operations nr_node_seqops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 .start = nr_node_start,
915 .next = nr_node_next,
916 .stop = nr_node_stop,
917 .show = nr_node_show,
918};
919
920static int nr_node_info_open(struct inode *inode, struct file *file)
921{
922 return seq_open(file, &nr_node_seqops);
923}
924
Arjan van de Venda7071d2007-02-12 00:55:36 -0800925const struct file_operations nr_nodes_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 .owner = THIS_MODULE,
927 .open = nr_node_info_open,
928 .read = seq_read,
929 .llseek = seq_lseek,
930 .release = seq_release,
931};
932
933static void *nr_neigh_start(struct seq_file *seq, loff_t *pos)
934{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 spin_lock_bh(&nr_neigh_list_lock);
Li Zefan90dd7f52010-02-08 23:19:42 +0000936 return seq_hlist_start_head(&nr_neigh_list, *pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937}
938
939static void *nr_neigh_next(struct seq_file *seq, void *v, loff_t *pos)
940{
Li Zefan90dd7f52010-02-08 23:19:42 +0000941 return seq_hlist_next(v, &nr_neigh_list, pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942}
943
944static void nr_neigh_stop(struct seq_file *seq, void *v)
945{
946 spin_unlock_bh(&nr_neigh_list_lock);
947}
948
949static int nr_neigh_show(struct seq_file *seq, void *v)
950{
Ralf Baechlef75268c2005-09-06 15:49:39 -0700951 char buf[11];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 int i;
953
954 if (v == SEQ_START_TOKEN)
955 seq_puts(seq, "addr callsign dev qual lock count failed digipeaters\n");
956 else {
Li Zefan90dd7f52010-02-08 23:19:42 +0000957 struct nr_neigh *nr_neigh;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958
Li Zefan90dd7f52010-02-08 23:19:42 +0000959 nr_neigh = hlist_entry(v, struct nr_neigh, neigh_node);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 seq_printf(seq, "%05d %-9s %-4s %3d %d %3d %3d",
961 nr_neigh->number,
Ralf Baechlef75268c2005-09-06 15:49:39 -0700962 ax2asc(buf, &nr_neigh->callsign),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 nr_neigh->dev ? nr_neigh->dev->name : "???",
964 nr_neigh->quality,
965 nr_neigh->locked,
966 nr_neigh->count,
967 nr_neigh->failed);
968
969 if (nr_neigh->digipeat != NULL) {
970 for (i = 0; i < nr_neigh->digipeat->ndigi; i++)
YOSHIFUJI Hideaki5f8f59d2007-02-09 23:25:09 +0900971 seq_printf(seq, " %s",
Ralf Baechlef75268c2005-09-06 15:49:39 -0700972 ax2asc(buf, &nr_neigh->digipeat->calls[i]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 }
974
975 seq_puts(seq, "\n");
976 }
977 return 0;
978}
979
Philippe De Muyter56b3d972007-07-10 23:07:31 -0700980static const struct seq_operations nr_neigh_seqops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 .start = nr_neigh_start,
982 .next = nr_neigh_next,
983 .stop = nr_neigh_stop,
984 .show = nr_neigh_show,
985};
986
987static int nr_neigh_info_open(struct inode *inode, struct file *file)
988{
989 return seq_open(file, &nr_neigh_seqops);
990}
991
Arjan van de Venda7071d2007-02-12 00:55:36 -0800992const struct file_operations nr_neigh_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 .owner = THIS_MODULE,
994 .open = nr_neigh_info_open,
995 .read = seq_read,
996 .llseek = seq_lseek,
997 .release = seq_release,
998};
999
1000#endif
1001
1002/*
1003 * Free all memory associated with the nodes and routes lists.
1004 */
1005void __exit nr_rt_free(void)
1006{
1007 struct nr_neigh *s = NULL;
1008 struct nr_node *t = NULL;
1009 struct hlist_node *node, *nodet;
1010
1011 spin_lock_bh(&nr_neigh_list_lock);
1012 spin_lock_bh(&nr_node_list_lock);
1013 nr_node_for_each_safe(t, node, nodet, &nr_node_list) {
1014 nr_node_lock(t);
1015 nr_remove_node_locked(t);
1016 nr_node_unlock(t);
1017 }
1018 nr_neigh_for_each_safe(s, node, nodet, &nr_neigh_list) {
1019 while(s->count) {
1020 s->count--;
1021 nr_neigh_put(s);
1022 }
1023 nr_remove_neigh_locked(s);
1024 }
1025 spin_unlock_bh(&nr_node_list_lock);
1026 spin_unlock_bh(&nr_neigh_list_lock);
1027}