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