Blame view

net/x25/x25_route.c 4.53 KB
ee5d8f4d8   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
  /*
   *	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...
7
   *	screw up. It might even work.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8
9
10
   *
   *	This code REQUIRES 2.1.15 or higher
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
12
13
   *	History
   *	X.25 001	Jonathan Naylor	Started coding.
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
15
  #include <linux/if_arp.h>
  #include <linux/init.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
16
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
  #include <net/x25.h>
0e3cf7e91   Denis Cheng   [X25]: use LIST_H...
18
  LIST_HEAD(x25_route_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
20
21
22
23
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
  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;
5f9ccf6f3   Reshetova, Elena   net, x25: convert...
51
  	refcount_set(&rt->refcnt, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
53
54
55
56
57
58
59
60
61
  
  	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-...
62
   * @rt: route to remove
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63
64
65
66
67
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
   *
   * 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 ...
116
117
118
  
  	/* Remove any related forwarding */
  	x25_clear_forward_by_dev(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
119
120
121
122
123
124
125
  }
  
  /*
   *	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...
126
  	struct net_device *dev = dev_get_by_name(&init_net, devname);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
127
128
129
  
  	if (dev &&
  	    (!(dev->flags & IFF_UP) || (dev->type != ARPHRD_X25
29c362623   Igor Maravić   net:x25: use IS_E...
130
  #if IS_ENABLED(CONFIG_LLC)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131
132
  					&& dev->type != ARPHRD_ETHER
  #endif
429d33ace   andrew hendry   X25: Fix oops and...
133
  					))){
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
134
  		dev_put(dev);
429d33ace   andrew hendry   X25: Fix oops and...
135
136
  		dev = NULL;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
137
138
139
140
141
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
  
  	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...
189
  	if (rt.sigdigits > 15)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
190
191
192
193
194
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
  		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);
  }