Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  X.25 Packet Layer release 002
0004  *
0005  *  This is ALPHA test software. This code may break your machine,
0006  *  randomly fail to work with new releases, misbehave and/or generally
0007  *  screw up. It might even work.
0008  *
0009  *  This code REQUIRES 2.1.15 or higher
0010  *
0011  *  History
0012  *  X.25 001    Jonathan Naylor Started coding.
0013  */
0014 
0015 #include <linux/if_arp.h>
0016 #include <linux/init.h>
0017 #include <linux/slab.h>
0018 #include <net/x25.h>
0019 
0020 LIST_HEAD(x25_route_list);
0021 DEFINE_RWLOCK(x25_route_list_lock);
0022 
0023 /*
0024  *  Add a new route.
0025  */
0026 static int x25_add_route(struct x25_address *address, unsigned int sigdigits,
0027              struct net_device *dev)
0028 {
0029     struct x25_route *rt;
0030     int rc = -EINVAL;
0031 
0032     write_lock_bh(&x25_route_list_lock);
0033 
0034     list_for_each_entry(rt, &x25_route_list, node) {
0035         if (!memcmp(&rt->address, address, sigdigits) &&
0036             rt->sigdigits == sigdigits)
0037             goto out;
0038     }
0039 
0040     rt = kmalloc(sizeof(*rt), GFP_ATOMIC);
0041     rc = -ENOMEM;
0042     if (!rt)
0043         goto out;
0044 
0045     strcpy(rt->address.x25_addr, "000000000000000");
0046     memcpy(rt->address.x25_addr, address->x25_addr, sigdigits);
0047 
0048     rt->sigdigits = sigdigits;
0049     rt->dev       = dev;
0050     refcount_set(&rt->refcnt, 1);
0051 
0052     list_add(&rt->node, &x25_route_list);
0053     rc = 0;
0054 out:
0055     write_unlock_bh(&x25_route_list_lock);
0056     return rc;
0057 }
0058 
0059 /**
0060  * __x25_remove_route - remove route from x25_route_list
0061  * @rt: route to remove
0062  *
0063  * Remove route from x25_route_list. If it was there.
0064  * Caller must hold x25_route_list_lock.
0065  */
0066 static void __x25_remove_route(struct x25_route *rt)
0067 {
0068     if (rt->node.next) {
0069         list_del(&rt->node);
0070         x25_route_put(rt);
0071     }
0072 }
0073 
0074 static int x25_del_route(struct x25_address *address, unsigned int sigdigits,
0075              struct net_device *dev)
0076 {
0077     struct x25_route *rt;
0078     int rc = -EINVAL;
0079 
0080     write_lock_bh(&x25_route_list_lock);
0081 
0082     list_for_each_entry(rt, &x25_route_list, node) {
0083         if (!memcmp(&rt->address, address, sigdigits) &&
0084             rt->sigdigits == sigdigits && rt->dev == dev) {
0085             __x25_remove_route(rt);
0086             rc = 0;
0087             break;
0088         }
0089     }
0090 
0091     write_unlock_bh(&x25_route_list_lock);
0092     return rc;
0093 }
0094 
0095 /*
0096  *  A device has been removed, remove its routes.
0097  */
0098 void x25_route_device_down(struct net_device *dev)
0099 {
0100     struct x25_route *rt;
0101     struct list_head *entry, *tmp;
0102 
0103     write_lock_bh(&x25_route_list_lock);
0104 
0105     list_for_each_safe(entry, tmp, &x25_route_list) {
0106         rt = list_entry(entry, struct x25_route, node);
0107 
0108         if (rt->dev == dev)
0109             __x25_remove_route(rt);
0110     }
0111     write_unlock_bh(&x25_route_list_lock);
0112 }
0113 
0114 /*
0115  *  Check that the device given is a valid X.25 interface that is "up".
0116  */
0117 struct net_device *x25_dev_get(char *devname)
0118 {
0119     struct net_device *dev = dev_get_by_name(&init_net, devname);
0120 
0121     if (dev && (!(dev->flags & IFF_UP) || dev->type != ARPHRD_X25)) {
0122         dev_put(dev);
0123         dev = NULL;
0124     }
0125 
0126     return dev;
0127 }
0128 
0129 /**
0130  *  x25_get_route - Find a route given an X.25 address.
0131  *  @addr: - address to find a route for
0132  *
0133  *  Find a route given an X.25 address.
0134  */
0135 struct x25_route *x25_get_route(struct x25_address *addr)
0136 {
0137     struct x25_route *rt, *use = NULL;
0138 
0139     read_lock_bh(&x25_route_list_lock);
0140 
0141     list_for_each_entry(rt, &x25_route_list, node) {
0142         if (!memcmp(&rt->address, addr, rt->sigdigits)) {
0143             if (!use)
0144                 use = rt;
0145             else if (rt->sigdigits > use->sigdigits)
0146                 use = rt;
0147         }
0148     }
0149 
0150     if (use)
0151         x25_route_hold(use);
0152 
0153     read_unlock_bh(&x25_route_list_lock);
0154     return use;
0155 }
0156 
0157 /*
0158  *  Handle the ioctls that control the routing functions.
0159  */
0160 int x25_route_ioctl(unsigned int cmd, void __user *arg)
0161 {
0162     struct x25_route_struct rt;
0163     struct net_device *dev;
0164     int rc = -EINVAL;
0165 
0166     if (cmd != SIOCADDRT && cmd != SIOCDELRT)
0167         goto out;
0168 
0169     rc = -EFAULT;
0170     if (copy_from_user(&rt, arg, sizeof(rt)))
0171         goto out;
0172 
0173     rc = -EINVAL;
0174     if (rt.sigdigits > 15)
0175         goto out;
0176 
0177     dev = x25_dev_get(rt.device);
0178     if (!dev)
0179         goto out;
0180 
0181     if (cmd == SIOCADDRT)
0182         rc = x25_add_route(&rt.address, rt.sigdigits, dev);
0183     else
0184         rc = x25_del_route(&rt.address, rt.sigdigits, dev);
0185     dev_put(dev);
0186 out:
0187     return rc;
0188 }
0189 
0190 /*
0191  *  Release all memory associated with X.25 routing structures.
0192  */
0193 void __exit x25_route_free(void)
0194 {
0195     struct x25_route *rt;
0196     struct list_head *entry, *tmp;
0197 
0198     write_lock_bh(&x25_route_list_lock);
0199     list_for_each_safe(entry, tmp, &x25_route_list) {
0200         rt = list_entry(entry, struct x25_route, node);
0201         __x25_remove_route(rt);
0202     }
0203     write_unlock_bh(&x25_route_list_lock);
0204 }