11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License as published by
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the Free Software Foundation; either version 2 of the License, or
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (at your option) any later version.
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) Steven Whitehouse GW7RRM (stevew@acm.org)
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) Hans-Joachim Hetscher DD8NE (dd8ne@bnv-bamberg.de)
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) Frederic Rible F1OAT (frible@teaser.fr)
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
144fc268d24ceb9f4150777c1b5b2b8e6214e56b2bRandy Dunlap
154fc268d24ceb9f4150777c1b5b2b8e6214e56b2bRandy Dunlap#include <linux/capability.h>
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h>
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/socket.h>
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/timer.h>
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/in.h>
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sched.h>
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h>
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sockios.h>
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/net.h>
265a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/ax25.h>
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/inet.h>
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h>
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/if_arp.h>
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/skbuff.h>
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h>
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/sock.h>
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h>
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fcntl.h>
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h>
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/seq_file.h>
40bc3b2d7fb9b014d75ebb79ba371a763dbab5e8cfPaul Gortmaker#include <linux/export.h>
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ax25_route *ax25_route_list;
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEFINE_RWLOCK(ax25_route_lock);
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid ax25_rt_device_down(struct net_device *dev)
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_route *s, *t, *ax25_rt;
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
494de211f1a279275c6c67d6e9b6b25513e46b0bb9Jarek Poplawski	write_lock_bh(&ax25_route_lock);
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_rt = ax25_route_list;
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (ax25_rt != NULL) {
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		s       = ax25_rt;
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ax25_rt = ax25_rt->next;
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (s->dev == dev) {
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ax25_route_list == s) {
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ax25_route_list = s->next;
58a51482bde22f99c63fbbb57d5d46cc666384e379Jesper Juhl				kfree(s->digipeat);
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				kfree(s);
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				for (t = ax25_route_list; t != NULL; t = t->next) {
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (t->next == s) {
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						t->next = s->next;
64a51482bde22f99c63fbbb57d5d46cc666384e379Jesper Juhl						kfree(s->digipeat);
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						kfree(s);
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						break;
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					}
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
724de211f1a279275c6c67d6e9b6b25513e46b0bb9Jarek Poplawski	write_unlock_bh(&ax25_route_lock);
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
75c9266b99e2def0a456766220df09713f8e765891Ralf Baechlestatic int __must_check ax25_rt_add(struct ax25_routes_struct *route)
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_route *ax25_rt;
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_dev *ax25_dev;
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((ax25_dev = ax25_addr_ax25dev(&route->port_addr)) == NULL)
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (route->digi_count > AX25_MAX_DIGIS)
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
864de211f1a279275c6c67d6e9b6b25513e46b0bb9Jarek Poplawski	write_lock_bh(&ax25_route_lock);
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_rt = ax25_route_list;
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (ax25_rt != NULL) {
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ax25cmp(&ax25_rt->callsign, &route->dest_addr) == 0 &&
91528930b91ee89a05a6264629cf99109652c19ca8YOSHIFUJI Hideaki			    ax25_rt->dev == ax25_dev->dev) {
92a51482bde22f99c63fbbb57d5d46cc666384e379Jesper Juhl			kfree(ax25_rt->digipeat);
93a51482bde22f99c63fbbb57d5d46cc666384e379Jesper Juhl			ax25_rt->digipeat = NULL;
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (route->digi_count != 0) {
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
964de211f1a279275c6c67d6e9b6b25513e46b0bb9Jarek Poplawski					write_unlock_bh(&ax25_route_lock);
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return -ENOMEM;
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ax25_rt->digipeat->lastrepeat = -1;
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ax25_rt->digipeat->ndigi      = route->digi_count;
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				for (i = 0; i < route->digi_count; i++) {
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					ax25_rt->digipeat->repeated[i] = 0;
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					ax25_rt->digipeat->calls[i]    = route->digi_addr[i];
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
1064de211f1a279275c6c67d6e9b6b25513e46b0bb9Jarek Poplawski			write_unlock_bh(&ax25_route_lock);
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ax25_rt = ax25_rt->next;
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((ax25_rt = kmalloc(sizeof(ax25_route), GFP_ATOMIC)) == NULL) {
1134de211f1a279275c6c67d6e9b6b25513e46b0bb9Jarek Poplawski		write_unlock_bh(&ax25_route_lock);
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
117006f68b84fe19fc5015a8cf838a10d75f91f0218Ralf Baechle	atomic_set(&ax25_rt->refcount, 1);
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_rt->callsign     = route->dest_addr;
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_rt->dev          = ax25_dev->dev;
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_rt->digipeat     = NULL;
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_rt->ip_mode      = ' ';
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (route->digi_count != 0) {
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
1244de211f1a279275c6c67d6e9b6b25513e46b0bb9Jarek Poplawski			write_unlock_bh(&ax25_route_lock);
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kfree(ax25_rt);
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENOMEM;
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ax25_rt->digipeat->lastrepeat = -1;
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ax25_rt->digipeat->ndigi      = route->digi_count;
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < route->digi_count; i++) {
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ax25_rt->digipeat->repeated[i] = 0;
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ax25_rt->digipeat->calls[i]    = route->digi_addr[i];
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_rt->next   = ax25_route_list;
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_route_list = ax25_rt;
1374de211f1a279275c6c67d6e9b6b25513e46b0bb9Jarek Poplawski	write_unlock_bh(&ax25_route_lock);
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
142006f68b84fe19fc5015a8cf838a10d75f91f0218Ralf Baechlevoid __ax25_put_route(ax25_route *ax25_rt)
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
144006f68b84fe19fc5015a8cf838a10d75f91f0218Ralf Baechle	kfree(ax25_rt->digipeat);
145006f68b84fe19fc5015a8cf838a10d75f91f0218Ralf Baechle	kfree(ax25_rt);
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ax25_rt_del(struct ax25_routes_struct *route)
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_route *s, *t, *ax25_rt;
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_dev *ax25_dev;
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((ax25_dev = ax25_addr_ax25dev(&route->port_addr)) == NULL)
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1564de211f1a279275c6c67d6e9b6b25513e46b0bb9Jarek Poplawski	write_lock_bh(&ax25_route_lock);
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_rt = ax25_route_list;
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (ax25_rt != NULL) {
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		s       = ax25_rt;
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ax25_rt = ax25_rt->next;
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (s->dev == ax25_dev->dev &&
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    ax25cmp(&route->dest_addr, &s->callsign) == 0) {
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ax25_route_list == s) {
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ax25_route_list = s->next;
166006f68b84fe19fc5015a8cf838a10d75f91f0218Ralf Baechle				ax25_put_route(s);
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				for (t = ax25_route_list; t != NULL; t = t->next) {
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (t->next == s) {
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						t->next = s->next;
171006f68b84fe19fc5015a8cf838a10d75f91f0218Ralf Baechle						ax25_put_route(s);
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						break;
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					}
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1784de211f1a279275c6c67d6e9b6b25513e46b0bb9Jarek Poplawski	write_unlock_bh(&ax25_route_lock);
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ax25_rt_opt(struct ax25_route_opt_struct *rt_option)
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_route *ax25_rt;
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_dev *ax25_dev;
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = 0;
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((ax25_dev = ax25_addr_ax25dev(&rt_option->port_addr)) == NULL)
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1924de211f1a279275c6c67d6e9b6b25513e46b0bb9Jarek Poplawski	write_lock_bh(&ax25_route_lock);
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_rt = ax25_route_list;
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (ax25_rt != NULL) {
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ax25_rt->dev == ax25_dev->dev &&
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    ax25cmp(&rt_option->dest_addr, &ax25_rt->callsign) == 0) {
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			switch (rt_option->cmd) {
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case AX25_SET_RT_IPMODE:
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				switch (rt_option->arg) {
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				case ' ':
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				case 'D':
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				case 'V':
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					ax25_rt->ip_mode = rt_option->arg;
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					break;
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				default:
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					err = -EINVAL;
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					goto out;
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			default:
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				err = -EINVAL;
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto out;
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ax25_rt = ax25_rt->next;
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout:
2204de211f1a279275c6c67d6e9b6b25513e46b0bb9Jarek Poplawski	write_unlock_bh(&ax25_route_lock);
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint ax25_rt_ioctl(unsigned int cmd, void __user *arg)
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ax25_route_opt_struct rt_option;
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ax25_routes_struct route;
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cmd) {
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SIOCADDRT:
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (copy_from_user(&route, arg, sizeof(route)))
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EFAULT;
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ax25_rt_add(&route);
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SIOCDELRT:
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (copy_from_user(&route, arg, sizeof(route)))
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EFAULT;
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ax25_rt_del(&route);
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SIOCAX25OPTRT:
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (copy_from_user(&rt_option, arg, sizeof(rt_option)))
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EFAULT;
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ax25_rt_opt(&rt_option);
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PROC_FS
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void *ax25_rt_seq_start(struct seq_file *seq, loff_t *pos)
253f16f3026db6fa63cbb0f4a37833562aa999c93e5Eric Dumazet	__acquires(ax25_route_lock)
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ax25_route *ax25_rt;
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i = 1;
257528930b91ee89a05a6264629cf99109652c19ca8YOSHIFUJI Hideaki
258528930b91ee89a05a6264629cf99109652c19ca8YOSHIFUJI Hideaki	read_lock(&ax25_route_lock);
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (*pos == 0)
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return SEQ_START_TOKEN;
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (ax25_rt = ax25_route_list; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (i == *pos)
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return ax25_rt;
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		++i;
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return NULL;
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void *ax25_rt_seq_next(struct seq_file *seq, void *v, loff_t *pos)
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	++*pos;
274528930b91ee89a05a6264629cf99109652c19ca8YOSHIFUJI Hideaki	return (v == SEQ_START_TOKEN) ? ax25_route_list :
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		((struct ax25_route *) v)->next;
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ax25_rt_seq_stop(struct seq_file *seq, void *v)
279f16f3026db6fa63cbb0f4a37833562aa999c93e5Eric Dumazet	__releases(ax25_route_lock)
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	read_unlock(&ax25_route_lock);
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ax25_rt_seq_show(struct seq_file *seq, void *v)
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
286f75268cd6cbd24e6c70ff1390f4de5d0bb618539Ralf Baechle	char buf[11];
287f75268cd6cbd24e6c70ff1390f4de5d0bb618539Ralf Baechle
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (v == SEQ_START_TOKEN)
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		seq_puts(seq, "callsign  dev  mode digipeaters\n");
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else {
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct ax25_route *ax25_rt = v;
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		const char *callsign;
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int i;
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0)
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			callsign = "default";
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
298f75268cd6cbd24e6c70ff1390f4de5d0bb618539Ralf Baechle			callsign = ax2asc(buf, &ax25_rt->callsign);
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		seq_printf(seq, "%-9s %-4s",
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			callsign,
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ax25_rt->dev ? ax25_rt->dev->name : "???");
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (ax25_rt->ip_mode) {
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 'V':
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			seq_puts(seq, "   vc");
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 'D':
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			seq_puts(seq, "   dg");
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			seq_puts(seq, "    *");
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ax25_rt->digipeat != NULL)
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (i = 0; i < ax25_rt->digipeat->ndigi; i++)
318f75268cd6cbd24e6c70ff1390f4de5d0bb618539Ralf Baechle				seq_printf(seq, " %s",
319f75268cd6cbd24e6c70ff1390f4de5d0bb618539Ralf Baechle				     ax2asc(buf, &ax25_rt->digipeat->calls[i]));
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		seq_puts(seq, "\n");
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
32656b3d975bbce65f655c5612b4822da671f9fd9b2Philippe De Muyterstatic const struct seq_operations ax25_rt_seqops = {
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.start = ax25_rt_seq_start,
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.next = ax25_rt_seq_next,
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.stop = ax25_rt_seq_stop,
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.show = ax25_rt_seq_show,
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ax25_rt_info_open(struct inode *inode, struct file *file)
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return seq_open(file, &ax25_rt_seqops);
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3389a32144e9d7b4e21341174b1a83b82a82353be86Arjan van de Venconst struct file_operations ax25_route_fops = {
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.owner = THIS_MODULE,
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.open = ax25_rt_info_open,
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.read = seq_read,
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.llseek = seq_lseek,
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.release = seq_release,
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Find AX.25 route
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
3513f072310d0ca85891323e9d325c37c76de389387Ralf Baechle *	Only routes with a reference count of zero can be destroyed.
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
353006f68b84fe19fc5015a8cf838a10d75f91f0218Ralf Baechleax25_route *ax25_get_route(ax25_address *addr, struct net_device *dev)
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_route *ax25_spe_rt = NULL;
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_route *ax25_def_rt = NULL;
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_route *ax25_rt;
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	read_lock(&ax25_route_lock);
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *	Bind to the physical interface we heard them on, or the default
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *	route if none is found;
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (ax25_rt = ax25_route_list; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (dev == NULL) {
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ax25cmp(&ax25_rt->callsign, addr) == 0 && ax25_rt->dev != NULL)
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ax25_spe_rt = ax25_rt;
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0 && ax25_rt->dev != NULL)
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ax25_def_rt = ax25_rt;
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ax25cmp(&ax25_rt->callsign, addr) == 0 && ax25_rt->dev == dev)
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ax25_spe_rt = ax25_rt;
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0 && ax25_rt->dev == dev)
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ax25_def_rt = ax25_rt;
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_rt = ax25_def_rt;
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ax25_spe_rt != NULL)
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ax25_rt = ax25_spe_rt;
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ax25_rt != NULL)
383006f68b84fe19fc5015a8cf838a10d75f91f0218Ralf Baechle		ax25_hold_route(ax25_rt);
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	read_unlock(&ax25_route_lock);
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ax25_rt;
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Adjust path: If you specify a default route and want to connect
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      a target on the digipeater path but w/o having a special route
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	set before, the path has to be truncated from your target on.
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void ax25_adjust_path(ax25_address *addr, ax25_digi *digipeat)
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int k;
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (k = 0; k < digipeat->ndigi; k++) {
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ax25cmp(addr, &digipeat->calls[k]) == 0)
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	digipeat->ndigi = k;
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Find which interface to use.
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint ax25_rt_autobind(ax25_cb *ax25, ax25_address *addr)
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
41301d7dd0e9f8c5f1888619d2649c7da389232b408Ralf Baechle	ax25_uid_assoc *user;
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_route *ax25_rt;
415b3d18f15092a7db2f229cd7bc69fc40eac0774f4Julia Lawall	int err = 0;
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((ax25_rt = ax25_get_route(addr, NULL)) == NULL)
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EHOSTUNREACH;
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((ax25->ax25_dev = ax25_dev_ax25dev(ax25_rt->dev)) == NULL) {
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = -EHOSTUNREACH;
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto put;
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
425734004072e05ae81c3cdd0a04ee37868fb09b71eDavid Howells	user = ax25_findbyuid(current_euid());
42601d7dd0e9f8c5f1888619d2649c7da389232b408Ralf Baechle	if (user) {
42701d7dd0e9f8c5f1888619d2649c7da389232b408Ralf Baechle		ax25->source_addr = user->call;
42801d7dd0e9f8c5f1888619d2649c7da389232b408Ralf Baechle		ax25_uid_put(user);
42901d7dd0e9f8c5f1888619d2649c7da389232b408Ralf Baechle	} else {
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ax25_uid_policy && !capable(CAP_NET_BIND_SERVICE)) {
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err = -EPERM;
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto put;
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
43401d7dd0e9f8c5f1888619d2649c7da389232b408Ralf Baechle		ax25->source_addr = *(ax25_address *)ax25->ax25_dev->dev->dev_addr;
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ax25_rt->digipeat != NULL) {
4380459d70add3f7ca5d433d4b2334cc6ec9ddab05bArnaldo Carvalho de Melo		ax25->digipeat = kmemdup(ax25_rt->digipeat, sizeof(ax25_digi),
4390459d70add3f7ca5d433d4b2334cc6ec9ddab05bArnaldo Carvalho de Melo					 GFP_ATOMIC);
4400459d70add3f7ca5d433d4b2334cc6ec9ddab05bArnaldo Carvalho de Melo		if (ax25->digipeat == NULL) {
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err = -ENOMEM;
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto put;
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ax25_adjust_path(addr, ax25->digipeat);
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ax25->sk != NULL) {
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bh_lock_sock(ax25->sk);
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sock_reset_flag(ax25->sk, SOCK_ZAPPED);
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bh_unlock_sock(ax25->sk);
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsput:
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_put_route(ax25_rt);
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
456b3d18f15092a7db2f229cd7bc69fc40eac0774f4Julia Lawall	return err;
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct sk_buff *ax25_rt_build_path(struct sk_buff *skb, ax25_address *src,
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_address *dest, ax25_digi *digi)
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff *skbn;
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *bp;
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int len;
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len = digi->ndigi * AX25_ADDR_LEN;
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (skb_headroom(skb) < len) {
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((skbn = skb_realloc_headroom(skb, len)) == NULL) {
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(KERN_CRIT "AX.25: ax25_dg_build_path - out of memory\n");
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return NULL;
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (skb->sk != NULL)
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			skb_set_owner_w(skbn, skb->sk);
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4775d0ba55b6486f58cc890918d7167063d83f7fbb4Eric Dumazet		consume_skb(skb);
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		skb = skbn;
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bp = skb_push(skb, len);
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_addr_build(bp, src, dest, digi, AX25_COMMAND, AX25_MODULUS);
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return skb;
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Free all memory associated with routing structures.
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid __exit ax25_rt_free(void)
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ax25_route *s, *ax25_rt = ax25_route_list;
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4964de211f1a279275c6c67d6e9b6b25513e46b0bb9Jarek Poplawski	write_lock_bh(&ax25_route_lock);
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (ax25_rt != NULL) {
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		s       = ax25_rt;
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ax25_rt = ax25_rt->next;
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
501a51482bde22f99c63fbbb57d5d46cc666384e379Jesper Juhl		kfree(s->digipeat);
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(s);
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5044de211f1a279275c6c67d6e9b6b25513e46b0bb9Jarek Poplawski	write_unlock_bh(&ax25_route_lock);
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
506