.. | .. |
---|
1 | 1 | // SPDX-License-Identifier: GPL-2.0 |
---|
2 | 2 | #include <linux/kmod.h> |
---|
3 | 3 | #include <linux/netdevice.h> |
---|
| 4 | +#include <linux/inetdevice.h> |
---|
4 | 5 | #include <linux/etherdevice.h> |
---|
5 | 6 | #include <linux/rtnetlink.h> |
---|
6 | 7 | #include <linux/net_tstamp.h> |
---|
7 | 8 | #include <linux/wireless.h> |
---|
| 9 | +#include <net/dsa.h> |
---|
8 | 10 | #include <net/wext.h> |
---|
9 | 11 | |
---|
10 | 12 | /* |
---|
.. | .. |
---|
24 | 26 | return netdev_get_name(net, ifr->ifr_name, ifr->ifr_ifindex); |
---|
25 | 27 | } |
---|
26 | 28 | |
---|
27 | | -static gifconf_func_t *gifconf_list[NPROTO]; |
---|
28 | | - |
---|
29 | | -/** |
---|
30 | | - * register_gifconf - register a SIOCGIF handler |
---|
31 | | - * @family: Address family |
---|
32 | | - * @gifconf: Function handler |
---|
33 | | - * |
---|
34 | | - * Register protocol dependent address dumping routines. The handler |
---|
35 | | - * that is passed must not be freed or reused until it has been replaced |
---|
36 | | - * by another handler. |
---|
37 | | - */ |
---|
38 | | -int register_gifconf(unsigned int family, gifconf_func_t *gifconf) |
---|
39 | | -{ |
---|
40 | | - if (family >= NPROTO) |
---|
41 | | - return -EINVAL; |
---|
42 | | - gifconf_list[family] = gifconf; |
---|
43 | | - return 0; |
---|
44 | | -} |
---|
45 | | -EXPORT_SYMBOL(register_gifconf); |
---|
46 | | - |
---|
47 | 29 | /* |
---|
48 | 30 | * Perform a SIOCGIFCONF call. This structure will change |
---|
49 | 31 | * size eventually, and there is nothing I can do about it. |
---|
.. | .. |
---|
56 | 38 | char __user *pos; |
---|
57 | 39 | int len; |
---|
58 | 40 | int total; |
---|
59 | | - int i; |
---|
60 | 41 | |
---|
61 | 42 | /* |
---|
62 | 43 | * Fetch the caller's info block. |
---|
.. | .. |
---|
71 | 52 | |
---|
72 | 53 | total = 0; |
---|
73 | 54 | for_each_netdev(net, dev) { |
---|
74 | | - for (i = 0; i < NPROTO; i++) { |
---|
75 | | - if (gifconf_list[i]) { |
---|
76 | | - int done; |
---|
77 | | - if (!pos) |
---|
78 | | - done = gifconf_list[i](dev, NULL, 0, size); |
---|
79 | | - else |
---|
80 | | - done = gifconf_list[i](dev, pos + total, |
---|
81 | | - len - total, size); |
---|
82 | | - if (done < 0) |
---|
83 | | - return -EFAULT; |
---|
84 | | - total += done; |
---|
85 | | - } |
---|
86 | | - } |
---|
| 55 | + int done; |
---|
| 56 | + if (!pos) |
---|
| 57 | + done = inet_gifconf(dev, NULL, 0, size); |
---|
| 58 | + else |
---|
| 59 | + done = inet_gifconf(dev, pos + total, |
---|
| 60 | + len - total, size); |
---|
| 61 | + if (done < 0) |
---|
| 62 | + return -EFAULT; |
---|
| 63 | + total += done; |
---|
87 | 64 | } |
---|
88 | 65 | |
---|
89 | 66 | /* |
---|
.. | .. |
---|
120 | 97 | |
---|
121 | 98 | case SIOCGIFMTU: /* Get the MTU of a device */ |
---|
122 | 99 | ifr->ifr_mtu = dev->mtu; |
---|
123 | | - return 0; |
---|
124 | | - |
---|
125 | | - case SIOCGIFHWADDR: |
---|
126 | | - if (!dev->addr_len) |
---|
127 | | - memset(ifr->ifr_hwaddr.sa_data, 0, |
---|
128 | | - sizeof(ifr->ifr_hwaddr.sa_data)); |
---|
129 | | - else |
---|
130 | | - memcpy(ifr->ifr_hwaddr.sa_data, dev->dev_addr, |
---|
131 | | - min(sizeof(ifr->ifr_hwaddr.sa_data), |
---|
132 | | - (size_t)dev->addr_len)); |
---|
133 | | - ifr->ifr_hwaddr.sa_family = dev->type; |
---|
134 | 100 | return 0; |
---|
135 | 101 | |
---|
136 | 102 | case SIOCGIFSLAVE: |
---|
.. | .. |
---|
187 | 153 | case HWTSTAMP_TX_OFF: |
---|
188 | 154 | case HWTSTAMP_TX_ON: |
---|
189 | 155 | case HWTSTAMP_TX_ONESTEP_SYNC: |
---|
| 156 | + case HWTSTAMP_TX_ONESTEP_P2P: |
---|
190 | 157 | tx_type_valid = 1; |
---|
| 158 | + break; |
---|
| 159 | + case __HWTSTAMP_TX_CNT: |
---|
| 160 | + /* not a real value */ |
---|
191 | 161 | break; |
---|
192 | 162 | } |
---|
193 | 163 | |
---|
.. | .. |
---|
210 | 180 | case HWTSTAMP_FILTER_NTP_ALL: |
---|
211 | 181 | rx_filter_valid = 1; |
---|
212 | 182 | break; |
---|
| 183 | + case __HWTSTAMP_FILTER_CNT: |
---|
| 184 | + /* not a real value */ |
---|
| 185 | + break; |
---|
213 | 186 | } |
---|
214 | 187 | |
---|
215 | 188 | if (!tx_type_valid || !rx_filter_valid) |
---|
216 | 189 | return -ERANGE; |
---|
217 | 190 | |
---|
218 | 191 | return 0; |
---|
| 192 | +} |
---|
| 193 | + |
---|
| 194 | +static int dev_do_ioctl(struct net_device *dev, |
---|
| 195 | + struct ifreq *ifr, unsigned int cmd) |
---|
| 196 | +{ |
---|
| 197 | + const struct net_device_ops *ops = dev->netdev_ops; |
---|
| 198 | + int err = -EOPNOTSUPP; |
---|
| 199 | + |
---|
| 200 | + err = dsa_ndo_do_ioctl(dev, ifr, cmd); |
---|
| 201 | + if (err == 0 || err != -EOPNOTSUPP) |
---|
| 202 | + return err; |
---|
| 203 | + |
---|
| 204 | + if (ops->ndo_do_ioctl) { |
---|
| 205 | + if (netif_device_present(dev)) |
---|
| 206 | + err = ops->ndo_do_ioctl(dev, ifr, cmd); |
---|
| 207 | + else |
---|
| 208 | + err = -ENODEV; |
---|
| 209 | + } |
---|
| 210 | + |
---|
| 211 | + return err; |
---|
219 | 212 | } |
---|
220 | 213 | |
---|
221 | 214 | /* |
---|
.. | .. |
---|
234 | 227 | |
---|
235 | 228 | switch (cmd) { |
---|
236 | 229 | case SIOCSIFFLAGS: /* Set interface flags */ |
---|
237 | | - return dev_change_flags(dev, ifr->ifr_flags); |
---|
| 230 | + return dev_change_flags(dev, ifr->ifr_flags, NULL); |
---|
238 | 231 | |
---|
239 | 232 | case SIOCSIFMETRIC: /* Set the metric on the interface |
---|
240 | 233 | (currently unused) */ |
---|
.. | .. |
---|
246 | 239 | case SIOCSIFHWADDR: |
---|
247 | 240 | if (dev->addr_len > sizeof(struct sockaddr)) |
---|
248 | 241 | return -EINVAL; |
---|
249 | | - return dev_set_mac_address(dev, &ifr->ifr_hwaddr); |
---|
| 242 | + return dev_set_mac_address_user(dev, &ifr->ifr_hwaddr, NULL); |
---|
250 | 243 | |
---|
251 | 244 | case SIOCSIFHWBROADCAST: |
---|
252 | 245 | if (ifr->ifr_hwaddr.sa_family != dev->type) |
---|
.. | .. |
---|
294 | 287 | err = net_hwtstamp_validate(ifr); |
---|
295 | 288 | if (err) |
---|
296 | 289 | return err; |
---|
297 | | - /* fall through */ |
---|
| 290 | + fallthrough; |
---|
298 | 291 | |
---|
299 | 292 | /* |
---|
300 | 293 | * Unknown or private ioctl |
---|
.. | .. |
---|
316 | 309 | cmd == SIOCSHWTSTAMP || |
---|
317 | 310 | cmd == SIOCGHWTSTAMP || |
---|
318 | 311 | cmd == SIOCWANDEV) { |
---|
319 | | - err = -EOPNOTSUPP; |
---|
320 | | - if (ops->ndo_do_ioctl) { |
---|
321 | | - if (netif_device_present(dev)) |
---|
322 | | - err = ops->ndo_do_ioctl(dev, ifr, cmd); |
---|
323 | | - else |
---|
324 | | - err = -ENODEV; |
---|
325 | | - } |
---|
| 312 | + err = dev_do_ioctl(dev, ifr, cmd); |
---|
326 | 313 | } else |
---|
327 | 314 | err = -EINVAL; |
---|
328 | 315 | |
---|
.. | .. |
---|
366 | 353 | * dev_ioctl - network device ioctl |
---|
367 | 354 | * @net: the applicable net namespace |
---|
368 | 355 | * @cmd: command to issue |
---|
369 | | - * @arg: pointer to a struct ifreq in user space |
---|
| 356 | + * @ifr: pointer to a struct ifreq in user space |
---|
| 357 | + * @need_copyout: whether or not copy_to_user() should be called |
---|
370 | 358 | * |
---|
371 | 359 | * Issue ioctl functions to devices. This is normally called by the |
---|
372 | 360 | * user space syscall interfaces but can sometimes be useful for |
---|
.. | .. |
---|
395 | 383 | */ |
---|
396 | 384 | |
---|
397 | 385 | switch (cmd) { |
---|
| 386 | + case SIOCGIFHWADDR: |
---|
| 387 | + dev_load(net, ifr->ifr_name); |
---|
| 388 | + ret = dev_get_mac_address(&ifr->ifr_hwaddr, net, ifr->ifr_name); |
---|
| 389 | + if (colon) |
---|
| 390 | + *colon = ':'; |
---|
| 391 | + return ret; |
---|
398 | 392 | /* |
---|
399 | 393 | * These ioctl calls: |
---|
400 | 394 | * - can be done by all. |
---|
.. | .. |
---|
404 | 398 | case SIOCGIFFLAGS: |
---|
405 | 399 | case SIOCGIFMETRIC: |
---|
406 | 400 | case SIOCGIFMTU: |
---|
407 | | - case SIOCGIFHWADDR: |
---|
408 | 401 | case SIOCGIFSLAVE: |
---|
409 | 402 | case SIOCGIFMAP: |
---|
410 | 403 | case SIOCGIFINDEX: |
---|
.. | .. |
---|
417 | 410 | *colon = ':'; |
---|
418 | 411 | return ret; |
---|
419 | 412 | |
---|
420 | | -#ifdef CONFIG_ETHTOOL |
---|
421 | 413 | case SIOCETHTOOL: |
---|
422 | 414 | dev_load(net, ifr->ifr_name); |
---|
423 | 415 | rtnl_lock(); |
---|
.. | .. |
---|
426 | 418 | if (colon) |
---|
427 | 419 | *colon = ':'; |
---|
428 | 420 | return ret; |
---|
429 | | -#endif |
---|
430 | 421 | |
---|
431 | 422 | /* |
---|
432 | 423 | * These ioctl calls: |
---|
.. | .. |
---|
457 | 448 | case SIOCSIFTXQLEN: |
---|
458 | 449 | if (!capable(CAP_NET_ADMIN)) |
---|
459 | 450 | return -EPERM; |
---|
460 | | - /* fall through */ |
---|
| 451 | + fallthrough; |
---|
461 | 452 | /* |
---|
462 | 453 | * These ioctl calls: |
---|
463 | 454 | * - require local superuser power. |
---|
.. | .. |
---|
482 | 473 | case SIOCSHWTSTAMP: |
---|
483 | 474 | if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) |
---|
484 | 475 | return -EPERM; |
---|
485 | | - /* fall through */ |
---|
| 476 | + fallthrough; |
---|
486 | 477 | case SIOCBONDSLAVEINFOQUERY: |
---|
487 | 478 | case SIOCBONDINFOQUERY: |
---|
488 | 479 | dev_load(net, ifr->ifr_name); |
---|