linux/net/x25/x25_route.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 *      X.25 Packet Layer release 002
   4 *
   5 *      This is ALPHA test software. This code may break your machine,
   6 *      randomly fail to work with new releases, misbehave and/or generally
   7 *      screw up. It might even work.
   8 *
   9 *      This code REQUIRES 2.1.15 or higher
  10 *
  11 *      History
  12 *      X.25 001        Jonathan Naylor Started coding.
  13 */
  14
  15#include <linux/if_arp.h>
  16#include <linux/init.h>
  17#include <linux/slab.h>
  18#include <net/x25.h>
  19
  20LIST_HEAD(x25_route_list);
  21DEFINE_RWLOCK(x25_route_list_lock);
  22
  23/*
  24 *      Add a new route.
  25 */
  26static int x25_add_route(struct x25_address *address, unsigned int sigdigits,
  27                         struct net_device *dev)
  28{
  29        struct x25_route *rt;
  30        int rc = -EINVAL;
  31
  32        write_lock_bh(&x25_route_list_lock);
  33
  34        list_for_each_entry(rt, &x25_route_list, node) {
  35                if (!memcmp(&rt->address, address, sigdigits) &&
  36                    rt->sigdigits == sigdigits)
  37                        goto out;
  38        }
  39
  40        rt = kmalloc(sizeof(*rt), GFP_ATOMIC);
  41        rc = -ENOMEM;
  42        if (!rt)
  43                goto out;
  44
  45        strcpy(rt->address.x25_addr, "000000000000000");
  46        memcpy(rt->address.x25_addr, address->x25_addr, sigdigits);
  47
  48        rt->sigdigits = sigdigits;
  49        rt->dev       = dev;
  50        refcount_set(&rt->refcnt, 1);
  51
  52        list_add(&rt->node, &x25_route_list);
  53        rc = 0;
  54out:
  55        write_unlock_bh(&x25_route_list_lock);
  56        return rc;
  57}
  58
  59/**
  60 * __x25_remove_route - remove route from x25_route_list
  61 * @rt: route to remove
  62 *
  63 * Remove route from x25_route_list. If it was there.
  64 * Caller must hold x25_route_list_lock.
  65 */
  66static void __x25_remove_route(struct x25_route *rt)
  67{
  68        if (rt->node.next) {
  69                list_del(&rt->node);
  70                x25_route_put(rt);
  71        }
  72}
  73
  74static int x25_del_route(struct x25_address *address, unsigned int sigdigits,
  75                         struct net_device *dev)
  76{
  77        struct x25_route *rt;
  78        int rc = -EINVAL;
  79
  80        write_lock_bh(&x25_route_list_lock);
  81
  82        list_for_each_entry(rt, &x25_route_list, node) {
  83                if (!memcmp(&rt->address, address, sigdigits) &&
  84                    rt->sigdigits == sigdigits && rt->dev == dev) {
  85                        __x25_remove_route(rt);
  86                        rc = 0;
  87                        break;
  88                }
  89        }
  90
  91        write_unlock_bh(&x25_route_list_lock);
  92        return rc;
  93}
  94
  95/*
  96 *      A device has been removed, remove its routes.
  97 */
  98void x25_route_device_down(struct net_device *dev)
  99{
 100        struct x25_route *rt;
 101        struct list_head *entry, *tmp;
 102
 103        write_lock_bh(&x25_route_list_lock);
 104
 105        list_for_each_safe(entry, tmp, &x25_route_list) {
 106                rt = list_entry(entry, struct x25_route, node);
 107
 108                if (rt->dev == dev)
 109                        __x25_remove_route(rt);
 110        }
 111        write_unlock_bh(&x25_route_list_lock);
 112}
 113
 114/*
 115 *      Check that the device given is a valid X.25 interface that is "up".
 116 */
 117struct net_device *x25_dev_get(char *devname)
 118{
 119        struct net_device *dev = dev_get_by_name(&init_net, devname);
 120
 121        if (dev && (!(dev->flags & IFF_UP) || dev->type != ARPHRD_X25)) {
 122                dev_put(dev);
 123                dev = NULL;
 124        }
 125
 126        return dev;
 127}
 128
 129/**
 130 *      x25_get_route - Find a route given an X.25 address.
 131 *      @addr: - address to find a route for
 132 *
 133 *      Find a route given an X.25 address.
 134 */
 135struct x25_route *x25_get_route(struct x25_address *addr)
 136{
 137        struct x25_route *rt, *use = NULL;
 138
 139        read_lock_bh(&x25_route_list_lock);
 140
 141        list_for_each_entry(rt, &x25_route_list, node) {
 142                if (!memcmp(&rt->address, addr, rt->sigdigits)) {
 143                        if (!use)
 144                                use = rt;
 145                        else if (rt->sigdigits > use->sigdigits)
 146                                use = rt;
 147                }
 148        }
 149
 150        if (use)
 151                x25_route_hold(use);
 152
 153        read_unlock_bh(&x25_route_list_lock);
 154        return use;
 155}
 156
 157/*
 158 *      Handle the ioctls that control the routing functions.
 159 */
 160int x25_route_ioctl(unsigned int cmd, void __user *arg)
 161{
 162        struct x25_route_struct rt;
 163        struct net_device *dev;
 164        int rc = -EINVAL;
 165
 166        if (cmd != SIOCADDRT && cmd != SIOCDELRT)
 167                goto out;
 168
 169        rc = -EFAULT;
 170        if (copy_from_user(&rt, arg, sizeof(rt)))
 171                goto out;
 172
 173        rc = -EINVAL;
 174        if (rt.sigdigits > 15)
 175                goto out;
 176
 177        dev = x25_dev_get(rt.device);
 178        if (!dev)
 179                goto out;
 180
 181        if (cmd == SIOCADDRT)
 182                rc = x25_add_route(&rt.address, rt.sigdigits, dev);
 183        else
 184                rc = x25_del_route(&rt.address, rt.sigdigits, dev);
 185        dev_put(dev);
 186out:
 187        return rc;
 188}
 189
 190/*
 191 *      Release all memory associated with X.25 routing structures.
 192 */
 193void __exit x25_route_free(void)
 194{
 195        struct x25_route *rt;
 196        struct list_head *entry, *tmp;
 197
 198        write_lock_bh(&x25_route_list_lock);
 199        list_for_each_safe(entry, tmp, &x25_route_list) {
 200                rt = list_entry(entry, struct x25_route, node);
 201                __x25_remove_route(rt);
 202        }
 203        write_unlock_bh(&x25_route_list_lock);
 204}
 205