18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#include <linux/kmod.h> 38c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 48c2ecf20Sopenharmony_ci#include <linux/inetdevice.h> 58c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 68c2ecf20Sopenharmony_ci#include <linux/rtnetlink.h> 78c2ecf20Sopenharmony_ci#include <linux/net_tstamp.h> 88c2ecf20Sopenharmony_ci#include <linux/wireless.h> 98c2ecf20Sopenharmony_ci#include <net/dsa.h> 108c2ecf20Sopenharmony_ci#include <net/wext.h> 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci/* 138c2ecf20Sopenharmony_ci * Map an interface index to its name (SIOCGIFNAME) 148c2ecf20Sopenharmony_ci */ 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci/* 178c2ecf20Sopenharmony_ci * We need this ioctl for efficient implementation of the 188c2ecf20Sopenharmony_ci * if_indextoname() function required by the IPv6 API. Without 198c2ecf20Sopenharmony_ci * it, we would have to search all the interfaces to find a 208c2ecf20Sopenharmony_ci * match. --pb 218c2ecf20Sopenharmony_ci */ 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistatic int dev_ifname(struct net *net, struct ifreq *ifr) 248c2ecf20Sopenharmony_ci{ 258c2ecf20Sopenharmony_ci ifr->ifr_name[IFNAMSIZ-1] = 0; 268c2ecf20Sopenharmony_ci return netdev_get_name(net, ifr->ifr_name, ifr->ifr_ifindex); 278c2ecf20Sopenharmony_ci} 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci/* 308c2ecf20Sopenharmony_ci * Perform a SIOCGIFCONF call. This structure will change 318c2ecf20Sopenharmony_ci * size eventually, and there is nothing I can do about it. 328c2ecf20Sopenharmony_ci * Thus we will need a 'compatibility mode'. 338c2ecf20Sopenharmony_ci */ 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ciint dev_ifconf(struct net *net, struct ifconf *ifc, int size) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci struct net_device *dev; 388c2ecf20Sopenharmony_ci char __user *pos; 398c2ecf20Sopenharmony_ci int len; 408c2ecf20Sopenharmony_ci int total; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci /* 438c2ecf20Sopenharmony_ci * Fetch the caller's info block. 448c2ecf20Sopenharmony_ci */ 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci pos = ifc->ifc_buf; 478c2ecf20Sopenharmony_ci len = ifc->ifc_len; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci /* 508c2ecf20Sopenharmony_ci * Loop over the interfaces, and write an info block for each. 518c2ecf20Sopenharmony_ci */ 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci total = 0; 548c2ecf20Sopenharmony_ci for_each_netdev(net, dev) { 558c2ecf20Sopenharmony_ci int done; 568c2ecf20Sopenharmony_ci if (!pos) 578c2ecf20Sopenharmony_ci done = inet_gifconf(dev, NULL, 0, size); 588c2ecf20Sopenharmony_ci else 598c2ecf20Sopenharmony_ci done = inet_gifconf(dev, pos + total, 608c2ecf20Sopenharmony_ci len - total, size); 618c2ecf20Sopenharmony_ci if (done < 0) 628c2ecf20Sopenharmony_ci return -EFAULT; 638c2ecf20Sopenharmony_ci total += done; 648c2ecf20Sopenharmony_ci } 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci /* 678c2ecf20Sopenharmony_ci * All done. Write the updated control block back to the caller. 688c2ecf20Sopenharmony_ci */ 698c2ecf20Sopenharmony_ci ifc->ifc_len = total; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci /* 728c2ecf20Sopenharmony_ci * Both BSD and Solaris return 0 here, so we do too. 738c2ecf20Sopenharmony_ci */ 748c2ecf20Sopenharmony_ci return 0; 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci/* 788c2ecf20Sopenharmony_ci * Perform the SIOCxIFxxx calls, inside rcu_read_lock() 798c2ecf20Sopenharmony_ci */ 808c2ecf20Sopenharmony_cistatic int dev_ifsioc_locked(struct net *net, struct ifreq *ifr, unsigned int cmd) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci int err; 838c2ecf20Sopenharmony_ci struct net_device *dev = dev_get_by_name_rcu(net, ifr->ifr_name); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci if (!dev) 868c2ecf20Sopenharmony_ci return -ENODEV; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci switch (cmd) { 898c2ecf20Sopenharmony_ci case SIOCGIFFLAGS: /* Get interface flags */ 908c2ecf20Sopenharmony_ci ifr->ifr_flags = (short) dev_get_flags(dev); 918c2ecf20Sopenharmony_ci return 0; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci case SIOCGIFMETRIC: /* Get the metric on the interface 948c2ecf20Sopenharmony_ci (currently unused) */ 958c2ecf20Sopenharmony_ci ifr->ifr_metric = 0; 968c2ecf20Sopenharmony_ci return 0; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci case SIOCGIFMTU: /* Get the MTU of a device */ 998c2ecf20Sopenharmony_ci ifr->ifr_mtu = dev->mtu; 1008c2ecf20Sopenharmony_ci return 0; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci case SIOCGIFSLAVE: 1038c2ecf20Sopenharmony_ci err = -EINVAL; 1048c2ecf20Sopenharmony_ci break; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci case SIOCGIFMAP: 1078c2ecf20Sopenharmony_ci ifr->ifr_map.mem_start = dev->mem_start; 1088c2ecf20Sopenharmony_ci ifr->ifr_map.mem_end = dev->mem_end; 1098c2ecf20Sopenharmony_ci ifr->ifr_map.base_addr = dev->base_addr; 1108c2ecf20Sopenharmony_ci ifr->ifr_map.irq = dev->irq; 1118c2ecf20Sopenharmony_ci ifr->ifr_map.dma = dev->dma; 1128c2ecf20Sopenharmony_ci ifr->ifr_map.port = dev->if_port; 1138c2ecf20Sopenharmony_ci return 0; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci case SIOCGIFINDEX: 1168c2ecf20Sopenharmony_ci ifr->ifr_ifindex = dev->ifindex; 1178c2ecf20Sopenharmony_ci return 0; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci case SIOCGIFTXQLEN: 1208c2ecf20Sopenharmony_ci ifr->ifr_qlen = dev->tx_queue_len; 1218c2ecf20Sopenharmony_ci return 0; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci default: 1248c2ecf20Sopenharmony_ci /* dev_ioctl() should ensure this case 1258c2ecf20Sopenharmony_ci * is never reached 1268c2ecf20Sopenharmony_ci */ 1278c2ecf20Sopenharmony_ci WARN_ON(1); 1288c2ecf20Sopenharmony_ci err = -ENOTTY; 1298c2ecf20Sopenharmony_ci break; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci return err; 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic int net_hwtstamp_validate(struct ifreq *ifr) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci struct hwtstamp_config cfg; 1388c2ecf20Sopenharmony_ci enum hwtstamp_tx_types tx_type; 1398c2ecf20Sopenharmony_ci enum hwtstamp_rx_filters rx_filter; 1408c2ecf20Sopenharmony_ci int tx_type_valid = 0; 1418c2ecf20Sopenharmony_ci int rx_filter_valid = 0; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg))) 1448c2ecf20Sopenharmony_ci return -EFAULT; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci if (cfg.flags) /* reserved for future extensions */ 1478c2ecf20Sopenharmony_ci return -EINVAL; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci tx_type = cfg.tx_type; 1508c2ecf20Sopenharmony_ci rx_filter = cfg.rx_filter; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci switch (tx_type) { 1538c2ecf20Sopenharmony_ci case HWTSTAMP_TX_OFF: 1548c2ecf20Sopenharmony_ci case HWTSTAMP_TX_ON: 1558c2ecf20Sopenharmony_ci case HWTSTAMP_TX_ONESTEP_SYNC: 1568c2ecf20Sopenharmony_ci case HWTSTAMP_TX_ONESTEP_P2P: 1578c2ecf20Sopenharmony_ci tx_type_valid = 1; 1588c2ecf20Sopenharmony_ci break; 1598c2ecf20Sopenharmony_ci case __HWTSTAMP_TX_CNT: 1608c2ecf20Sopenharmony_ci /* not a real value */ 1618c2ecf20Sopenharmony_ci break; 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci switch (rx_filter) { 1658c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_NONE: 1668c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_ALL: 1678c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_SOME: 1688c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: 1698c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: 1708c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: 1718c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: 1728c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: 1738c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: 1748c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: 1758c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: 1768c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: 1778c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_EVENT: 1788c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_SYNC: 1798c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: 1808c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_NTP_ALL: 1818c2ecf20Sopenharmony_ci rx_filter_valid = 1; 1828c2ecf20Sopenharmony_ci break; 1838c2ecf20Sopenharmony_ci case __HWTSTAMP_FILTER_CNT: 1848c2ecf20Sopenharmony_ci /* not a real value */ 1858c2ecf20Sopenharmony_ci break; 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci if (!tx_type_valid || !rx_filter_valid) 1898c2ecf20Sopenharmony_ci return -ERANGE; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci return 0; 1928c2ecf20Sopenharmony_ci} 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_cistatic int dev_do_ioctl(struct net_device *dev, 1958c2ecf20Sopenharmony_ci struct ifreq *ifr, unsigned int cmd) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci const struct net_device_ops *ops = dev->netdev_ops; 1988c2ecf20Sopenharmony_ci int err = -EOPNOTSUPP; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci err = dsa_ndo_do_ioctl(dev, ifr, cmd); 2018c2ecf20Sopenharmony_ci if (err == 0 || err != -EOPNOTSUPP) 2028c2ecf20Sopenharmony_ci return err; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci if (ops->ndo_do_ioctl) { 2058c2ecf20Sopenharmony_ci if (netif_device_present(dev)) 2068c2ecf20Sopenharmony_ci err = ops->ndo_do_ioctl(dev, ifr, cmd); 2078c2ecf20Sopenharmony_ci else 2088c2ecf20Sopenharmony_ci err = -ENODEV; 2098c2ecf20Sopenharmony_ci } 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci return err; 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci/* 2158c2ecf20Sopenharmony_ci * Perform the SIOCxIFxxx calls, inside rtnl_lock() 2168c2ecf20Sopenharmony_ci */ 2178c2ecf20Sopenharmony_cistatic int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd) 2188c2ecf20Sopenharmony_ci{ 2198c2ecf20Sopenharmony_ci int err; 2208c2ecf20Sopenharmony_ci struct net_device *dev = __dev_get_by_name(net, ifr->ifr_name); 2218c2ecf20Sopenharmony_ci const struct net_device_ops *ops; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci if (!dev) 2248c2ecf20Sopenharmony_ci return -ENODEV; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci ops = dev->netdev_ops; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci switch (cmd) { 2298c2ecf20Sopenharmony_ci case SIOCSIFFLAGS: /* Set interface flags */ 2308c2ecf20Sopenharmony_ci return dev_change_flags(dev, ifr->ifr_flags, NULL); 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci case SIOCSIFMETRIC: /* Set the metric on the interface 2338c2ecf20Sopenharmony_ci (currently unused) */ 2348c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci case SIOCSIFMTU: /* Set the MTU of a device */ 2378c2ecf20Sopenharmony_ci return dev_set_mtu(dev, ifr->ifr_mtu); 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci case SIOCSIFHWADDR: 2408c2ecf20Sopenharmony_ci if (dev->addr_len > sizeof(struct sockaddr)) 2418c2ecf20Sopenharmony_ci return -EINVAL; 2428c2ecf20Sopenharmony_ci return dev_set_mac_address_user(dev, &ifr->ifr_hwaddr, NULL); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci case SIOCSIFHWBROADCAST: 2458c2ecf20Sopenharmony_ci if (ifr->ifr_hwaddr.sa_family != dev->type) 2468c2ecf20Sopenharmony_ci return -EINVAL; 2478c2ecf20Sopenharmony_ci memcpy(dev->broadcast, ifr->ifr_hwaddr.sa_data, 2488c2ecf20Sopenharmony_ci min(sizeof(ifr->ifr_hwaddr.sa_data_min), 2498c2ecf20Sopenharmony_ci (size_t)dev->addr_len)); 2508c2ecf20Sopenharmony_ci call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); 2518c2ecf20Sopenharmony_ci return 0; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci case SIOCSIFMAP: 2548c2ecf20Sopenharmony_ci if (ops->ndo_set_config) { 2558c2ecf20Sopenharmony_ci if (!netif_device_present(dev)) 2568c2ecf20Sopenharmony_ci return -ENODEV; 2578c2ecf20Sopenharmony_ci return ops->ndo_set_config(dev, &ifr->ifr_map); 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci case SIOCADDMULTI: 2628c2ecf20Sopenharmony_ci if (!ops->ndo_set_rx_mode || 2638c2ecf20Sopenharmony_ci ifr->ifr_hwaddr.sa_family != AF_UNSPEC) 2648c2ecf20Sopenharmony_ci return -EINVAL; 2658c2ecf20Sopenharmony_ci if (!netif_device_present(dev)) 2668c2ecf20Sopenharmony_ci return -ENODEV; 2678c2ecf20Sopenharmony_ci return dev_mc_add_global(dev, ifr->ifr_hwaddr.sa_data); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci case SIOCDELMULTI: 2708c2ecf20Sopenharmony_ci if (!ops->ndo_set_rx_mode || 2718c2ecf20Sopenharmony_ci ifr->ifr_hwaddr.sa_family != AF_UNSPEC) 2728c2ecf20Sopenharmony_ci return -EINVAL; 2738c2ecf20Sopenharmony_ci if (!netif_device_present(dev)) 2748c2ecf20Sopenharmony_ci return -ENODEV; 2758c2ecf20Sopenharmony_ci return dev_mc_del_global(dev, ifr->ifr_hwaddr.sa_data); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci case SIOCSIFTXQLEN: 2788c2ecf20Sopenharmony_ci if (ifr->ifr_qlen < 0) 2798c2ecf20Sopenharmony_ci return -EINVAL; 2808c2ecf20Sopenharmony_ci return dev_change_tx_queue_len(dev, ifr->ifr_qlen); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci case SIOCSIFNAME: 2838c2ecf20Sopenharmony_ci ifr->ifr_newname[IFNAMSIZ-1] = '\0'; 2848c2ecf20Sopenharmony_ci return dev_change_name(dev, ifr->ifr_newname); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci case SIOCSHWTSTAMP: 2878c2ecf20Sopenharmony_ci err = net_hwtstamp_validate(ifr); 2888c2ecf20Sopenharmony_ci if (err) 2898c2ecf20Sopenharmony_ci return err; 2908c2ecf20Sopenharmony_ci fallthrough; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci /* 2938c2ecf20Sopenharmony_ci * Unknown or private ioctl 2948c2ecf20Sopenharmony_ci */ 2958c2ecf20Sopenharmony_ci default: 2968c2ecf20Sopenharmony_ci if ((cmd >= SIOCDEVPRIVATE && 2978c2ecf20Sopenharmony_ci cmd <= SIOCDEVPRIVATE + 15) || 2988c2ecf20Sopenharmony_ci cmd == SIOCBONDENSLAVE || 2998c2ecf20Sopenharmony_ci cmd == SIOCBONDRELEASE || 3008c2ecf20Sopenharmony_ci cmd == SIOCBONDSETHWADDR || 3018c2ecf20Sopenharmony_ci cmd == SIOCBONDSLAVEINFOQUERY || 3028c2ecf20Sopenharmony_ci cmd == SIOCBONDINFOQUERY || 3038c2ecf20Sopenharmony_ci cmd == SIOCBONDCHANGEACTIVE || 3048c2ecf20Sopenharmony_ci cmd == SIOCGMIIPHY || 3058c2ecf20Sopenharmony_ci cmd == SIOCGMIIREG || 3068c2ecf20Sopenharmony_ci cmd == SIOCSMIIREG || 3078c2ecf20Sopenharmony_ci cmd == SIOCBRADDIF || 3088c2ecf20Sopenharmony_ci cmd == SIOCBRDELIF || 3098c2ecf20Sopenharmony_ci cmd == SIOCSHWTSTAMP || 3108c2ecf20Sopenharmony_ci cmd == SIOCGHWTSTAMP || 3118c2ecf20Sopenharmony_ci cmd == SIOCWANDEV) { 3128c2ecf20Sopenharmony_ci err = dev_do_ioctl(dev, ifr, cmd); 3138c2ecf20Sopenharmony_ci } else 3148c2ecf20Sopenharmony_ci err = -EINVAL; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci return err; 3188c2ecf20Sopenharmony_ci} 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci/** 3218c2ecf20Sopenharmony_ci * dev_load - load a network module 3228c2ecf20Sopenharmony_ci * @net: the applicable net namespace 3238c2ecf20Sopenharmony_ci * @name: name of interface 3248c2ecf20Sopenharmony_ci * 3258c2ecf20Sopenharmony_ci * If a network interface is not present and the process has suitable 3268c2ecf20Sopenharmony_ci * privileges this function loads the module. If module loading is not 3278c2ecf20Sopenharmony_ci * available in this kernel then it becomes a nop. 3288c2ecf20Sopenharmony_ci */ 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_civoid dev_load(struct net *net, const char *name) 3318c2ecf20Sopenharmony_ci{ 3328c2ecf20Sopenharmony_ci struct net_device *dev; 3338c2ecf20Sopenharmony_ci int no_module; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci rcu_read_lock(); 3368c2ecf20Sopenharmony_ci dev = dev_get_by_name_rcu(net, name); 3378c2ecf20Sopenharmony_ci rcu_read_unlock(); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci no_module = !dev; 3408c2ecf20Sopenharmony_ci if (no_module && capable(CAP_NET_ADMIN)) 3418c2ecf20Sopenharmony_ci no_module = request_module("netdev-%s", name); 3428c2ecf20Sopenharmony_ci if (no_module && capable(CAP_SYS_MODULE)) 3438c2ecf20Sopenharmony_ci request_module("%s", name); 3448c2ecf20Sopenharmony_ci} 3458c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dev_load); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci/* 3488c2ecf20Sopenharmony_ci * This function handles all "interface"-type I/O control requests. The actual 3498c2ecf20Sopenharmony_ci * 'doing' part of this is dev_ifsioc above. 3508c2ecf20Sopenharmony_ci */ 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci/** 3538c2ecf20Sopenharmony_ci * dev_ioctl - network device ioctl 3548c2ecf20Sopenharmony_ci * @net: the applicable net namespace 3558c2ecf20Sopenharmony_ci * @cmd: command to issue 3568c2ecf20Sopenharmony_ci * @ifr: pointer to a struct ifreq in user space 3578c2ecf20Sopenharmony_ci * @need_copyout: whether or not copy_to_user() should be called 3588c2ecf20Sopenharmony_ci * 3598c2ecf20Sopenharmony_ci * Issue ioctl functions to devices. This is normally called by the 3608c2ecf20Sopenharmony_ci * user space syscall interfaces but can sometimes be useful for 3618c2ecf20Sopenharmony_ci * other purposes. The return value is the return from the syscall if 3628c2ecf20Sopenharmony_ci * positive or a negative errno code on error. 3638c2ecf20Sopenharmony_ci */ 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ciint dev_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr, bool *need_copyout) 3668c2ecf20Sopenharmony_ci{ 3678c2ecf20Sopenharmony_ci int ret; 3688c2ecf20Sopenharmony_ci char *colon; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci if (need_copyout) 3718c2ecf20Sopenharmony_ci *need_copyout = true; 3728c2ecf20Sopenharmony_ci if (cmd == SIOCGIFNAME) 3738c2ecf20Sopenharmony_ci return dev_ifname(net, ifr); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci ifr->ifr_name[IFNAMSIZ-1] = 0; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci colon = strchr(ifr->ifr_name, ':'); 3788c2ecf20Sopenharmony_ci if (colon) 3798c2ecf20Sopenharmony_ci *colon = 0; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci /* 3828c2ecf20Sopenharmony_ci * See which interface the caller is talking about. 3838c2ecf20Sopenharmony_ci */ 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci switch (cmd) { 3868c2ecf20Sopenharmony_ci case SIOCGIFHWADDR: 3878c2ecf20Sopenharmony_ci dev_load(net, ifr->ifr_name); 3888c2ecf20Sopenharmony_ci ret = dev_get_mac_address(&ifr->ifr_hwaddr, net, ifr->ifr_name); 3898c2ecf20Sopenharmony_ci if (colon) 3908c2ecf20Sopenharmony_ci *colon = ':'; 3918c2ecf20Sopenharmony_ci return ret; 3928c2ecf20Sopenharmony_ci /* 3938c2ecf20Sopenharmony_ci * These ioctl calls: 3948c2ecf20Sopenharmony_ci * - can be done by all. 3958c2ecf20Sopenharmony_ci * - atomic and do not require locking. 3968c2ecf20Sopenharmony_ci * - return a value 3978c2ecf20Sopenharmony_ci */ 3988c2ecf20Sopenharmony_ci case SIOCGIFFLAGS: 3998c2ecf20Sopenharmony_ci case SIOCGIFMETRIC: 4008c2ecf20Sopenharmony_ci case SIOCGIFMTU: 4018c2ecf20Sopenharmony_ci case SIOCGIFSLAVE: 4028c2ecf20Sopenharmony_ci case SIOCGIFMAP: 4038c2ecf20Sopenharmony_ci case SIOCGIFINDEX: 4048c2ecf20Sopenharmony_ci case SIOCGIFTXQLEN: 4058c2ecf20Sopenharmony_ci dev_load(net, ifr->ifr_name); 4068c2ecf20Sopenharmony_ci rcu_read_lock(); 4078c2ecf20Sopenharmony_ci ret = dev_ifsioc_locked(net, ifr, cmd); 4088c2ecf20Sopenharmony_ci rcu_read_unlock(); 4098c2ecf20Sopenharmony_ci if (colon) 4108c2ecf20Sopenharmony_ci *colon = ':'; 4118c2ecf20Sopenharmony_ci return ret; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci case SIOCETHTOOL: 4148c2ecf20Sopenharmony_ci dev_load(net, ifr->ifr_name); 4158c2ecf20Sopenharmony_ci rtnl_lock(); 4168c2ecf20Sopenharmony_ci ret = dev_ethtool(net, ifr); 4178c2ecf20Sopenharmony_ci rtnl_unlock(); 4188c2ecf20Sopenharmony_ci if (colon) 4198c2ecf20Sopenharmony_ci *colon = ':'; 4208c2ecf20Sopenharmony_ci return ret; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci /* 4238c2ecf20Sopenharmony_ci * These ioctl calls: 4248c2ecf20Sopenharmony_ci * - require superuser power. 4258c2ecf20Sopenharmony_ci * - require strict serialization. 4268c2ecf20Sopenharmony_ci * - return a value 4278c2ecf20Sopenharmony_ci */ 4288c2ecf20Sopenharmony_ci case SIOCGMIIPHY: 4298c2ecf20Sopenharmony_ci case SIOCGMIIREG: 4308c2ecf20Sopenharmony_ci case SIOCSIFNAME: 4318c2ecf20Sopenharmony_ci dev_load(net, ifr->ifr_name); 4328c2ecf20Sopenharmony_ci if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) 4338c2ecf20Sopenharmony_ci return -EPERM; 4348c2ecf20Sopenharmony_ci rtnl_lock(); 4358c2ecf20Sopenharmony_ci ret = dev_ifsioc(net, ifr, cmd); 4368c2ecf20Sopenharmony_ci rtnl_unlock(); 4378c2ecf20Sopenharmony_ci if (colon) 4388c2ecf20Sopenharmony_ci *colon = ':'; 4398c2ecf20Sopenharmony_ci return ret; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci /* 4428c2ecf20Sopenharmony_ci * These ioctl calls: 4438c2ecf20Sopenharmony_ci * - require superuser power. 4448c2ecf20Sopenharmony_ci * - require strict serialization. 4458c2ecf20Sopenharmony_ci * - do not return a value 4468c2ecf20Sopenharmony_ci */ 4478c2ecf20Sopenharmony_ci case SIOCSIFMAP: 4488c2ecf20Sopenharmony_ci case SIOCSIFTXQLEN: 4498c2ecf20Sopenharmony_ci if (!capable(CAP_NET_ADMIN)) 4508c2ecf20Sopenharmony_ci return -EPERM; 4518c2ecf20Sopenharmony_ci fallthrough; 4528c2ecf20Sopenharmony_ci /* 4538c2ecf20Sopenharmony_ci * These ioctl calls: 4548c2ecf20Sopenharmony_ci * - require local superuser power. 4558c2ecf20Sopenharmony_ci * - require strict serialization. 4568c2ecf20Sopenharmony_ci * - do not return a value 4578c2ecf20Sopenharmony_ci */ 4588c2ecf20Sopenharmony_ci case SIOCSIFFLAGS: 4598c2ecf20Sopenharmony_ci case SIOCSIFMETRIC: 4608c2ecf20Sopenharmony_ci case SIOCSIFMTU: 4618c2ecf20Sopenharmony_ci case SIOCSIFHWADDR: 4628c2ecf20Sopenharmony_ci case SIOCSIFSLAVE: 4638c2ecf20Sopenharmony_ci case SIOCADDMULTI: 4648c2ecf20Sopenharmony_ci case SIOCDELMULTI: 4658c2ecf20Sopenharmony_ci case SIOCSIFHWBROADCAST: 4668c2ecf20Sopenharmony_ci case SIOCSMIIREG: 4678c2ecf20Sopenharmony_ci case SIOCBONDENSLAVE: 4688c2ecf20Sopenharmony_ci case SIOCBONDRELEASE: 4698c2ecf20Sopenharmony_ci case SIOCBONDSETHWADDR: 4708c2ecf20Sopenharmony_ci case SIOCBONDCHANGEACTIVE: 4718c2ecf20Sopenharmony_ci case SIOCBRADDIF: 4728c2ecf20Sopenharmony_ci case SIOCBRDELIF: 4738c2ecf20Sopenharmony_ci case SIOCSHWTSTAMP: 4748c2ecf20Sopenharmony_ci if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) 4758c2ecf20Sopenharmony_ci return -EPERM; 4768c2ecf20Sopenharmony_ci fallthrough; 4778c2ecf20Sopenharmony_ci case SIOCBONDSLAVEINFOQUERY: 4788c2ecf20Sopenharmony_ci case SIOCBONDINFOQUERY: 4798c2ecf20Sopenharmony_ci dev_load(net, ifr->ifr_name); 4808c2ecf20Sopenharmony_ci rtnl_lock(); 4818c2ecf20Sopenharmony_ci ret = dev_ifsioc(net, ifr, cmd); 4828c2ecf20Sopenharmony_ci rtnl_unlock(); 4838c2ecf20Sopenharmony_ci if (need_copyout) 4848c2ecf20Sopenharmony_ci *need_copyout = false; 4858c2ecf20Sopenharmony_ci return ret; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci case SIOCGIFMEM: 4888c2ecf20Sopenharmony_ci /* Get the per device memory space. We can add this but 4898c2ecf20Sopenharmony_ci * currently do not support it */ 4908c2ecf20Sopenharmony_ci case SIOCSIFMEM: 4918c2ecf20Sopenharmony_ci /* Set the per device memory buffer space. 4928c2ecf20Sopenharmony_ci * Not applicable in our case */ 4938c2ecf20Sopenharmony_ci case SIOCSIFLINK: 4948c2ecf20Sopenharmony_ci return -ENOTTY; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci /* 4978c2ecf20Sopenharmony_ci * Unknown or private ioctl. 4988c2ecf20Sopenharmony_ci */ 4998c2ecf20Sopenharmony_ci default: 5008c2ecf20Sopenharmony_ci if (cmd == SIOCWANDEV || 5018c2ecf20Sopenharmony_ci cmd == SIOCGHWTSTAMP || 5028c2ecf20Sopenharmony_ci (cmd >= SIOCDEVPRIVATE && 5038c2ecf20Sopenharmony_ci cmd <= SIOCDEVPRIVATE + 15)) { 5048c2ecf20Sopenharmony_ci dev_load(net, ifr->ifr_name); 5058c2ecf20Sopenharmony_ci rtnl_lock(); 5068c2ecf20Sopenharmony_ci ret = dev_ifsioc(net, ifr, cmd); 5078c2ecf20Sopenharmony_ci rtnl_unlock(); 5088c2ecf20Sopenharmony_ci return ret; 5098c2ecf20Sopenharmony_ci } 5108c2ecf20Sopenharmony_ci return -ENOTTY; 5118c2ecf20Sopenharmony_ci } 5128c2ecf20Sopenharmony_ci} 513