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