xref: /openbmc/linux/net/x25/x25_route.c (revision 762f99f4f3cb41a775b5157dd761217beba65873)
1ee5d8f4dSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  *	X.25 Packet Layer release 002
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  *	This is ALPHA test software. This code may break your machine,
61da177e4SLinus Torvalds  *	randomly fail to work with new releases, misbehave and/or generally
71da177e4SLinus Torvalds  *	screw up. It might even work.
81da177e4SLinus Torvalds  *
91da177e4SLinus Torvalds  *	This code REQUIRES 2.1.15 or higher
101da177e4SLinus Torvalds  *
111da177e4SLinus Torvalds  *	History
121da177e4SLinus Torvalds  *	X.25 001	Jonathan Naylor	Started coding.
131da177e4SLinus Torvalds  */
141da177e4SLinus Torvalds 
151da177e4SLinus Torvalds #include <linux/if_arp.h>
161da177e4SLinus Torvalds #include <linux/init.h>
175a0e3ad6STejun Heo #include <linux/slab.h>
181da177e4SLinus Torvalds #include <net/x25.h>
191da177e4SLinus Torvalds 
200e3cf7e9SDenis Cheng LIST_HEAD(x25_route_list);
211da177e4SLinus Torvalds DEFINE_RWLOCK(x25_route_list_lock);
221da177e4SLinus Torvalds 
231da177e4SLinus Torvalds /*
241da177e4SLinus Torvalds  *	Add a new route.
251da177e4SLinus Torvalds  */
x25_add_route(struct x25_address * address,unsigned int sigdigits,struct net_device * dev)261da177e4SLinus Torvalds static int x25_add_route(struct x25_address *address, unsigned int sigdigits,
271da177e4SLinus Torvalds 			 struct net_device *dev)
281da177e4SLinus Torvalds {
291da177e4SLinus Torvalds 	struct x25_route *rt;
301da177e4SLinus Torvalds 	int rc = -EINVAL;
311da177e4SLinus Torvalds 
321da177e4SLinus Torvalds 	write_lock_bh(&x25_route_list_lock);
331da177e4SLinus Torvalds 
34*bc831facSWang Hai 	list_for_each_entry(rt, &x25_route_list, node) {
351da177e4SLinus Torvalds 		if (!memcmp(&rt->address, address, sigdigits) &&
361da177e4SLinus Torvalds 		    rt->sigdigits == sigdigits)
371da177e4SLinus Torvalds 			goto out;
381da177e4SLinus Torvalds 	}
391da177e4SLinus Torvalds 
401da177e4SLinus Torvalds 	rt = kmalloc(sizeof(*rt), GFP_ATOMIC);
411da177e4SLinus Torvalds 	rc = -ENOMEM;
421da177e4SLinus Torvalds 	if (!rt)
431da177e4SLinus Torvalds 		goto out;
441da177e4SLinus Torvalds 
451da177e4SLinus Torvalds 	strcpy(rt->address.x25_addr, "000000000000000");
461da177e4SLinus Torvalds 	memcpy(rt->address.x25_addr, address->x25_addr, sigdigits);
471da177e4SLinus Torvalds 
481da177e4SLinus Torvalds 	rt->sigdigits = sigdigits;
491da177e4SLinus Torvalds 	rt->dev       = dev;
505f9ccf6fSReshetova, Elena 	refcount_set(&rt->refcnt, 1);
511da177e4SLinus Torvalds 
521da177e4SLinus Torvalds 	list_add(&rt->node, &x25_route_list);
531da177e4SLinus Torvalds 	rc = 0;
541da177e4SLinus Torvalds out:
551da177e4SLinus Torvalds 	write_unlock_bh(&x25_route_list_lock);
561da177e4SLinus Torvalds 	return rc;
571da177e4SLinus Torvalds }
581da177e4SLinus Torvalds 
591da177e4SLinus Torvalds /**
601da177e4SLinus Torvalds  * __x25_remove_route - remove route from x25_route_list
612c53040fSBen Hutchings  * @rt: route to remove
621da177e4SLinus Torvalds  *
631da177e4SLinus Torvalds  * Remove route from x25_route_list. If it was there.
641da177e4SLinus Torvalds  * Caller must hold x25_route_list_lock.
651da177e4SLinus Torvalds  */
__x25_remove_route(struct x25_route * rt)661da177e4SLinus Torvalds static void __x25_remove_route(struct x25_route *rt)
671da177e4SLinus Torvalds {
681da177e4SLinus Torvalds 	if (rt->node.next) {
691da177e4SLinus Torvalds 		list_del(&rt->node);
701da177e4SLinus Torvalds 		x25_route_put(rt);
711da177e4SLinus Torvalds 	}
721da177e4SLinus Torvalds }
731da177e4SLinus Torvalds 
x25_del_route(struct x25_address * address,unsigned int sigdigits,struct net_device * dev)741da177e4SLinus Torvalds static int x25_del_route(struct x25_address *address, unsigned int sigdigits,
751da177e4SLinus Torvalds 			 struct net_device *dev)
761da177e4SLinus Torvalds {
771da177e4SLinus Torvalds 	struct x25_route *rt;
781da177e4SLinus Torvalds 	int rc = -EINVAL;
791da177e4SLinus Torvalds 
801da177e4SLinus Torvalds 	write_lock_bh(&x25_route_list_lock);
811da177e4SLinus Torvalds 
82*bc831facSWang Hai 	list_for_each_entry(rt, &x25_route_list, node) {
831da177e4SLinus Torvalds 		if (!memcmp(&rt->address, address, sigdigits) &&
841da177e4SLinus Torvalds 		    rt->sigdigits == sigdigits && rt->dev == dev) {
851da177e4SLinus Torvalds 			__x25_remove_route(rt);
861da177e4SLinus Torvalds 			rc = 0;
871da177e4SLinus Torvalds 			break;
881da177e4SLinus Torvalds 		}
891da177e4SLinus Torvalds 	}
901da177e4SLinus Torvalds 
911da177e4SLinus Torvalds 	write_unlock_bh(&x25_route_list_lock);
921da177e4SLinus Torvalds 	return rc;
931da177e4SLinus Torvalds }
941da177e4SLinus Torvalds 
951da177e4SLinus Torvalds /*
961da177e4SLinus Torvalds  *	A device has been removed, remove its routes.
971da177e4SLinus Torvalds  */
x25_route_device_down(struct net_device * dev)981da177e4SLinus Torvalds void x25_route_device_down(struct net_device *dev)
991da177e4SLinus Torvalds {
1001da177e4SLinus Torvalds 	struct x25_route *rt;
1011da177e4SLinus Torvalds 	struct list_head *entry, *tmp;
1021da177e4SLinus Torvalds 
1031da177e4SLinus Torvalds 	write_lock_bh(&x25_route_list_lock);
1041da177e4SLinus Torvalds 
1051da177e4SLinus Torvalds 	list_for_each_safe(entry, tmp, &x25_route_list) {
1061da177e4SLinus Torvalds 		rt = list_entry(entry, struct x25_route, node);
1071da177e4SLinus Torvalds 
1081da177e4SLinus Torvalds 		if (rt->dev == dev)
1091da177e4SLinus Torvalds 			__x25_remove_route(rt);
1101da177e4SLinus Torvalds 	}
1111da177e4SLinus Torvalds 	write_unlock_bh(&x25_route_list_lock);
1121da177e4SLinus Torvalds }
1131da177e4SLinus Torvalds 
1141da177e4SLinus Torvalds /*
1151da177e4SLinus Torvalds  *	Check that the device given is a valid X.25 interface that is "up".
1161da177e4SLinus Torvalds  */
x25_dev_get(char * devname)1171da177e4SLinus Torvalds struct net_device *x25_dev_get(char *devname)
1181da177e4SLinus Torvalds {
119881d966bSEric W. Biederman 	struct net_device *dev = dev_get_by_name(&init_net, devname);
1201da177e4SLinus Torvalds 
12113458ffeSXie He 	if (dev && (!(dev->flags & IFF_UP) || dev->type != ARPHRD_X25)) {
1221da177e4SLinus Torvalds 		dev_put(dev);
123429d33acSandrew hendry 		dev = NULL;
124429d33acSandrew hendry 	}
1251da177e4SLinus Torvalds 
1261da177e4SLinus Torvalds 	return dev;
1271da177e4SLinus Torvalds }
1281da177e4SLinus Torvalds 
1291da177e4SLinus Torvalds /**
1301da177e4SLinus Torvalds  * 	x25_get_route -	Find a route given an X.25 address.
13162c89238SAndrew Lunn  *	@addr: - address to find a route for
1321da177e4SLinus Torvalds  *
1331da177e4SLinus Torvalds  * 	Find a route given an X.25 address.
1341da177e4SLinus Torvalds  */
x25_get_route(struct x25_address * addr)1351da177e4SLinus Torvalds struct x25_route *x25_get_route(struct x25_address *addr)
1361da177e4SLinus Torvalds {
1371da177e4SLinus Torvalds 	struct x25_route *rt, *use = NULL;
1381da177e4SLinus Torvalds 
1391da177e4SLinus Torvalds 	read_lock_bh(&x25_route_list_lock);
1401da177e4SLinus Torvalds 
141*bc831facSWang Hai 	list_for_each_entry(rt, &x25_route_list, node) {
1421da177e4SLinus Torvalds 		if (!memcmp(&rt->address, addr, rt->sigdigits)) {
1431da177e4SLinus Torvalds 			if (!use)
1441da177e4SLinus Torvalds 				use = rt;
1451da177e4SLinus Torvalds 			else if (rt->sigdigits > use->sigdigits)
1461da177e4SLinus Torvalds 				use = rt;
1471da177e4SLinus Torvalds 		}
1481da177e4SLinus Torvalds 	}
1491da177e4SLinus Torvalds 
1501da177e4SLinus Torvalds 	if (use)
1511da177e4SLinus Torvalds 		x25_route_hold(use);
1521da177e4SLinus Torvalds 
1531da177e4SLinus Torvalds 	read_unlock_bh(&x25_route_list_lock);
1541da177e4SLinus Torvalds 	return use;
1551da177e4SLinus Torvalds }
1561da177e4SLinus Torvalds 
1571da177e4SLinus Torvalds /*
1581da177e4SLinus Torvalds  *	Handle the ioctls that control the routing functions.
1591da177e4SLinus Torvalds  */
x25_route_ioctl(unsigned int cmd,void __user * arg)1601da177e4SLinus Torvalds int x25_route_ioctl(unsigned int cmd, void __user *arg)
1611da177e4SLinus Torvalds {
1621da177e4SLinus Torvalds 	struct x25_route_struct rt;
1631da177e4SLinus Torvalds 	struct net_device *dev;
1641da177e4SLinus Torvalds 	int rc = -EINVAL;
1651da177e4SLinus Torvalds 
1661da177e4SLinus Torvalds 	if (cmd != SIOCADDRT && cmd != SIOCDELRT)
1671da177e4SLinus Torvalds 		goto out;
1681da177e4SLinus Torvalds 
1691da177e4SLinus Torvalds 	rc = -EFAULT;
1701da177e4SLinus Torvalds 	if (copy_from_user(&rt, arg, sizeof(rt)))
1711da177e4SLinus Torvalds 		goto out;
1721da177e4SLinus Torvalds 
1731da177e4SLinus Torvalds 	rc = -EINVAL;
174091bb8abSroel kluin 	if (rt.sigdigits > 15)
1751da177e4SLinus Torvalds 		goto out;
1761da177e4SLinus Torvalds 
1771da177e4SLinus Torvalds 	dev = x25_dev_get(rt.device);
1781da177e4SLinus Torvalds 	if (!dev)
1791da177e4SLinus Torvalds 		goto out;
1801da177e4SLinus Torvalds 
1811da177e4SLinus Torvalds 	if (cmd == SIOCADDRT)
1821da177e4SLinus Torvalds 		rc = x25_add_route(&rt.address, rt.sigdigits, dev);
1831da177e4SLinus Torvalds 	else
1841da177e4SLinus Torvalds 		rc = x25_del_route(&rt.address, rt.sigdigits, dev);
1851da177e4SLinus Torvalds 	dev_put(dev);
1861da177e4SLinus Torvalds out:
1871da177e4SLinus Torvalds 	return rc;
1881da177e4SLinus Torvalds }
1891da177e4SLinus Torvalds 
1901da177e4SLinus Torvalds /*
1911da177e4SLinus Torvalds  *	Release all memory associated with X.25 routing structures.
1921da177e4SLinus Torvalds  */
x25_route_free(void)1931da177e4SLinus Torvalds void __exit x25_route_free(void)
1941da177e4SLinus Torvalds {
1951da177e4SLinus Torvalds 	struct x25_route *rt;
1961da177e4SLinus Torvalds 	struct list_head *entry, *tmp;
1971da177e4SLinus Torvalds 
1981da177e4SLinus Torvalds 	write_lock_bh(&x25_route_list_lock);
1991da177e4SLinus Torvalds 	list_for_each_safe(entry, tmp, &x25_route_list) {
2001da177e4SLinus Torvalds 		rt = list_entry(entry, struct x25_route, node);
2011da177e4SLinus Torvalds 		__x25_remove_route(rt);
2021da177e4SLinus Torvalds 	}
2031da177e4SLinus Torvalds 	write_unlock_bh(&x25_route_list_lock);
2041da177e4SLinus Torvalds }
205