Blame view

net/x25/x25_route.c 4.75 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
  /*
   *	X.25 Packet Layer release 002
   *
   *	This is ALPHA test software. This code may break your machine,
   *	randomly fail to work with new releases, misbehave and/or generally
f8e1d2018   YOSHIFUJI Hideaki   [NET] X25: Fix wh...
6
   *	screw up. It might even work.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7
8
9
10
11
12
13
14
15
16
17
18
   *
   *	This code REQUIRES 2.1.15 or higher
   *
   *	This module:
   *		This module is free software; you can redistribute it and/or
   *		modify it under the terms of the GNU General Public License
   *		as published by the Free Software Foundation; either version
   *		2 of the License, or (at your option) any later version.
   *
   *	History
   *	X.25 001	Jonathan Naylor	Started coding.
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
20
  #include <linux/if_arp.h>
  #include <linux/init.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
21
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
  #include <net/x25.h>
0e3cf7e91   Denis Cheng   [X25]: use LIST_H...
23
  LIST_HEAD(x25_route_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
  DEFINE_RWLOCK(x25_route_list_lock);
  
  /*
   *	Add a new route.
   */
  static int x25_add_route(struct x25_address *address, unsigned int sigdigits,
  			 struct net_device *dev)
  {
  	struct x25_route *rt;
  	struct list_head *entry;
  	int rc = -EINVAL;
  
  	write_lock_bh(&x25_route_list_lock);
  
  	list_for_each(entry, &x25_route_list) {
  		rt = list_entry(entry, struct x25_route, node);
  
  		if (!memcmp(&rt->address, address, sigdigits) &&
  		    rt->sigdigits == sigdigits)
  			goto out;
  	}
  
  	rt = kmalloc(sizeof(*rt), GFP_ATOMIC);
  	rc = -ENOMEM;
  	if (!rt)
  		goto out;
  
  	strcpy(rt->address.x25_addr, "000000000000000");
  	memcpy(rt->address.x25_addr, address->x25_addr, sigdigits);
  
  	rt->sigdigits = sigdigits;
  	rt->dev       = dev;
  	atomic_set(&rt->refcnt, 1);
  
  	list_add(&rt->node, &x25_route_list);
  	rc = 0;
  out:
  	write_unlock_bh(&x25_route_list_lock);
  	return rc;
  }
  
  /**
   * __x25_remove_route - remove route from x25_route_list
2c53040f0   Ben Hutchings   net: Fix (nearly-...
67
   * @rt: route to remove
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
   *
   * Remove route from x25_route_list. If it was there.
   * Caller must hold x25_route_list_lock.
   */
  static void __x25_remove_route(struct x25_route *rt)
  {
  	if (rt->node.next) {
  		list_del(&rt->node);
  		x25_route_put(rt);
  	}
  }
  
  static int x25_del_route(struct x25_address *address, unsigned int sigdigits,
  			 struct net_device *dev)
  {
  	struct x25_route *rt;
  	struct list_head *entry;
  	int rc = -EINVAL;
  
  	write_lock_bh(&x25_route_list_lock);
  
  	list_for_each(entry, &x25_route_list) {
  		rt = list_entry(entry, struct x25_route, node);
  
  		if (!memcmp(&rt->address, address, sigdigits) &&
  		    rt->sigdigits == sigdigits && rt->dev == dev) {
  			__x25_remove_route(rt);
  			rc = 0;
  			break;
  		}
  	}
  
  	write_unlock_bh(&x25_route_list_lock);
  	return rc;
  }
  
  /*
   *	A device has been removed, remove its routes.
   */
  void x25_route_device_down(struct net_device *dev)
  {
  	struct x25_route *rt;
  	struct list_head *entry, *tmp;
  
  	write_lock_bh(&x25_route_list_lock);
  
  	list_for_each_safe(entry, tmp, &x25_route_list) {
  		rt = list_entry(entry, struct x25_route, node);
  
  		if (rt->dev == dev)
  			__x25_remove_route(rt);
  	}
  	write_unlock_bh(&x25_route_list_lock);
95a9dc439   Andrew Hendry   [X.25]: Add call ...
121
122
123
  
  	/* Remove any related forwarding */
  	x25_clear_forward_by_dev(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
124
125
126
127
128
129
130
  }
  
  /*
   *	Check that the device given is a valid X.25 interface that is "up".
   */
  struct net_device *x25_dev_get(char *devname)
  {
881d966b4   Eric W. Biederman   [NET]: Make the d...
131
  	struct net_device *dev = dev_get_by_name(&init_net, devname);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
132
133
134
  
  	if (dev &&
  	    (!(dev->flags & IFF_UP) || (dev->type != ARPHRD_X25
29c362623   Igor Maravić   net:x25: use IS_E...
135
  #if IS_ENABLED(CONFIG_LLC)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136
137
  					&& dev->type != ARPHRD_ETHER
  #endif
429d33ace   andrew hendry   X25: Fix oops and...
138
  					))){
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
139
  		dev_put(dev);
429d33ace   andrew hendry   X25: Fix oops and...
140
141
  		dev = NULL;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
  
  	return dev;
  }
  
  /**
   * 	x25_get_route -	Find a route given an X.25 address.
   * 	@addr - address to find a route for
   *
   * 	Find a route given an X.25 address.
   */
  struct x25_route *x25_get_route(struct x25_address *addr)
  {
  	struct x25_route *rt, *use = NULL;
  	struct list_head *entry;
  
  	read_lock_bh(&x25_route_list_lock);
  
  	list_for_each(entry, &x25_route_list) {
  		rt = list_entry(entry, struct x25_route, node);
  
  		if (!memcmp(&rt->address, addr, rt->sigdigits)) {
  			if (!use)
  				use = rt;
  			else if (rt->sigdigits > use->sigdigits)
  				use = rt;
  		}
  	}
  
  	if (use)
  		x25_route_hold(use);
  
  	read_unlock_bh(&x25_route_list_lock);
  	return use;
  }
  
  /*
   *	Handle the ioctls that control the routing functions.
   */
  int x25_route_ioctl(unsigned int cmd, void __user *arg)
  {
  	struct x25_route_struct rt;
  	struct net_device *dev;
  	int rc = -EINVAL;
  
  	if (cmd != SIOCADDRT && cmd != SIOCDELRT)
  		goto out;
  
  	rc = -EFAULT;
  	if (copy_from_user(&rt, arg, sizeof(rt)))
  		goto out;
  
  	rc = -EINVAL;
091bb8ab5   roel kluin   net: Cleanup redu...
194
  	if (rt.sigdigits > 15)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
  		goto out;
  
  	dev = x25_dev_get(rt.device);
  	if (!dev)
  		goto out;
  
  	if (cmd == SIOCADDRT)
  		rc = x25_add_route(&rt.address, rt.sigdigits, dev);
  	else
  		rc = x25_del_route(&rt.address, rt.sigdigits, dev);
  	dev_put(dev);
  out:
  	return rc;
  }
  
  /*
   *	Release all memory associated with X.25 routing structures.
   */
  void __exit x25_route_free(void)
  {
  	struct x25_route *rt;
  	struct list_head *entry, *tmp;
  
  	write_lock_bh(&x25_route_list_lock);
  	list_for_each_safe(entry, tmp, &x25_route_list) {
  		rt = list_entry(entry, struct x25_route, node);
  		__x25_remove_route(rt);
  	}
  	write_unlock_bh(&x25_route_list_lock);
  }