| .. | .. |
|---|
| 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); |
|---|