blob: 70ffff76a967e0f439796ec9ffde93a67cd8454e [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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#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>
Paul Gortmakerbc3b2d72011-07-15 11:47:34 -040039#include <linux/export.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070040
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) {
Joe Perchesc4855382011-07-01 09:43:10 +0000260 case 0:
261 nr_node->which = 1;
262 break;
263 case 1:
264 nr_node->which = 0;
265 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 }
267 nr_route = nr_node->routes[0];
268 nr_node->routes[0] = nr_node->routes[1];
269 nr_node->routes[1] = nr_route;
270 }
271 if (nr_node->routes[2].quality > nr_node->routes[1].quality) {
272 switch (nr_node->which) {
273 case 1: nr_node->which = 2;
274 break;
275
276 case 2: nr_node->which = 1;
277 break;
278
279 default:
280 break;
281 }
282 nr_route = nr_node->routes[1];
283 nr_node->routes[1] = nr_node->routes[2];
284 nr_node->routes[2] = nr_route;
285 }
286 case 2:
287 if (nr_node->routes[1].quality > nr_node->routes[0].quality) {
288 switch (nr_node->which) {
289 case 0: nr_node->which = 1;
290 break;
291
292 case 1: nr_node->which = 0;
293 break;
294
295 default: break;
296 }
297 nr_route = nr_node->routes[0];
298 nr_node->routes[0] = nr_node->routes[1];
299 nr_node->routes[1] = nr_route;
300 }
301 case 1:
302 break;
303 }
304
305 for (i = 0; i < nr_node->count; i++) {
306 if (nr_node->routes[i].neighbour == nr_neigh) {
307 if (i < nr_node->which)
308 nr_node->which = i;
309 break;
310 }
311 }
312
313 nr_neigh_put(nr_neigh);
314 nr_node_unlock(nr_node);
315 nr_node_put(nr_node);
316 return 0;
317}
318
319static inline void __nr_remove_node(struct nr_node *nr_node)
320{
321 hlist_del_init(&nr_node->node_node);
322 nr_node_put(nr_node);
323}
324
325#define nr_remove_node_locked(__node) \
326 __nr_remove_node(__node)
327
328static void nr_remove_node(struct nr_node *nr_node)
329{
330 spin_lock_bh(&nr_node_list_lock);
331 __nr_remove_node(nr_node);
332 spin_unlock_bh(&nr_node_list_lock);
333}
334
335static inline void __nr_remove_neigh(struct nr_neigh *nr_neigh)
336{
337 hlist_del_init(&nr_neigh->neigh_node);
338 nr_neigh_put(nr_neigh);
339}
340
341#define nr_remove_neigh_locked(__neigh) \
342 __nr_remove_neigh(__neigh)
343
344static void nr_remove_neigh(struct nr_neigh *nr_neigh)
345{
346 spin_lock_bh(&nr_neigh_list_lock);
347 __nr_remove_neigh(nr_neigh);
348 spin_unlock_bh(&nr_neigh_list_lock);
349}
350
351/*
352 * "Delete" a node. Strictly speaking remove a route to a node. The node
353 * is only deleted if no routes are left to it.
354 */
355static int nr_del_node(ax25_address *callsign, ax25_address *neighbour, struct net_device *dev)
356{
357 struct nr_node *nr_node;
358 struct nr_neigh *nr_neigh;
359 int i;
360
361 nr_node = nr_node_get(callsign);
362
363 if (nr_node == NULL)
364 return -EINVAL;
365
366 nr_neigh = nr_neigh_get_dev(neighbour, dev);
367
368 if (nr_neigh == NULL) {
369 nr_node_put(nr_node);
370 return -EINVAL;
371 }
372
373 nr_node_lock(nr_node);
374 for (i = 0; i < nr_node->count; i++) {
375 if (nr_node->routes[i].neighbour == nr_neigh) {
376 nr_neigh->count--;
377 nr_neigh_put(nr_neigh);
378
379 if (nr_neigh->count == 0 && !nr_neigh->locked)
380 nr_remove_neigh(nr_neigh);
381 nr_neigh_put(nr_neigh);
382
383 nr_node->count--;
384
385 if (nr_node->count == 0) {
386 nr_remove_node(nr_node);
387 } else {
388 switch (i) {
389 case 0:
390 nr_node->routes[0] = nr_node->routes[1];
391 case 1:
392 nr_node->routes[1] = nr_node->routes[2];
393 case 2:
394 break;
395 }
396 nr_node_put(nr_node);
397 }
398 nr_node_unlock(nr_node);
399
400 return 0;
401 }
402 }
403 nr_neigh_put(nr_neigh);
404 nr_node_unlock(nr_node);
405 nr_node_put(nr_node);
406
407 return -EINVAL;
408}
409
410/*
411 * Lock a neighbour with a quality.
412 */
Ralf Baechlec9266b92006-12-14 15:49:28 -0800413static int __must_check nr_add_neigh(ax25_address *callsign,
414 ax25_digi *ax25_digi, struct net_device *dev, unsigned int quality)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415{
416 struct nr_neigh *nr_neigh;
417
418 nr_neigh = nr_neigh_get_dev(callsign, dev);
419 if (nr_neigh) {
420 nr_neigh->quality = quality;
421 nr_neigh->locked = 1;
422 nr_neigh_put(nr_neigh);
423 return 0;
424 }
425
426 if ((nr_neigh = kmalloc(sizeof(*nr_neigh), GFP_ATOMIC)) == NULL)
427 return -ENOMEM;
428
429 nr_neigh->callsign = *callsign;
430 nr_neigh->digipeat = NULL;
431 nr_neigh->ax25 = NULL;
432 nr_neigh->dev = dev;
433 nr_neigh->quality = quality;
434 nr_neigh->locked = 1;
435 nr_neigh->count = 0;
436 nr_neigh->number = nr_neigh_no++;
437 nr_neigh->failed = 0;
438 atomic_set(&nr_neigh->refcount, 1);
439
440 if (ax25_digi != NULL && ax25_digi->ndigi > 0) {
Arnaldo Carvalho de Meloeafff862006-11-17 13:05:04 -0200441 nr_neigh->digipeat = kmemdup(ax25_digi, sizeof(*ax25_digi),
442 GFP_KERNEL);
443 if (nr_neigh->digipeat == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 kfree(nr_neigh);
445 return -ENOMEM;
446 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 }
448
449 spin_lock_bh(&nr_neigh_list_lock);
450 hlist_add_head(&nr_neigh->neigh_node, &nr_neigh_list);
451 /* refcount is initialized at 1 */
452 spin_unlock_bh(&nr_neigh_list_lock);
453
454 return 0;
455}
456
457/*
458 * "Delete" a neighbour. The neighbour is only removed if the number
459 * of nodes that may use it is zero.
460 */
461static int nr_del_neigh(ax25_address *callsign, struct net_device *dev, unsigned int quality)
462{
463 struct nr_neigh *nr_neigh;
464
465 nr_neigh = nr_neigh_get_dev(callsign, dev);
466
467 if (nr_neigh == NULL) return -EINVAL;
468
469 nr_neigh->quality = quality;
470 nr_neigh->locked = 0;
471
472 if (nr_neigh->count == 0)
473 nr_remove_neigh(nr_neigh);
474 nr_neigh_put(nr_neigh);
475
476 return 0;
477}
478
479/*
480 * Decrement the obsolescence count by one. If a route is reduced to a
481 * count of zero, remove it. Also remove any unlocked neighbours with
482 * zero nodes routing via it.
483 */
484static int nr_dec_obs(void)
485{
486 struct nr_neigh *nr_neigh;
487 struct nr_node *s;
488 struct hlist_node *node, *nodet;
489 int i;
490
491 spin_lock_bh(&nr_node_list_lock);
492 nr_node_for_each_safe(s, node, nodet, &nr_node_list) {
493 nr_node_lock(s);
494 for (i = 0; i < s->count; i++) {
495 switch (s->routes[i].obs_count) {
496 case 0: /* A locked entry */
497 break;
498
499 case 1: /* From 1 -> 0 */
500 nr_neigh = s->routes[i].neighbour;
501
502 nr_neigh->count--;
503 nr_neigh_put(nr_neigh);
504
505 if (nr_neigh->count == 0 && !nr_neigh->locked)
506 nr_remove_neigh(nr_neigh);
507
508 s->count--;
509
510 switch (i) {
Joe Perchesc4855382011-07-01 09:43:10 +0000511 case 0:
512 s->routes[0] = s->routes[1];
513 /* Fallthrough */
514 case 1:
515 s->routes[1] = s->routes[2];
516 case 2:
517 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 }
519 break;
520
521 default:
522 s->routes[i].obs_count--;
523 break;
524
525 }
526 }
527
528 if (s->count <= 0)
529 nr_remove_node_locked(s);
530 nr_node_unlock(s);
531 }
532 spin_unlock_bh(&nr_node_list_lock);
533
534 return 0;
535}
536
537/*
538 * A device has been removed. Remove its routes and neighbours.
539 */
540void nr_rt_device_down(struct net_device *dev)
541{
542 struct nr_neigh *s;
543 struct hlist_node *node, *nodet, *node2, *node2t;
544 struct nr_node *t;
545 int i;
546
547 spin_lock_bh(&nr_neigh_list_lock);
548 nr_neigh_for_each_safe(s, node, nodet, &nr_neigh_list) {
549 if (s->dev == dev) {
550 spin_lock_bh(&nr_node_list_lock);
551 nr_node_for_each_safe(t, node2, node2t, &nr_node_list) {
552 nr_node_lock(t);
553 for (i = 0; i < t->count; i++) {
554 if (t->routes[i].neighbour == s) {
555 t->count--;
556
557 switch (i) {
558 case 0:
559 t->routes[0] = t->routes[1];
560 case 1:
561 t->routes[1] = t->routes[2];
562 case 2:
563 break;
564 }
565 }
566 }
567
568 if (t->count <= 0)
569 nr_remove_node_locked(t);
570 nr_node_unlock(t);
571 }
572 spin_unlock_bh(&nr_node_list_lock);
573
574 nr_remove_neigh_locked(s);
575 }
576 }
577 spin_unlock_bh(&nr_neigh_list_lock);
578}
579
580/*
581 * Check that the device given is a valid AX.25 interface that is "up".
582 * Or a valid ethernet interface with an AX.25 callsign binding.
583 */
584static struct net_device *nr_ax25_dev_get(char *devname)
585{
586 struct net_device *dev;
587
Eric W. Biederman881d9662007-09-17 11:56:21 -0700588 if ((dev = dev_get_by_name(&init_net, devname)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 return NULL;
590
591 if ((dev->flags & IFF_UP) && dev->type == ARPHRD_AX25)
592 return dev;
593
594 dev_put(dev);
595 return NULL;
596}
597
598/*
599 * Find the first active NET/ROM device, usually "nr0".
600 */
601struct net_device *nr_dev_first(void)
602{
603 struct net_device *dev, *first = NULL;
604
Eric Dumazetc6d14c82009-11-04 05:43:23 -0800605 rcu_read_lock();
606 for_each_netdev_rcu(&init_net, dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM)
608 if (first == NULL || strncmp(dev->name, first->name, 3) < 0)
609 first = dev;
610 }
611 if (first)
612 dev_hold(first);
Eric Dumazetc6d14c82009-11-04 05:43:23 -0800613 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614
615 return first;
616}
617
618/*
619 * Find the NET/ROM device for the given callsign.
620 */
621struct net_device *nr_dev_get(ax25_address *addr)
622{
623 struct net_device *dev;
624
Eric Dumazetc6d14c82009-11-04 05:43:23 -0800625 rcu_read_lock();
626 for_each_netdev_rcu(&init_net, dev) {
627 if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM &&
628 ax25cmp(addr, (ax25_address *)dev->dev_addr) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 dev_hold(dev);
630 goto out;
631 }
632 }
Pavel Emelianov7562f872007-05-03 15:13:45 -0700633 dev = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634out:
Eric Dumazetc6d14c82009-11-04 05:43:23 -0800635 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 return dev;
637}
638
Ralf Baechlec6ba9732009-08-17 18:05:32 -0700639static ax25_digi *nr_call_to_digi(ax25_digi *digi, int ndigis,
640 ax25_address *digipeaters)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 int i;
643
644 if (ndigis == 0)
645 return NULL;
646
647 for (i = 0; i < ndigis; i++) {
Ralf Baechlec6ba9732009-08-17 18:05:32 -0700648 digi->calls[i] = digipeaters[i];
649 digi->repeated[i] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 }
651
Ralf Baechlec6ba9732009-08-17 18:05:32 -0700652 digi->ndigi = ndigis;
653 digi->lastrepeat = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654
Ralf Baechlec6ba9732009-08-17 18:05:32 -0700655 return digi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656}
657
658/*
659 * Handle the ioctls that control the routing functions.
660 */
661int nr_rt_ioctl(unsigned int cmd, void __user *arg)
662{
663 struct nr_route_struct nr_route;
664 struct net_device *dev;
Ralf Baechlec6ba9732009-08-17 18:05:32 -0700665 ax25_digi digi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 int ret;
667
668 switch (cmd) {
669 case SIOCADDRT:
670 if (copy_from_user(&nr_route, arg, sizeof(struct nr_route_struct)))
671 return -EFAULT;
Ralf Baechle10cae1c2011-11-24 23:09:00 +0000672 if (nr_route.ndigis > AX25_MAX_DIGIS)
673 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 if ((dev = nr_ax25_dev_get(nr_route.device)) == NULL)
675 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 switch (nr_route.type) {
677 case NETROM_NODE:
Ralf Baechleac1a1de2011-11-24 23:08:49 +0000678 if (strnlen(nr_route.mnemonic, 7) == 7) {
679 ret = -EINVAL;
680 break;
681 }
682
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 ret = nr_add_node(&nr_route.callsign,
684 nr_route.mnemonic,
685 &nr_route.neighbour,
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 nr_route.obs_count);
690 break;
691 case NETROM_NEIGH:
692 ret = nr_add_neigh(&nr_route.callsign,
Ralf Baechlec6ba9732009-08-17 18:05:32 -0700693 nr_call_to_digi(&digi, nr_route.ndigis,
694 nr_route.digipeaters),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 dev, nr_route.quality);
696 break;
697 default:
698 ret = -EINVAL;
699 }
700 dev_put(dev);
701 return ret;
702
703 case SIOCDELRT:
704 if (copy_from_user(&nr_route, arg, sizeof(struct nr_route_struct)))
705 return -EFAULT;
706 if ((dev = nr_ax25_dev_get(nr_route.device)) == NULL)
707 return -EINVAL;
708 switch (nr_route.type) {
709 case NETROM_NODE:
710 ret = nr_del_node(&nr_route.callsign,
711 &nr_route.neighbour, dev);
712 break;
713 case NETROM_NEIGH:
714 ret = nr_del_neigh(&nr_route.callsign,
715 dev, nr_route.quality);
716 break;
717 default:
718 ret = -EINVAL;
719 }
720 dev_put(dev);
721 return ret;
722
723 case SIOCNRDECOBS:
724 return nr_dec_obs();
725
726 default:
727 return -EINVAL;
728 }
729
730 return 0;
731}
732
733/*
734 * A level 2 link has timed out, therefore it appears to be a poor link,
735 * then don't use that neighbour until it is reset.
736 */
737void nr_link_failed(ax25_cb *ax25, int reason)
738{
739 struct nr_neigh *s, *nr_neigh = NULL;
740 struct hlist_node *node;
741 struct nr_node *nr_node = NULL;
742
743 spin_lock_bh(&nr_neigh_list_lock);
Ralf Baechle52383672006-06-26 00:05:23 -0700744 nr_neigh_for_each(s, node, &nr_neigh_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 if (s->ax25 == ax25) {
746 nr_neigh_hold(s);
747 nr_neigh = s;
748 break;
749 }
Ralf Baechle52383672006-06-26 00:05:23 -0700750 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 spin_unlock_bh(&nr_neigh_list_lock);
752
Ralf Baechle52383672006-06-26 00:05:23 -0700753 if (nr_neigh == NULL)
754 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755
756 nr_neigh->ax25 = NULL;
757 ax25_cb_put(ax25);
758
759 if (++nr_neigh->failed < sysctl_netrom_link_fails_count) {
760 nr_neigh_put(nr_neigh);
761 return;
762 }
763 spin_lock_bh(&nr_node_list_lock);
Ralf Baechle52383672006-06-26 00:05:23 -0700764 nr_node_for_each(nr_node, node, &nr_node_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 nr_node_lock(nr_node);
Ralf Baechle52383672006-06-26 00:05:23 -0700766 if (nr_node->which < nr_node->count &&
767 nr_node->routes[nr_node->which].neighbour == nr_neigh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 nr_node->which++;
769 nr_node_unlock(nr_node);
Ralf Baechle52383672006-06-26 00:05:23 -0700770 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 spin_unlock_bh(&nr_node_list_lock);
772 nr_neigh_put(nr_neigh);
773}
774
775/*
776 * Route a frame to an appropriate AX.25 connection. A NULL ax25_cb
777 * indicates an internally generated frame.
778 */
779int nr_route_frame(struct sk_buff *skb, ax25_cb *ax25)
780{
781 ax25_address *nr_src, *nr_dest;
782 struct nr_neigh *nr_neigh;
783 struct nr_node *nr_node;
784 struct net_device *dev;
785 unsigned char *dptr;
786 ax25_cb *ax25s;
787 int ret;
788 struct sk_buff *skbn;
789
790
791 nr_src = (ax25_address *)(skb->data + 0);
792 nr_dest = (ax25_address *)(skb->data + 7);
793
Ralf Baechle58bc5742006-12-14 15:50:58 -0800794 if (ax25 != NULL) {
795 ret = nr_add_node(nr_src, "", &ax25->dest_addr, ax25->digipeat,
YOSHIFUJI Hideaki5f8f59d2007-02-09 23:25:09 +0900796 ax25->ax25_dev->dev, 0,
797 sysctl_netrom_obsolescence_count_initialiser);
Ralf Baechle58bc5742006-12-14 15:50:58 -0800798 if (ret)
799 return ret;
800 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801
802 if ((dev = nr_dev_get(nr_dest)) != NULL) { /* Its for me */
803 if (ax25 == NULL) /* Its from me */
804 ret = nr_loopback_queue(skb);
805 else
806 ret = nr_rx_frame(skb, dev);
807 dev_put(dev);
808 return ret;
809 }
810
811 if (!sysctl_netrom_routing_control && ax25 != NULL)
812 return 0;
813
814 /* Its Time-To-Live has expired */
815 if (skb->data[14] == 1) {
816 return 0;
817 }
818
819 nr_node = nr_node_get(nr_dest);
820 if (nr_node == NULL)
821 return 0;
822 nr_node_lock(nr_node);
823
824 if (nr_node->which >= nr_node->count) {
825 nr_node_unlock(nr_node);
826 nr_node_put(nr_node);
827 return 0;
828 }
829
830 nr_neigh = nr_node->routes[nr_node->which].neighbour;
831
832 if ((dev = nr_dev_first()) == NULL) {
833 nr_node_unlock(nr_node);
834 nr_node_put(nr_node);
835 return 0;
836 }
837
838 /* We are going to change the netrom headers so we should get our
839 own skb, we also did not know until now how much header space
840 we had to reserve... - RXQ */
841 if ((skbn=skb_copy_expand(skb, dev->hard_header_len, 0, GFP_ATOMIC)) == NULL) {
842 nr_node_unlock(nr_node);
843 nr_node_put(nr_node);
844 dev_put(dev);
845 return 0;
846 }
847 kfree_skb(skb);
848 skb=skbn;
849 skb->data[14]--;
850
851 dptr = skb_push(skb, 1);
852 *dptr = AX25_P_NETROM;
853
Jarek Poplawskid00c3622010-01-16 01:04:04 -0800854 ax25s = nr_neigh->ax25;
855 nr_neigh->ax25 = ax25_send_frame(skb, 256,
856 (ax25_address *)dev->dev_addr,
857 &nr_neigh->callsign,
858 nr_neigh->digipeat, nr_neigh->dev);
859 if (ax25s)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 ax25_cb_put(ax25s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861
862 dev_put(dev);
863 ret = (nr_neigh->ax25 != NULL);
864 nr_node_unlock(nr_node);
865 nr_node_put(nr_node);
Ralf Baechle58bc5742006-12-14 15:50:58 -0800866
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 return ret;
868}
869
870#ifdef CONFIG_PROC_FS
871
872static void *nr_node_start(struct seq_file *seq, loff_t *pos)
873{
YOSHIFUJI Hideaki5f8f59d2007-02-09 23:25:09 +0900874 spin_lock_bh(&nr_node_list_lock);
Li Zefan90dd7f52010-02-08 23:19:42 +0000875 return seq_hlist_start_head(&nr_node_list, *pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876}
877
878static void *nr_node_next(struct seq_file *seq, void *v, loff_t *pos)
879{
Li Zefan90dd7f52010-02-08 23:19:42 +0000880 return seq_hlist_next(v, &nr_node_list, pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881}
882
883static void nr_node_stop(struct seq_file *seq, void *v)
884{
885 spin_unlock_bh(&nr_node_list_lock);
886}
887
888static int nr_node_show(struct seq_file *seq, void *v)
889{
Ralf Baechlef75268c2005-09-06 15:49:39 -0700890 char buf[11];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 int i;
892
893 if (v == SEQ_START_TOKEN)
894 seq_puts(seq,
895 "callsign mnemonic w n qual obs neigh qual obs neigh qual obs neigh\n");
896 else {
Li Zefan90dd7f52010-02-08 23:19:42 +0000897 struct nr_node *nr_node = hlist_entry(v, struct nr_node,
898 node_node);
899
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 nr_node_lock(nr_node);
901 seq_printf(seq, "%-9s %-7s %d %d",
Ralf Baechlef75268c2005-09-06 15:49:39 -0700902 ax2asc(buf, &nr_node->callsign),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 (nr_node->mnemonic[0] == '\0') ? "*" : nr_node->mnemonic,
904 nr_node->which + 1,
905 nr_node->count);
906
907 for (i = 0; i < nr_node->count; i++) {
908 seq_printf(seq, " %3d %d %05d",
909 nr_node->routes[i].quality,
910 nr_node->routes[i].obs_count,
911 nr_node->routes[i].neighbour->number);
912 }
913 nr_node_unlock(nr_node);
914
915 seq_puts(seq, "\n");
916 }
917 return 0;
918}
919
Philippe De Muyter56b3d972007-07-10 23:07:31 -0700920static const struct seq_operations nr_node_seqops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 .start = nr_node_start,
922 .next = nr_node_next,
923 .stop = nr_node_stop,
924 .show = nr_node_show,
925};
926
927static int nr_node_info_open(struct inode *inode, struct file *file)
928{
929 return seq_open(file, &nr_node_seqops);
930}
931
Arjan van de Venda7071d2007-02-12 00:55:36 -0800932const struct file_operations nr_nodes_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 .owner = THIS_MODULE,
934 .open = nr_node_info_open,
935 .read = seq_read,
936 .llseek = seq_lseek,
937 .release = seq_release,
938};
939
940static void *nr_neigh_start(struct seq_file *seq, loff_t *pos)
941{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 spin_lock_bh(&nr_neigh_list_lock);
Li Zefan90dd7f52010-02-08 23:19:42 +0000943 return seq_hlist_start_head(&nr_neigh_list, *pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944}
945
946static void *nr_neigh_next(struct seq_file *seq, void *v, loff_t *pos)
947{
Li Zefan90dd7f52010-02-08 23:19:42 +0000948 return seq_hlist_next(v, &nr_neigh_list, pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949}
950
951static void nr_neigh_stop(struct seq_file *seq, void *v)
952{
953 spin_unlock_bh(&nr_neigh_list_lock);
954}
955
956static int nr_neigh_show(struct seq_file *seq, void *v)
957{
Ralf Baechlef75268c2005-09-06 15:49:39 -0700958 char buf[11];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959 int i;
960
961 if (v == SEQ_START_TOKEN)
962 seq_puts(seq, "addr callsign dev qual lock count failed digipeaters\n");
963 else {
Li Zefan90dd7f52010-02-08 23:19:42 +0000964 struct nr_neigh *nr_neigh;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965
Li Zefan90dd7f52010-02-08 23:19:42 +0000966 nr_neigh = hlist_entry(v, struct nr_neigh, neigh_node);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 seq_printf(seq, "%05d %-9s %-4s %3d %d %3d %3d",
968 nr_neigh->number,
Ralf Baechlef75268c2005-09-06 15:49:39 -0700969 ax2asc(buf, &nr_neigh->callsign),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970 nr_neigh->dev ? nr_neigh->dev->name : "???",
971 nr_neigh->quality,
972 nr_neigh->locked,
973 nr_neigh->count,
974 nr_neigh->failed);
975
976 if (nr_neigh->digipeat != NULL) {
977 for (i = 0; i < nr_neigh->digipeat->ndigi; i++)
YOSHIFUJI Hideaki5f8f59d2007-02-09 23:25:09 +0900978 seq_printf(seq, " %s",
Ralf Baechlef75268c2005-09-06 15:49:39 -0700979 ax2asc(buf, &nr_neigh->digipeat->calls[i]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 }
981
982 seq_puts(seq, "\n");
983 }
984 return 0;
985}
986
Philippe De Muyter56b3d972007-07-10 23:07:31 -0700987static const struct seq_operations nr_neigh_seqops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 .start = nr_neigh_start,
989 .next = nr_neigh_next,
990 .stop = nr_neigh_stop,
991 .show = nr_neigh_show,
992};
993
994static int nr_neigh_info_open(struct inode *inode, struct file *file)
995{
996 return seq_open(file, &nr_neigh_seqops);
997}
998
Arjan van de Venda7071d2007-02-12 00:55:36 -0800999const struct file_operations nr_neigh_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 .owner = THIS_MODULE,
1001 .open = nr_neigh_info_open,
1002 .read = seq_read,
1003 .llseek = seq_lseek,
1004 .release = seq_release,
1005};
1006
1007#endif
1008
1009/*
1010 * Free all memory associated with the nodes and routes lists.
1011 */
1012void __exit nr_rt_free(void)
1013{
1014 struct nr_neigh *s = NULL;
1015 struct nr_node *t = NULL;
1016 struct hlist_node *node, *nodet;
1017
1018 spin_lock_bh(&nr_neigh_list_lock);
1019 spin_lock_bh(&nr_node_list_lock);
1020 nr_node_for_each_safe(t, node, nodet, &nr_node_list) {
1021 nr_node_lock(t);
1022 nr_remove_node_locked(t);
1023 nr_node_unlock(t);
1024 }
1025 nr_neigh_for_each_safe(s, node, nodet, &nr_neigh_list) {
1026 while(s->count) {
1027 s->count--;
1028 nr_neigh_put(s);
1029 }
1030 nr_remove_neigh_locked(s);
1031 }
1032 spin_unlock_bh(&nr_node_list_lock);
1033 spin_unlock_bh(&nr_neigh_list_lock);
1034}