Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
x25_route.c
Go to the documentation of this file.
1 /*
2  * X.25 Packet Layer release 002
3  *
4  * This is ALPHA test software. This code may break your machine,
5  * randomly fail to work with new releases, misbehave and/or generally
6  * screw up. It might even work.
7  *
8  * This code REQUIRES 2.1.15 or higher
9  *
10  * This module:
11  * This module is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version
14  * 2 of the License, or (at your option) any later version.
15  *
16  * History
17  * X.25 001 Jonathan Naylor Started coding.
18  */
19 
20 #include <linux/if_arp.h>
21 #include <linux/init.h>
22 #include <linux/slab.h>
23 #include <net/x25.h>
24 
25 LIST_HEAD(x25_route_list);
26 DEFINE_RWLOCK(x25_route_list_lock);
27 
28 /*
29  * Add a new route.
30  */
31 static int x25_add_route(struct x25_address *address, unsigned int sigdigits,
32  struct net_device *dev)
33 {
34  struct x25_route *rt;
35  struct list_head *entry;
36  int rc = -EINVAL;
37 
38  write_lock_bh(&x25_route_list_lock);
39 
40  list_for_each(entry, &x25_route_list) {
41  rt = list_entry(entry, struct x25_route, node);
42 
43  if (!memcmp(&rt->address, address, sigdigits) &&
44  rt->sigdigits == sigdigits)
45  goto out;
46  }
47 
48  rt = kmalloc(sizeof(*rt), GFP_ATOMIC);
49  rc = -ENOMEM;
50  if (!rt)
51  goto out;
52 
53  strcpy(rt->address.x25_addr, "000000000000000");
54  memcpy(rt->address.x25_addr, address->x25_addr, sigdigits);
55 
56  rt->sigdigits = sigdigits;
57  rt->dev = dev;
58  atomic_set(&rt->refcnt, 1);
59 
60  list_add(&rt->node, &x25_route_list);
61  rc = 0;
62 out:
63  write_unlock_bh(&x25_route_list_lock);
64  return rc;
65 }
66 
74 static void __x25_remove_route(struct x25_route *rt)
75 {
76  if (rt->node.next) {
77  list_del(&rt->node);
78  x25_route_put(rt);
79  }
80 }
81 
82 static int x25_del_route(struct x25_address *address, unsigned int sigdigits,
83  struct net_device *dev)
84 {
85  struct x25_route *rt;
86  struct list_head *entry;
87  int rc = -EINVAL;
88 
89  write_lock_bh(&x25_route_list_lock);
90 
91  list_for_each(entry, &x25_route_list) {
92  rt = list_entry(entry, struct x25_route, node);
93 
94  if (!memcmp(&rt->address, address, sigdigits) &&
95  rt->sigdigits == sigdigits && rt->dev == dev) {
96  __x25_remove_route(rt);
97  rc = 0;
98  break;
99  }
100  }
101 
102  write_unlock_bh(&x25_route_list_lock);
103  return rc;
104 }
105 
106 /*
107  * A device has been removed, remove its routes.
108  */
110 {
111  struct x25_route *rt;
112  struct list_head *entry, *tmp;
113 
115 
116  list_for_each_safe(entry, tmp, &x25_route_list) {
117  rt = list_entry(entry, struct x25_route, node);
118 
119  if (rt->dev == dev)
120  __x25_remove_route(rt);
121  }
123 
124  /* Remove any related forwarding */
126 }
127 
128 /*
129  * Check that the device given is a valid X.25 interface that is "up".
130  */
131 struct net_device *x25_dev_get(char *devname)
132 {
133  struct net_device *dev = dev_get_by_name(&init_net, devname);
134 
135  if (dev &&
136  (!(dev->flags & IFF_UP) || (dev->type != ARPHRD_X25
137 #if IS_ENABLED(CONFIG_LLC)
138  && dev->type != ARPHRD_ETHER
139 #endif
140  ))){
141  dev_put(dev);
142  dev = NULL;
143  }
144 
145  return dev;
146 }
147 
155 {
156  struct x25_route *rt, *use = NULL;
157  struct list_head *entry;
158 
160 
161  list_for_each(entry, &x25_route_list) {
162  rt = list_entry(entry, struct x25_route, node);
163 
164  if (!memcmp(&rt->address, addr, rt->sigdigits)) {
165  if (!use)
166  use = rt;
167  else if (rt->sigdigits > use->sigdigits)
168  use = rt;
169  }
170  }
171 
172  if (use)
173  x25_route_hold(use);
174 
176  return use;
177 }
178 
179 /*
180  * Handle the ioctls that control the routing functions.
181  */
182 int x25_route_ioctl(unsigned int cmd, void __user *arg)
183 {
184  struct x25_route_struct rt;
185  struct net_device *dev;
186  int rc = -EINVAL;
187 
188  if (cmd != SIOCADDRT && cmd != SIOCDELRT)
189  goto out;
190 
191  rc = -EFAULT;
192  if (copy_from_user(&rt, arg, sizeof(rt)))
193  goto out;
194 
195  rc = -EINVAL;
196  if (rt.sigdigits > 15)
197  goto out;
198 
199  dev = x25_dev_get(rt.device);
200  if (!dev)
201  goto out;
202 
203  if (cmd == SIOCADDRT)
204  rc = x25_add_route(&rt.address, rt.sigdigits, dev);
205  else
206  rc = x25_del_route(&rt.address, rt.sigdigits, dev);
207  dev_put(dev);
208 out:
209  return rc;
210 }
211 
212 /*
213  * Release all memory associated with X.25 routing structures.
214  */
216 {
217  struct x25_route *rt;
218  struct list_head *entry, *tmp;
219 
221  list_for_each_safe(entry, tmp, &x25_route_list) {
222  rt = list_entry(entry, struct x25_route, node);
223  __x25_remove_route(rt);
224  }
226 }