xref: /OK3568_Linux_fs/kernel/net/core/dev_ioctl.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun #include <linux/kmod.h>
3*4882a593Smuzhiyun #include <linux/netdevice.h>
4*4882a593Smuzhiyun #include <linux/inetdevice.h>
5*4882a593Smuzhiyun #include <linux/etherdevice.h>
6*4882a593Smuzhiyun #include <linux/rtnetlink.h>
7*4882a593Smuzhiyun #include <linux/net_tstamp.h>
8*4882a593Smuzhiyun #include <linux/wireless.h>
9*4882a593Smuzhiyun #include <net/dsa.h>
10*4882a593Smuzhiyun #include <net/wext.h>
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun /*
13*4882a593Smuzhiyun  *	Map an interface index to its name (SIOCGIFNAME)
14*4882a593Smuzhiyun  */
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun /*
17*4882a593Smuzhiyun  *	We need this ioctl for efficient implementation of the
18*4882a593Smuzhiyun  *	if_indextoname() function required by the IPv6 API.  Without
19*4882a593Smuzhiyun  *	it, we would have to search all the interfaces to find a
20*4882a593Smuzhiyun  *	match.  --pb
21*4882a593Smuzhiyun  */
22*4882a593Smuzhiyun 
dev_ifname(struct net * net,struct ifreq * ifr)23*4882a593Smuzhiyun static int dev_ifname(struct net *net, struct ifreq *ifr)
24*4882a593Smuzhiyun {
25*4882a593Smuzhiyun 	ifr->ifr_name[IFNAMSIZ-1] = 0;
26*4882a593Smuzhiyun 	return netdev_get_name(net, ifr->ifr_name, ifr->ifr_ifindex);
27*4882a593Smuzhiyun }
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun /*
30*4882a593Smuzhiyun  *	Perform a SIOCGIFCONF call. This structure will change
31*4882a593Smuzhiyun  *	size eventually, and there is nothing I can do about it.
32*4882a593Smuzhiyun  *	Thus we will need a 'compatibility mode'.
33*4882a593Smuzhiyun  */
34*4882a593Smuzhiyun 
dev_ifconf(struct net * net,struct ifconf * ifc,int size)35*4882a593Smuzhiyun int dev_ifconf(struct net *net, struct ifconf *ifc, int size)
36*4882a593Smuzhiyun {
37*4882a593Smuzhiyun 	struct net_device *dev;
38*4882a593Smuzhiyun 	char __user *pos;
39*4882a593Smuzhiyun 	int len;
40*4882a593Smuzhiyun 	int total;
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun 	/*
43*4882a593Smuzhiyun 	 *	Fetch the caller's info block.
44*4882a593Smuzhiyun 	 */
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun 	pos = ifc->ifc_buf;
47*4882a593Smuzhiyun 	len = ifc->ifc_len;
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun 	/*
50*4882a593Smuzhiyun 	 *	Loop over the interfaces, and write an info block for each.
51*4882a593Smuzhiyun 	 */
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun 	total = 0;
54*4882a593Smuzhiyun 	for_each_netdev(net, dev) {
55*4882a593Smuzhiyun 		int done;
56*4882a593Smuzhiyun 		if (!pos)
57*4882a593Smuzhiyun 			done = inet_gifconf(dev, NULL, 0, size);
58*4882a593Smuzhiyun 		else
59*4882a593Smuzhiyun 			done = inet_gifconf(dev, pos + total,
60*4882a593Smuzhiyun 					    len - total, size);
61*4882a593Smuzhiyun 		if (done < 0)
62*4882a593Smuzhiyun 			return -EFAULT;
63*4882a593Smuzhiyun 		total += done;
64*4882a593Smuzhiyun 	}
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun 	/*
67*4882a593Smuzhiyun 	 *	All done.  Write the updated control block back to the caller.
68*4882a593Smuzhiyun 	 */
69*4882a593Smuzhiyun 	ifc->ifc_len = total;
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun 	/*
72*4882a593Smuzhiyun 	 * 	Both BSD and Solaris return 0 here, so we do too.
73*4882a593Smuzhiyun 	 */
74*4882a593Smuzhiyun 	return 0;
75*4882a593Smuzhiyun }
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun /*
78*4882a593Smuzhiyun  *	Perform the SIOCxIFxxx calls, inside rcu_read_lock()
79*4882a593Smuzhiyun  */
dev_ifsioc_locked(struct net * net,struct ifreq * ifr,unsigned int cmd)80*4882a593Smuzhiyun static int dev_ifsioc_locked(struct net *net, struct ifreq *ifr, unsigned int cmd)
81*4882a593Smuzhiyun {
82*4882a593Smuzhiyun 	int err;
83*4882a593Smuzhiyun 	struct net_device *dev = dev_get_by_name_rcu(net, ifr->ifr_name);
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun 	if (!dev)
86*4882a593Smuzhiyun 		return -ENODEV;
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun 	switch (cmd) {
89*4882a593Smuzhiyun 	case SIOCGIFFLAGS:	/* Get interface flags */
90*4882a593Smuzhiyun 		ifr->ifr_flags = (short) dev_get_flags(dev);
91*4882a593Smuzhiyun 		return 0;
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 	case SIOCGIFMETRIC:	/* Get the metric on the interface
94*4882a593Smuzhiyun 				   (currently unused) */
95*4882a593Smuzhiyun 		ifr->ifr_metric = 0;
96*4882a593Smuzhiyun 		return 0;
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 	case SIOCGIFMTU:	/* Get the MTU of a device */
99*4882a593Smuzhiyun 		ifr->ifr_mtu = dev->mtu;
100*4882a593Smuzhiyun 		return 0;
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 	case SIOCGIFSLAVE:
103*4882a593Smuzhiyun 		err = -EINVAL;
104*4882a593Smuzhiyun 		break;
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun 	case SIOCGIFMAP:
107*4882a593Smuzhiyun 		ifr->ifr_map.mem_start = dev->mem_start;
108*4882a593Smuzhiyun 		ifr->ifr_map.mem_end   = dev->mem_end;
109*4882a593Smuzhiyun 		ifr->ifr_map.base_addr = dev->base_addr;
110*4882a593Smuzhiyun 		ifr->ifr_map.irq       = dev->irq;
111*4882a593Smuzhiyun 		ifr->ifr_map.dma       = dev->dma;
112*4882a593Smuzhiyun 		ifr->ifr_map.port      = dev->if_port;
113*4882a593Smuzhiyun 		return 0;
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	case SIOCGIFINDEX:
116*4882a593Smuzhiyun 		ifr->ifr_ifindex = dev->ifindex;
117*4882a593Smuzhiyun 		return 0;
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 	case SIOCGIFTXQLEN:
120*4882a593Smuzhiyun 		ifr->ifr_qlen = dev->tx_queue_len;
121*4882a593Smuzhiyun 		return 0;
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 	default:
124*4882a593Smuzhiyun 		/* dev_ioctl() should ensure this case
125*4882a593Smuzhiyun 		 * is never reached
126*4882a593Smuzhiyun 		 */
127*4882a593Smuzhiyun 		WARN_ON(1);
128*4882a593Smuzhiyun 		err = -ENOTTY;
129*4882a593Smuzhiyun 		break;
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 	}
132*4882a593Smuzhiyun 	return err;
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun 
net_hwtstamp_validate(struct ifreq * ifr)135*4882a593Smuzhiyun static int net_hwtstamp_validate(struct ifreq *ifr)
136*4882a593Smuzhiyun {
137*4882a593Smuzhiyun 	struct hwtstamp_config cfg;
138*4882a593Smuzhiyun 	enum hwtstamp_tx_types tx_type;
139*4882a593Smuzhiyun 	enum hwtstamp_rx_filters rx_filter;
140*4882a593Smuzhiyun 	int tx_type_valid = 0;
141*4882a593Smuzhiyun 	int rx_filter_valid = 0;
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
144*4882a593Smuzhiyun 		return -EFAULT;
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun 	if (cfg.flags) /* reserved for future extensions */
147*4882a593Smuzhiyun 		return -EINVAL;
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 	tx_type = cfg.tx_type;
150*4882a593Smuzhiyun 	rx_filter = cfg.rx_filter;
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 	switch (tx_type) {
153*4882a593Smuzhiyun 	case HWTSTAMP_TX_OFF:
154*4882a593Smuzhiyun 	case HWTSTAMP_TX_ON:
155*4882a593Smuzhiyun 	case HWTSTAMP_TX_ONESTEP_SYNC:
156*4882a593Smuzhiyun 	case HWTSTAMP_TX_ONESTEP_P2P:
157*4882a593Smuzhiyun 		tx_type_valid = 1;
158*4882a593Smuzhiyun 		break;
159*4882a593Smuzhiyun 	case __HWTSTAMP_TX_CNT:
160*4882a593Smuzhiyun 		/* not a real value */
161*4882a593Smuzhiyun 		break;
162*4882a593Smuzhiyun 	}
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	switch (rx_filter) {
165*4882a593Smuzhiyun 	case HWTSTAMP_FILTER_NONE:
166*4882a593Smuzhiyun 	case HWTSTAMP_FILTER_ALL:
167*4882a593Smuzhiyun 	case HWTSTAMP_FILTER_SOME:
168*4882a593Smuzhiyun 	case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
169*4882a593Smuzhiyun 	case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
170*4882a593Smuzhiyun 	case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
171*4882a593Smuzhiyun 	case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
172*4882a593Smuzhiyun 	case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
173*4882a593Smuzhiyun 	case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
174*4882a593Smuzhiyun 	case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
175*4882a593Smuzhiyun 	case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
176*4882a593Smuzhiyun 	case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
177*4882a593Smuzhiyun 	case HWTSTAMP_FILTER_PTP_V2_EVENT:
178*4882a593Smuzhiyun 	case HWTSTAMP_FILTER_PTP_V2_SYNC:
179*4882a593Smuzhiyun 	case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
180*4882a593Smuzhiyun 	case HWTSTAMP_FILTER_NTP_ALL:
181*4882a593Smuzhiyun 		rx_filter_valid = 1;
182*4882a593Smuzhiyun 		break;
183*4882a593Smuzhiyun 	case __HWTSTAMP_FILTER_CNT:
184*4882a593Smuzhiyun 		/* not a real value */
185*4882a593Smuzhiyun 		break;
186*4882a593Smuzhiyun 	}
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 	if (!tx_type_valid || !rx_filter_valid)
189*4882a593Smuzhiyun 		return -ERANGE;
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 	return 0;
192*4882a593Smuzhiyun }
193*4882a593Smuzhiyun 
dev_do_ioctl(struct net_device * dev,struct ifreq * ifr,unsigned int cmd)194*4882a593Smuzhiyun static int dev_do_ioctl(struct net_device *dev,
195*4882a593Smuzhiyun 			struct ifreq *ifr, unsigned int cmd)
196*4882a593Smuzhiyun {
197*4882a593Smuzhiyun 	const struct net_device_ops *ops = dev->netdev_ops;
198*4882a593Smuzhiyun 	int err = -EOPNOTSUPP;
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun 	err = dsa_ndo_do_ioctl(dev, ifr, cmd);
201*4882a593Smuzhiyun 	if (err == 0 || err != -EOPNOTSUPP)
202*4882a593Smuzhiyun 		return err;
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun 	if (ops->ndo_do_ioctl) {
205*4882a593Smuzhiyun 		if (netif_device_present(dev))
206*4882a593Smuzhiyun 			err = ops->ndo_do_ioctl(dev, ifr, cmd);
207*4882a593Smuzhiyun 		else
208*4882a593Smuzhiyun 			err = -ENODEV;
209*4882a593Smuzhiyun 	}
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun 	return err;
212*4882a593Smuzhiyun }
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun /*
215*4882a593Smuzhiyun  *	Perform the SIOCxIFxxx calls, inside rtnl_lock()
216*4882a593Smuzhiyun  */
dev_ifsioc(struct net * net,struct ifreq * ifr,unsigned int cmd)217*4882a593Smuzhiyun static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd)
218*4882a593Smuzhiyun {
219*4882a593Smuzhiyun 	int err;
220*4882a593Smuzhiyun 	struct net_device *dev = __dev_get_by_name(net, ifr->ifr_name);
221*4882a593Smuzhiyun 	const struct net_device_ops *ops;
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun 	if (!dev)
224*4882a593Smuzhiyun 		return -ENODEV;
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun 	ops = dev->netdev_ops;
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun 	switch (cmd) {
229*4882a593Smuzhiyun 	case SIOCSIFFLAGS:	/* Set interface flags */
230*4882a593Smuzhiyun 		return dev_change_flags(dev, ifr->ifr_flags, NULL);
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 	case SIOCSIFMETRIC:	/* Set the metric on the interface
233*4882a593Smuzhiyun 				   (currently unused) */
234*4882a593Smuzhiyun 		return -EOPNOTSUPP;
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun 	case SIOCSIFMTU:	/* Set the MTU of a device */
237*4882a593Smuzhiyun 		return dev_set_mtu(dev, ifr->ifr_mtu);
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	case SIOCSIFHWADDR:
240*4882a593Smuzhiyun 		if (dev->addr_len > sizeof(struct sockaddr))
241*4882a593Smuzhiyun 			return -EINVAL;
242*4882a593Smuzhiyun 		return dev_set_mac_address_user(dev, &ifr->ifr_hwaddr, NULL);
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun 	case SIOCSIFHWBROADCAST:
245*4882a593Smuzhiyun 		if (ifr->ifr_hwaddr.sa_family != dev->type)
246*4882a593Smuzhiyun 			return -EINVAL;
247*4882a593Smuzhiyun 		memcpy(dev->broadcast, ifr->ifr_hwaddr.sa_data,
248*4882a593Smuzhiyun 		       min(sizeof(ifr->ifr_hwaddr.sa_data),
249*4882a593Smuzhiyun 			   (size_t)dev->addr_len));
250*4882a593Smuzhiyun 		call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
251*4882a593Smuzhiyun 		return 0;
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 	case SIOCSIFMAP:
254*4882a593Smuzhiyun 		if (ops->ndo_set_config) {
255*4882a593Smuzhiyun 			if (!netif_device_present(dev))
256*4882a593Smuzhiyun 				return -ENODEV;
257*4882a593Smuzhiyun 			return ops->ndo_set_config(dev, &ifr->ifr_map);
258*4882a593Smuzhiyun 		}
259*4882a593Smuzhiyun 		return -EOPNOTSUPP;
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun 	case SIOCADDMULTI:
262*4882a593Smuzhiyun 		if (!ops->ndo_set_rx_mode ||
263*4882a593Smuzhiyun 		    ifr->ifr_hwaddr.sa_family != AF_UNSPEC)
264*4882a593Smuzhiyun 			return -EINVAL;
265*4882a593Smuzhiyun 		if (!netif_device_present(dev))
266*4882a593Smuzhiyun 			return -ENODEV;
267*4882a593Smuzhiyun 		return dev_mc_add_global(dev, ifr->ifr_hwaddr.sa_data);
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun 	case SIOCDELMULTI:
270*4882a593Smuzhiyun 		if (!ops->ndo_set_rx_mode ||
271*4882a593Smuzhiyun 		    ifr->ifr_hwaddr.sa_family != AF_UNSPEC)
272*4882a593Smuzhiyun 			return -EINVAL;
273*4882a593Smuzhiyun 		if (!netif_device_present(dev))
274*4882a593Smuzhiyun 			return -ENODEV;
275*4882a593Smuzhiyun 		return dev_mc_del_global(dev, ifr->ifr_hwaddr.sa_data);
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun 	case SIOCSIFTXQLEN:
278*4882a593Smuzhiyun 		if (ifr->ifr_qlen < 0)
279*4882a593Smuzhiyun 			return -EINVAL;
280*4882a593Smuzhiyun 		return dev_change_tx_queue_len(dev, ifr->ifr_qlen);
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun 	case SIOCSIFNAME:
283*4882a593Smuzhiyun 		ifr->ifr_newname[IFNAMSIZ-1] = '\0';
284*4882a593Smuzhiyun 		return dev_change_name(dev, ifr->ifr_newname);
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 	case SIOCSHWTSTAMP:
287*4882a593Smuzhiyun 		err = net_hwtstamp_validate(ifr);
288*4882a593Smuzhiyun 		if (err)
289*4882a593Smuzhiyun 			return err;
290*4882a593Smuzhiyun 		fallthrough;
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun 	/*
293*4882a593Smuzhiyun 	 *	Unknown or private ioctl
294*4882a593Smuzhiyun 	 */
295*4882a593Smuzhiyun 	default:
296*4882a593Smuzhiyun 		if ((cmd >= SIOCDEVPRIVATE &&
297*4882a593Smuzhiyun 		    cmd <= SIOCDEVPRIVATE + 15) ||
298*4882a593Smuzhiyun 		    cmd == SIOCBONDENSLAVE ||
299*4882a593Smuzhiyun 		    cmd == SIOCBONDRELEASE ||
300*4882a593Smuzhiyun 		    cmd == SIOCBONDSETHWADDR ||
301*4882a593Smuzhiyun 		    cmd == SIOCBONDSLAVEINFOQUERY ||
302*4882a593Smuzhiyun 		    cmd == SIOCBONDINFOQUERY ||
303*4882a593Smuzhiyun 		    cmd == SIOCBONDCHANGEACTIVE ||
304*4882a593Smuzhiyun 		    cmd == SIOCGMIIPHY ||
305*4882a593Smuzhiyun 		    cmd == SIOCGMIIREG ||
306*4882a593Smuzhiyun 		    cmd == SIOCSMIIREG ||
307*4882a593Smuzhiyun 		    cmd == SIOCBRADDIF ||
308*4882a593Smuzhiyun 		    cmd == SIOCBRDELIF ||
309*4882a593Smuzhiyun 		    cmd == SIOCSHWTSTAMP ||
310*4882a593Smuzhiyun 		    cmd == SIOCGHWTSTAMP ||
311*4882a593Smuzhiyun 		    cmd == SIOCWANDEV) {
312*4882a593Smuzhiyun 			err = dev_do_ioctl(dev, ifr, cmd);
313*4882a593Smuzhiyun 		} else
314*4882a593Smuzhiyun 			err = -EINVAL;
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun 	}
317*4882a593Smuzhiyun 	return err;
318*4882a593Smuzhiyun }
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun /**
321*4882a593Smuzhiyun  *	dev_load 	- load a network module
322*4882a593Smuzhiyun  *	@net: the applicable net namespace
323*4882a593Smuzhiyun  *	@name: name of interface
324*4882a593Smuzhiyun  *
325*4882a593Smuzhiyun  *	If a network interface is not present and the process has suitable
326*4882a593Smuzhiyun  *	privileges this function loads the module. If module loading is not
327*4882a593Smuzhiyun  *	available in this kernel then it becomes a nop.
328*4882a593Smuzhiyun  */
329*4882a593Smuzhiyun 
dev_load(struct net * net,const char * name)330*4882a593Smuzhiyun void dev_load(struct net *net, const char *name)
331*4882a593Smuzhiyun {
332*4882a593Smuzhiyun 	struct net_device *dev;
333*4882a593Smuzhiyun 	int no_module;
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 	rcu_read_lock();
336*4882a593Smuzhiyun 	dev = dev_get_by_name_rcu(net, name);
337*4882a593Smuzhiyun 	rcu_read_unlock();
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun 	no_module = !dev;
340*4882a593Smuzhiyun 	if (no_module && capable(CAP_NET_ADMIN))
341*4882a593Smuzhiyun 		no_module = request_module("netdev-%s", name);
342*4882a593Smuzhiyun 	if (no_module && capable(CAP_SYS_MODULE))
343*4882a593Smuzhiyun 		request_module("%s", name);
344*4882a593Smuzhiyun }
345*4882a593Smuzhiyun EXPORT_SYMBOL(dev_load);
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun /*
348*4882a593Smuzhiyun  *	This function handles all "interface"-type I/O control requests. The actual
349*4882a593Smuzhiyun  *	'doing' part of this is dev_ifsioc above.
350*4882a593Smuzhiyun  */
351*4882a593Smuzhiyun 
352*4882a593Smuzhiyun /**
353*4882a593Smuzhiyun  *	dev_ioctl	-	network device ioctl
354*4882a593Smuzhiyun  *	@net: the applicable net namespace
355*4882a593Smuzhiyun  *	@cmd: command to issue
356*4882a593Smuzhiyun  *	@ifr: pointer to a struct ifreq in user space
357*4882a593Smuzhiyun  *	@need_copyout: whether or not copy_to_user() should be called
358*4882a593Smuzhiyun  *
359*4882a593Smuzhiyun  *	Issue ioctl functions to devices. This is normally called by the
360*4882a593Smuzhiyun  *	user space syscall interfaces but can sometimes be useful for
361*4882a593Smuzhiyun  *	other purposes. The return value is the return from the syscall if
362*4882a593Smuzhiyun  *	positive or a negative errno code on error.
363*4882a593Smuzhiyun  */
364*4882a593Smuzhiyun 
dev_ioctl(struct net * net,unsigned int cmd,struct ifreq * ifr,bool * need_copyout)365*4882a593Smuzhiyun int dev_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr, bool *need_copyout)
366*4882a593Smuzhiyun {
367*4882a593Smuzhiyun 	int ret;
368*4882a593Smuzhiyun 	char *colon;
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun 	if (need_copyout)
371*4882a593Smuzhiyun 		*need_copyout = true;
372*4882a593Smuzhiyun 	if (cmd == SIOCGIFNAME)
373*4882a593Smuzhiyun 		return dev_ifname(net, ifr);
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun 	ifr->ifr_name[IFNAMSIZ-1] = 0;
376*4882a593Smuzhiyun 
377*4882a593Smuzhiyun 	colon = strchr(ifr->ifr_name, ':');
378*4882a593Smuzhiyun 	if (colon)
379*4882a593Smuzhiyun 		*colon = 0;
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun 	/*
382*4882a593Smuzhiyun 	 *	See which interface the caller is talking about.
383*4882a593Smuzhiyun 	 */
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun 	switch (cmd) {
386*4882a593Smuzhiyun 	case SIOCGIFHWADDR:
387*4882a593Smuzhiyun 		dev_load(net, ifr->ifr_name);
388*4882a593Smuzhiyun 		ret = dev_get_mac_address(&ifr->ifr_hwaddr, net, ifr->ifr_name);
389*4882a593Smuzhiyun 		if (colon)
390*4882a593Smuzhiyun 			*colon = ':';
391*4882a593Smuzhiyun 		return ret;
392*4882a593Smuzhiyun 	/*
393*4882a593Smuzhiyun 	 *	These ioctl calls:
394*4882a593Smuzhiyun 	 *	- can be done by all.
395*4882a593Smuzhiyun 	 *	- atomic and do not require locking.
396*4882a593Smuzhiyun 	 *	- return a value
397*4882a593Smuzhiyun 	 */
398*4882a593Smuzhiyun 	case SIOCGIFFLAGS:
399*4882a593Smuzhiyun 	case SIOCGIFMETRIC:
400*4882a593Smuzhiyun 	case SIOCGIFMTU:
401*4882a593Smuzhiyun 	case SIOCGIFSLAVE:
402*4882a593Smuzhiyun 	case SIOCGIFMAP:
403*4882a593Smuzhiyun 	case SIOCGIFINDEX:
404*4882a593Smuzhiyun 	case SIOCGIFTXQLEN:
405*4882a593Smuzhiyun 		dev_load(net, ifr->ifr_name);
406*4882a593Smuzhiyun 		rcu_read_lock();
407*4882a593Smuzhiyun 		ret = dev_ifsioc_locked(net, ifr, cmd);
408*4882a593Smuzhiyun 		rcu_read_unlock();
409*4882a593Smuzhiyun 		if (colon)
410*4882a593Smuzhiyun 			*colon = ':';
411*4882a593Smuzhiyun 		return ret;
412*4882a593Smuzhiyun 
413*4882a593Smuzhiyun 	case SIOCETHTOOL:
414*4882a593Smuzhiyun 		dev_load(net, ifr->ifr_name);
415*4882a593Smuzhiyun 		rtnl_lock();
416*4882a593Smuzhiyun 		ret = dev_ethtool(net, ifr);
417*4882a593Smuzhiyun 		rtnl_unlock();
418*4882a593Smuzhiyun 		if (colon)
419*4882a593Smuzhiyun 			*colon = ':';
420*4882a593Smuzhiyun 		return ret;
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun 	/*
423*4882a593Smuzhiyun 	 *	These ioctl calls:
424*4882a593Smuzhiyun 	 *	- require superuser power.
425*4882a593Smuzhiyun 	 *	- require strict serialization.
426*4882a593Smuzhiyun 	 *	- return a value
427*4882a593Smuzhiyun 	 */
428*4882a593Smuzhiyun 	case SIOCGMIIPHY:
429*4882a593Smuzhiyun 	case SIOCGMIIREG:
430*4882a593Smuzhiyun 	case SIOCSIFNAME:
431*4882a593Smuzhiyun 		dev_load(net, ifr->ifr_name);
432*4882a593Smuzhiyun 		if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
433*4882a593Smuzhiyun 			return -EPERM;
434*4882a593Smuzhiyun 		rtnl_lock();
435*4882a593Smuzhiyun 		ret = dev_ifsioc(net, ifr, cmd);
436*4882a593Smuzhiyun 		rtnl_unlock();
437*4882a593Smuzhiyun 		if (colon)
438*4882a593Smuzhiyun 			*colon = ':';
439*4882a593Smuzhiyun 		return ret;
440*4882a593Smuzhiyun 
441*4882a593Smuzhiyun 	/*
442*4882a593Smuzhiyun 	 *	These ioctl calls:
443*4882a593Smuzhiyun 	 *	- require superuser power.
444*4882a593Smuzhiyun 	 *	- require strict serialization.
445*4882a593Smuzhiyun 	 *	- do not return a value
446*4882a593Smuzhiyun 	 */
447*4882a593Smuzhiyun 	case SIOCSIFMAP:
448*4882a593Smuzhiyun 	case SIOCSIFTXQLEN:
449*4882a593Smuzhiyun 		if (!capable(CAP_NET_ADMIN))
450*4882a593Smuzhiyun 			return -EPERM;
451*4882a593Smuzhiyun 		fallthrough;
452*4882a593Smuzhiyun 	/*
453*4882a593Smuzhiyun 	 *	These ioctl calls:
454*4882a593Smuzhiyun 	 *	- require local superuser power.
455*4882a593Smuzhiyun 	 *	- require strict serialization.
456*4882a593Smuzhiyun 	 *	- do not return a value
457*4882a593Smuzhiyun 	 */
458*4882a593Smuzhiyun 	case SIOCSIFFLAGS:
459*4882a593Smuzhiyun 	case SIOCSIFMETRIC:
460*4882a593Smuzhiyun 	case SIOCSIFMTU:
461*4882a593Smuzhiyun 	case SIOCSIFHWADDR:
462*4882a593Smuzhiyun 	case SIOCSIFSLAVE:
463*4882a593Smuzhiyun 	case SIOCADDMULTI:
464*4882a593Smuzhiyun 	case SIOCDELMULTI:
465*4882a593Smuzhiyun 	case SIOCSIFHWBROADCAST:
466*4882a593Smuzhiyun 	case SIOCSMIIREG:
467*4882a593Smuzhiyun 	case SIOCBONDENSLAVE:
468*4882a593Smuzhiyun 	case SIOCBONDRELEASE:
469*4882a593Smuzhiyun 	case SIOCBONDSETHWADDR:
470*4882a593Smuzhiyun 	case SIOCBONDCHANGEACTIVE:
471*4882a593Smuzhiyun 	case SIOCBRADDIF:
472*4882a593Smuzhiyun 	case SIOCBRDELIF:
473*4882a593Smuzhiyun 	case SIOCSHWTSTAMP:
474*4882a593Smuzhiyun 		if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
475*4882a593Smuzhiyun 			return -EPERM;
476*4882a593Smuzhiyun 		fallthrough;
477*4882a593Smuzhiyun 	case SIOCBONDSLAVEINFOQUERY:
478*4882a593Smuzhiyun 	case SIOCBONDINFOQUERY:
479*4882a593Smuzhiyun 		dev_load(net, ifr->ifr_name);
480*4882a593Smuzhiyun 		rtnl_lock();
481*4882a593Smuzhiyun 		ret = dev_ifsioc(net, ifr, cmd);
482*4882a593Smuzhiyun 		rtnl_unlock();
483*4882a593Smuzhiyun 		if (need_copyout)
484*4882a593Smuzhiyun 			*need_copyout = false;
485*4882a593Smuzhiyun 		return ret;
486*4882a593Smuzhiyun 
487*4882a593Smuzhiyun 	case SIOCGIFMEM:
488*4882a593Smuzhiyun 		/* Get the per device memory space. We can add this but
489*4882a593Smuzhiyun 		 * currently do not support it */
490*4882a593Smuzhiyun 	case SIOCSIFMEM:
491*4882a593Smuzhiyun 		/* Set the per device memory buffer space.
492*4882a593Smuzhiyun 		 * Not applicable in our case */
493*4882a593Smuzhiyun 	case SIOCSIFLINK:
494*4882a593Smuzhiyun 		return -ENOTTY;
495*4882a593Smuzhiyun 
496*4882a593Smuzhiyun 	/*
497*4882a593Smuzhiyun 	 *	Unknown or private ioctl.
498*4882a593Smuzhiyun 	 */
499*4882a593Smuzhiyun 	default:
500*4882a593Smuzhiyun 		if (cmd == SIOCWANDEV ||
501*4882a593Smuzhiyun 		    cmd == SIOCGHWTSTAMP ||
502*4882a593Smuzhiyun 		    (cmd >= SIOCDEVPRIVATE &&
503*4882a593Smuzhiyun 		     cmd <= SIOCDEVPRIVATE + 15)) {
504*4882a593Smuzhiyun 			dev_load(net, ifr->ifr_name);
505*4882a593Smuzhiyun 			rtnl_lock();
506*4882a593Smuzhiyun 			ret = dev_ifsioc(net, ifr, cmd);
507*4882a593Smuzhiyun 			rtnl_unlock();
508*4882a593Smuzhiyun 			return ret;
509*4882a593Smuzhiyun 		}
510*4882a593Smuzhiyun 		return -ENOTTY;
511*4882a593Smuzhiyun 	}
512*4882a593Smuzhiyun }
513