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