162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci#include <linux/kmod.h> 362306a36Sopenharmony_ci#include <linux/netdevice.h> 462306a36Sopenharmony_ci#include <linux/inetdevice.h> 562306a36Sopenharmony_ci#include <linux/etherdevice.h> 662306a36Sopenharmony_ci#include <linux/rtnetlink.h> 762306a36Sopenharmony_ci#include <linux/net_tstamp.h> 862306a36Sopenharmony_ci#include <linux/phylib_stubs.h> 962306a36Sopenharmony_ci#include <linux/wireless.h> 1062306a36Sopenharmony_ci#include <linux/if_bridge.h> 1162306a36Sopenharmony_ci#include <net/dsa_stubs.h> 1262306a36Sopenharmony_ci#include <net/wext.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include "dev.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci/* 1762306a36Sopenharmony_ci * Map an interface index to its name (SIOCGIFNAME) 1862306a36Sopenharmony_ci */ 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci/* 2162306a36Sopenharmony_ci * We need this ioctl for efficient implementation of the 2262306a36Sopenharmony_ci * if_indextoname() function required by the IPv6 API. Without 2362306a36Sopenharmony_ci * it, we would have to search all the interfaces to find a 2462306a36Sopenharmony_ci * match. --pb 2562306a36Sopenharmony_ci */ 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic int dev_ifname(struct net *net, struct ifreq *ifr) 2862306a36Sopenharmony_ci{ 2962306a36Sopenharmony_ci ifr->ifr_name[IFNAMSIZ-1] = 0; 3062306a36Sopenharmony_ci return netdev_get_name(net, ifr->ifr_name, ifr->ifr_ifindex); 3162306a36Sopenharmony_ci} 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci/* 3462306a36Sopenharmony_ci * Perform a SIOCGIFCONF call. This structure will change 3562306a36Sopenharmony_ci * size eventually, and there is nothing I can do about it. 3662306a36Sopenharmony_ci * Thus we will need a 'compatibility mode'. 3762306a36Sopenharmony_ci */ 3862306a36Sopenharmony_ciint dev_ifconf(struct net *net, struct ifconf __user *uifc) 3962306a36Sopenharmony_ci{ 4062306a36Sopenharmony_ci struct net_device *dev; 4162306a36Sopenharmony_ci void __user *pos; 4262306a36Sopenharmony_ci size_t size; 4362306a36Sopenharmony_ci int len, total = 0, done; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci /* both the ifconf and the ifreq structures are slightly different */ 4662306a36Sopenharmony_ci if (in_compat_syscall()) { 4762306a36Sopenharmony_ci struct compat_ifconf ifc32; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci if (copy_from_user(&ifc32, uifc, sizeof(struct compat_ifconf))) 5062306a36Sopenharmony_ci return -EFAULT; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci pos = compat_ptr(ifc32.ifcbuf); 5362306a36Sopenharmony_ci len = ifc32.ifc_len; 5462306a36Sopenharmony_ci size = sizeof(struct compat_ifreq); 5562306a36Sopenharmony_ci } else { 5662306a36Sopenharmony_ci struct ifconf ifc; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci if (copy_from_user(&ifc, uifc, sizeof(struct ifconf))) 5962306a36Sopenharmony_ci return -EFAULT; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci pos = ifc.ifc_buf; 6262306a36Sopenharmony_ci len = ifc.ifc_len; 6362306a36Sopenharmony_ci size = sizeof(struct ifreq); 6462306a36Sopenharmony_ci } 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci /* Loop over the interfaces, and write an info block for each. */ 6762306a36Sopenharmony_ci rtnl_lock(); 6862306a36Sopenharmony_ci for_each_netdev(net, dev) { 6962306a36Sopenharmony_ci if (!pos) 7062306a36Sopenharmony_ci done = inet_gifconf(dev, NULL, 0, size); 7162306a36Sopenharmony_ci else 7262306a36Sopenharmony_ci done = inet_gifconf(dev, pos + total, 7362306a36Sopenharmony_ci len - total, size); 7462306a36Sopenharmony_ci if (done < 0) { 7562306a36Sopenharmony_ci rtnl_unlock(); 7662306a36Sopenharmony_ci return -EFAULT; 7762306a36Sopenharmony_ci } 7862306a36Sopenharmony_ci total += done; 7962306a36Sopenharmony_ci } 8062306a36Sopenharmony_ci rtnl_unlock(); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci return put_user(total, &uifc->ifc_len); 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cistatic int dev_getifmap(struct net_device *dev, struct ifreq *ifr) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci struct ifmap *ifmap = &ifr->ifr_map; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci if (in_compat_syscall()) { 9062306a36Sopenharmony_ci struct compat_ifmap *cifmap = (struct compat_ifmap *)ifmap; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci cifmap->mem_start = dev->mem_start; 9362306a36Sopenharmony_ci cifmap->mem_end = dev->mem_end; 9462306a36Sopenharmony_ci cifmap->base_addr = dev->base_addr; 9562306a36Sopenharmony_ci cifmap->irq = dev->irq; 9662306a36Sopenharmony_ci cifmap->dma = dev->dma; 9762306a36Sopenharmony_ci cifmap->port = dev->if_port; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci return 0; 10062306a36Sopenharmony_ci } 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci ifmap->mem_start = dev->mem_start; 10362306a36Sopenharmony_ci ifmap->mem_end = dev->mem_end; 10462306a36Sopenharmony_ci ifmap->base_addr = dev->base_addr; 10562306a36Sopenharmony_ci ifmap->irq = dev->irq; 10662306a36Sopenharmony_ci ifmap->dma = dev->dma; 10762306a36Sopenharmony_ci ifmap->port = dev->if_port; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci return 0; 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cistatic int dev_setifmap(struct net_device *dev, struct ifreq *ifr) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci struct compat_ifmap *cifmap = (struct compat_ifmap *)&ifr->ifr_map; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci if (!dev->netdev_ops->ndo_set_config) 11762306a36Sopenharmony_ci return -EOPNOTSUPP; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci if (in_compat_syscall()) { 12062306a36Sopenharmony_ci struct ifmap ifmap = { 12162306a36Sopenharmony_ci .mem_start = cifmap->mem_start, 12262306a36Sopenharmony_ci .mem_end = cifmap->mem_end, 12362306a36Sopenharmony_ci .base_addr = cifmap->base_addr, 12462306a36Sopenharmony_ci .irq = cifmap->irq, 12562306a36Sopenharmony_ci .dma = cifmap->dma, 12662306a36Sopenharmony_ci .port = cifmap->port, 12762306a36Sopenharmony_ci }; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci return dev->netdev_ops->ndo_set_config(dev, &ifmap); 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci return dev->netdev_ops->ndo_set_config(dev, &ifr->ifr_map); 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci/* 13662306a36Sopenharmony_ci * Perform the SIOCxIFxxx calls, inside rcu_read_lock() 13762306a36Sopenharmony_ci */ 13862306a36Sopenharmony_cistatic int dev_ifsioc_locked(struct net *net, struct ifreq *ifr, unsigned int cmd) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci int err; 14162306a36Sopenharmony_ci struct net_device *dev = dev_get_by_name_rcu(net, ifr->ifr_name); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci if (!dev) 14462306a36Sopenharmony_ci return -ENODEV; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci switch (cmd) { 14762306a36Sopenharmony_ci case SIOCGIFFLAGS: /* Get interface flags */ 14862306a36Sopenharmony_ci ifr->ifr_flags = (short) dev_get_flags(dev); 14962306a36Sopenharmony_ci return 0; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci case SIOCGIFMETRIC: /* Get the metric on the interface 15262306a36Sopenharmony_ci (currently unused) */ 15362306a36Sopenharmony_ci ifr->ifr_metric = 0; 15462306a36Sopenharmony_ci return 0; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci case SIOCGIFMTU: /* Get the MTU of a device */ 15762306a36Sopenharmony_ci ifr->ifr_mtu = dev->mtu; 15862306a36Sopenharmony_ci return 0; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci case SIOCGIFSLAVE: 16162306a36Sopenharmony_ci err = -EINVAL; 16262306a36Sopenharmony_ci break; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci case SIOCGIFMAP: 16562306a36Sopenharmony_ci return dev_getifmap(dev, ifr); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci case SIOCGIFINDEX: 16862306a36Sopenharmony_ci ifr->ifr_ifindex = dev->ifindex; 16962306a36Sopenharmony_ci return 0; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci case SIOCGIFTXQLEN: 17262306a36Sopenharmony_ci ifr->ifr_qlen = dev->tx_queue_len; 17362306a36Sopenharmony_ci return 0; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci default: 17662306a36Sopenharmony_ci /* dev_ioctl() should ensure this case 17762306a36Sopenharmony_ci * is never reached 17862306a36Sopenharmony_ci */ 17962306a36Sopenharmony_ci WARN_ON(1); 18062306a36Sopenharmony_ci err = -ENOTTY; 18162306a36Sopenharmony_ci break; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci } 18462306a36Sopenharmony_ci return err; 18562306a36Sopenharmony_ci} 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_cistatic int net_hwtstamp_validate(const struct kernel_hwtstamp_config *cfg) 18862306a36Sopenharmony_ci{ 18962306a36Sopenharmony_ci enum hwtstamp_tx_types tx_type; 19062306a36Sopenharmony_ci enum hwtstamp_rx_filters rx_filter; 19162306a36Sopenharmony_ci int tx_type_valid = 0; 19262306a36Sopenharmony_ci int rx_filter_valid = 0; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci if (cfg->flags & ~HWTSTAMP_FLAG_MASK) 19562306a36Sopenharmony_ci return -EINVAL; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci tx_type = cfg->tx_type; 19862306a36Sopenharmony_ci rx_filter = cfg->rx_filter; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci switch (tx_type) { 20162306a36Sopenharmony_ci case HWTSTAMP_TX_OFF: 20262306a36Sopenharmony_ci case HWTSTAMP_TX_ON: 20362306a36Sopenharmony_ci case HWTSTAMP_TX_ONESTEP_SYNC: 20462306a36Sopenharmony_ci case HWTSTAMP_TX_ONESTEP_P2P: 20562306a36Sopenharmony_ci tx_type_valid = 1; 20662306a36Sopenharmony_ci break; 20762306a36Sopenharmony_ci case __HWTSTAMP_TX_CNT: 20862306a36Sopenharmony_ci /* not a real value */ 20962306a36Sopenharmony_ci break; 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci switch (rx_filter) { 21362306a36Sopenharmony_ci case HWTSTAMP_FILTER_NONE: 21462306a36Sopenharmony_ci case HWTSTAMP_FILTER_ALL: 21562306a36Sopenharmony_ci case HWTSTAMP_FILTER_SOME: 21662306a36Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: 21762306a36Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: 21862306a36Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: 21962306a36Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: 22062306a36Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: 22162306a36Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: 22262306a36Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: 22362306a36Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: 22462306a36Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: 22562306a36Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_EVENT: 22662306a36Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_SYNC: 22762306a36Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: 22862306a36Sopenharmony_ci case HWTSTAMP_FILTER_NTP_ALL: 22962306a36Sopenharmony_ci rx_filter_valid = 1; 23062306a36Sopenharmony_ci break; 23162306a36Sopenharmony_ci case __HWTSTAMP_FILTER_CNT: 23262306a36Sopenharmony_ci /* not a real value */ 23362306a36Sopenharmony_ci break; 23462306a36Sopenharmony_ci } 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci if (!tx_type_valid || !rx_filter_valid) 23762306a36Sopenharmony_ci return -ERANGE; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci return 0; 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_cistatic int dev_eth_ioctl(struct net_device *dev, 24362306a36Sopenharmony_ci struct ifreq *ifr, unsigned int cmd) 24462306a36Sopenharmony_ci{ 24562306a36Sopenharmony_ci const struct net_device_ops *ops = dev->netdev_ops; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci if (!ops->ndo_eth_ioctl) 24862306a36Sopenharmony_ci return -EOPNOTSUPP; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci if (!netif_device_present(dev)) 25162306a36Sopenharmony_ci return -ENODEV; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci return ops->ndo_eth_ioctl(dev, ifr, cmd); 25462306a36Sopenharmony_ci} 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci/** 25762306a36Sopenharmony_ci * dev_get_hwtstamp_phylib() - Get hardware timestamping settings of NIC 25862306a36Sopenharmony_ci * or of attached phylib PHY 25962306a36Sopenharmony_ci * @dev: Network device 26062306a36Sopenharmony_ci * @cfg: Timestamping configuration structure 26162306a36Sopenharmony_ci * 26262306a36Sopenharmony_ci * Helper for enforcing a common policy that phylib timestamping, if available, 26362306a36Sopenharmony_ci * should take precedence in front of hardware timestamping provided by the 26462306a36Sopenharmony_ci * netdev. 26562306a36Sopenharmony_ci * 26662306a36Sopenharmony_ci * Note: phy_mii_ioctl() only handles SIOCSHWTSTAMP (not SIOCGHWTSTAMP), and 26762306a36Sopenharmony_ci * there only exists a phydev->mii_ts->hwtstamp() method. So this will return 26862306a36Sopenharmony_ci * -EOPNOTSUPP for phylib for now, which is still more accurate than letting 26962306a36Sopenharmony_ci * the netdev handle the GET request. 27062306a36Sopenharmony_ci */ 27162306a36Sopenharmony_cistatic int dev_get_hwtstamp_phylib(struct net_device *dev, 27262306a36Sopenharmony_ci struct kernel_hwtstamp_config *cfg) 27362306a36Sopenharmony_ci{ 27462306a36Sopenharmony_ci if (phy_has_hwtstamp(dev->phydev)) 27562306a36Sopenharmony_ci return phy_hwtstamp_get(dev->phydev, cfg); 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci return dev->netdev_ops->ndo_hwtstamp_get(dev, cfg); 27862306a36Sopenharmony_ci} 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_cistatic int dev_get_hwtstamp(struct net_device *dev, struct ifreq *ifr) 28162306a36Sopenharmony_ci{ 28262306a36Sopenharmony_ci const struct net_device_ops *ops = dev->netdev_ops; 28362306a36Sopenharmony_ci struct kernel_hwtstamp_config kernel_cfg = {}; 28462306a36Sopenharmony_ci struct hwtstamp_config cfg; 28562306a36Sopenharmony_ci int err; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci if (!ops->ndo_hwtstamp_get) 28862306a36Sopenharmony_ci return dev_eth_ioctl(dev, ifr, SIOCGHWTSTAMP); /* legacy */ 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci if (!netif_device_present(dev)) 29162306a36Sopenharmony_ci return -ENODEV; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci kernel_cfg.ifr = ifr; 29462306a36Sopenharmony_ci err = dev_get_hwtstamp_phylib(dev, &kernel_cfg); 29562306a36Sopenharmony_ci if (err) 29662306a36Sopenharmony_ci return err; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci /* If the request was resolved through an unconverted driver, omit 29962306a36Sopenharmony_ci * the copy_to_user(), since the implementation has already done that 30062306a36Sopenharmony_ci */ 30162306a36Sopenharmony_ci if (!kernel_cfg.copied_to_user) { 30262306a36Sopenharmony_ci hwtstamp_config_from_kernel(&cfg, &kernel_cfg); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci if (copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg))) 30562306a36Sopenharmony_ci return -EFAULT; 30662306a36Sopenharmony_ci } 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci return 0; 30962306a36Sopenharmony_ci} 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci/** 31262306a36Sopenharmony_ci * dev_set_hwtstamp_phylib() - Change hardware timestamping of NIC 31362306a36Sopenharmony_ci * or of attached phylib PHY 31462306a36Sopenharmony_ci * @dev: Network device 31562306a36Sopenharmony_ci * @cfg: Timestamping configuration structure 31662306a36Sopenharmony_ci * @extack: Netlink extended ack message structure, for error reporting 31762306a36Sopenharmony_ci * 31862306a36Sopenharmony_ci * Helper for enforcing a common policy that phylib timestamping, if available, 31962306a36Sopenharmony_ci * should take precedence in front of hardware timestamping provided by the 32062306a36Sopenharmony_ci * netdev. If the netdev driver needs to perform specific actions even for PHY 32162306a36Sopenharmony_ci * timestamping to work properly (a switch port must trap the timestamped 32262306a36Sopenharmony_ci * frames and not forward them), it must set IFF_SEE_ALL_HWTSTAMP_REQUESTS in 32362306a36Sopenharmony_ci * dev->priv_flags. 32462306a36Sopenharmony_ci */ 32562306a36Sopenharmony_cistatic int dev_set_hwtstamp_phylib(struct net_device *dev, 32662306a36Sopenharmony_ci struct kernel_hwtstamp_config *cfg, 32762306a36Sopenharmony_ci struct netlink_ext_ack *extack) 32862306a36Sopenharmony_ci{ 32962306a36Sopenharmony_ci const struct net_device_ops *ops = dev->netdev_ops; 33062306a36Sopenharmony_ci bool phy_ts = phy_has_hwtstamp(dev->phydev); 33162306a36Sopenharmony_ci struct kernel_hwtstamp_config old_cfg = {}; 33262306a36Sopenharmony_ci bool changed = false; 33362306a36Sopenharmony_ci int err; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci cfg->source = phy_ts ? HWTSTAMP_SOURCE_PHYLIB : HWTSTAMP_SOURCE_NETDEV; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci if (phy_ts && (dev->priv_flags & IFF_SEE_ALL_HWTSTAMP_REQUESTS)) { 33862306a36Sopenharmony_ci err = ops->ndo_hwtstamp_get(dev, &old_cfg); 33962306a36Sopenharmony_ci if (err) 34062306a36Sopenharmony_ci return err; 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci if (!phy_ts || (dev->priv_flags & IFF_SEE_ALL_HWTSTAMP_REQUESTS)) { 34462306a36Sopenharmony_ci err = ops->ndo_hwtstamp_set(dev, cfg, extack); 34562306a36Sopenharmony_ci if (err) { 34662306a36Sopenharmony_ci if (extack->_msg) 34762306a36Sopenharmony_ci netdev_err(dev, "%s\n", extack->_msg); 34862306a36Sopenharmony_ci return err; 34962306a36Sopenharmony_ci } 35062306a36Sopenharmony_ci } 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci if (phy_ts && (dev->priv_flags & IFF_SEE_ALL_HWTSTAMP_REQUESTS)) 35362306a36Sopenharmony_ci changed = kernel_hwtstamp_config_changed(&old_cfg, cfg); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci if (phy_ts) { 35662306a36Sopenharmony_ci err = phy_hwtstamp_set(dev->phydev, cfg, extack); 35762306a36Sopenharmony_ci if (err) { 35862306a36Sopenharmony_ci if (changed) 35962306a36Sopenharmony_ci ops->ndo_hwtstamp_set(dev, &old_cfg, NULL); 36062306a36Sopenharmony_ci return err; 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci return 0; 36562306a36Sopenharmony_ci} 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_cistatic int dev_set_hwtstamp(struct net_device *dev, struct ifreq *ifr) 36862306a36Sopenharmony_ci{ 36962306a36Sopenharmony_ci const struct net_device_ops *ops = dev->netdev_ops; 37062306a36Sopenharmony_ci struct kernel_hwtstamp_config kernel_cfg = {}; 37162306a36Sopenharmony_ci struct netlink_ext_ack extack = {}; 37262306a36Sopenharmony_ci struct hwtstamp_config cfg; 37362306a36Sopenharmony_ci int err; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg))) 37662306a36Sopenharmony_ci return -EFAULT; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci hwtstamp_config_to_kernel(&kernel_cfg, &cfg); 37962306a36Sopenharmony_ci kernel_cfg.ifr = ifr; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci err = net_hwtstamp_validate(&kernel_cfg); 38262306a36Sopenharmony_ci if (err) 38362306a36Sopenharmony_ci return err; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci err = dsa_master_hwtstamp_validate(dev, &kernel_cfg, &extack); 38662306a36Sopenharmony_ci if (err) { 38762306a36Sopenharmony_ci if (extack._msg) 38862306a36Sopenharmony_ci netdev_err(dev, "%s\n", extack._msg); 38962306a36Sopenharmony_ci return err; 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci if (!ops->ndo_hwtstamp_set) 39362306a36Sopenharmony_ci return dev_eth_ioctl(dev, ifr, SIOCSHWTSTAMP); /* legacy */ 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci if (!netif_device_present(dev)) 39662306a36Sopenharmony_ci return -ENODEV; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci err = dev_set_hwtstamp_phylib(dev, &kernel_cfg, &extack); 39962306a36Sopenharmony_ci if (err) 40062306a36Sopenharmony_ci return err; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci /* The driver may have modified the configuration, so copy the 40362306a36Sopenharmony_ci * updated version of it back to user space 40462306a36Sopenharmony_ci */ 40562306a36Sopenharmony_ci if (!kernel_cfg.copied_to_user) { 40662306a36Sopenharmony_ci hwtstamp_config_from_kernel(&cfg, &kernel_cfg); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci if (copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg))) 40962306a36Sopenharmony_ci return -EFAULT; 41062306a36Sopenharmony_ci } 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci return 0; 41362306a36Sopenharmony_ci} 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_cistatic int generic_hwtstamp_ioctl_lower(struct net_device *dev, int cmd, 41662306a36Sopenharmony_ci struct kernel_hwtstamp_config *kernel_cfg) 41762306a36Sopenharmony_ci{ 41862306a36Sopenharmony_ci struct ifreq ifrr; 41962306a36Sopenharmony_ci int err; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci strscpy_pad(ifrr.ifr_name, dev->name, IFNAMSIZ); 42262306a36Sopenharmony_ci ifrr.ifr_ifru = kernel_cfg->ifr->ifr_ifru; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci err = dev_eth_ioctl(dev, &ifrr, cmd); 42562306a36Sopenharmony_ci if (err) 42662306a36Sopenharmony_ci return err; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci kernel_cfg->ifr->ifr_ifru = ifrr.ifr_ifru; 42962306a36Sopenharmony_ci kernel_cfg->copied_to_user = true; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci return 0; 43262306a36Sopenharmony_ci} 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ciint generic_hwtstamp_get_lower(struct net_device *dev, 43562306a36Sopenharmony_ci struct kernel_hwtstamp_config *kernel_cfg) 43662306a36Sopenharmony_ci{ 43762306a36Sopenharmony_ci const struct net_device_ops *ops = dev->netdev_ops; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci if (!netif_device_present(dev)) 44062306a36Sopenharmony_ci return -ENODEV; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci if (ops->ndo_hwtstamp_get) 44362306a36Sopenharmony_ci return dev_get_hwtstamp_phylib(dev, kernel_cfg); 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci /* Legacy path: unconverted lower driver */ 44662306a36Sopenharmony_ci return generic_hwtstamp_ioctl_lower(dev, SIOCGHWTSTAMP, kernel_cfg); 44762306a36Sopenharmony_ci} 44862306a36Sopenharmony_ciEXPORT_SYMBOL(generic_hwtstamp_get_lower); 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ciint generic_hwtstamp_set_lower(struct net_device *dev, 45162306a36Sopenharmony_ci struct kernel_hwtstamp_config *kernel_cfg, 45262306a36Sopenharmony_ci struct netlink_ext_ack *extack) 45362306a36Sopenharmony_ci{ 45462306a36Sopenharmony_ci const struct net_device_ops *ops = dev->netdev_ops; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci if (!netif_device_present(dev)) 45762306a36Sopenharmony_ci return -ENODEV; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci if (ops->ndo_hwtstamp_set) 46062306a36Sopenharmony_ci return dev_set_hwtstamp_phylib(dev, kernel_cfg, extack); 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci /* Legacy path: unconverted lower driver */ 46362306a36Sopenharmony_ci return generic_hwtstamp_ioctl_lower(dev, SIOCSHWTSTAMP, kernel_cfg); 46462306a36Sopenharmony_ci} 46562306a36Sopenharmony_ciEXPORT_SYMBOL(generic_hwtstamp_set_lower); 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_cistatic int dev_siocbond(struct net_device *dev, 46862306a36Sopenharmony_ci struct ifreq *ifr, unsigned int cmd) 46962306a36Sopenharmony_ci{ 47062306a36Sopenharmony_ci const struct net_device_ops *ops = dev->netdev_ops; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci if (ops->ndo_siocbond) { 47362306a36Sopenharmony_ci if (netif_device_present(dev)) 47462306a36Sopenharmony_ci return ops->ndo_siocbond(dev, ifr, cmd); 47562306a36Sopenharmony_ci else 47662306a36Sopenharmony_ci return -ENODEV; 47762306a36Sopenharmony_ci } 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci return -EOPNOTSUPP; 48062306a36Sopenharmony_ci} 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_cistatic int dev_siocdevprivate(struct net_device *dev, struct ifreq *ifr, 48362306a36Sopenharmony_ci void __user *data, unsigned int cmd) 48462306a36Sopenharmony_ci{ 48562306a36Sopenharmony_ci const struct net_device_ops *ops = dev->netdev_ops; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci if (ops->ndo_siocdevprivate) { 48862306a36Sopenharmony_ci if (netif_device_present(dev)) 48962306a36Sopenharmony_ci return ops->ndo_siocdevprivate(dev, ifr, data, cmd); 49062306a36Sopenharmony_ci else 49162306a36Sopenharmony_ci return -ENODEV; 49262306a36Sopenharmony_ci } 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci return -EOPNOTSUPP; 49562306a36Sopenharmony_ci} 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_cistatic int dev_siocwandev(struct net_device *dev, struct if_settings *ifs) 49862306a36Sopenharmony_ci{ 49962306a36Sopenharmony_ci const struct net_device_ops *ops = dev->netdev_ops; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci if (ops->ndo_siocwandev) { 50262306a36Sopenharmony_ci if (netif_device_present(dev)) 50362306a36Sopenharmony_ci return ops->ndo_siocwandev(dev, ifs); 50462306a36Sopenharmony_ci else 50562306a36Sopenharmony_ci return -ENODEV; 50662306a36Sopenharmony_ci } 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci return -EOPNOTSUPP; 50962306a36Sopenharmony_ci} 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci/* 51262306a36Sopenharmony_ci * Perform the SIOCxIFxxx calls, inside rtnl_lock() 51362306a36Sopenharmony_ci */ 51462306a36Sopenharmony_cistatic int dev_ifsioc(struct net *net, struct ifreq *ifr, void __user *data, 51562306a36Sopenharmony_ci unsigned int cmd) 51662306a36Sopenharmony_ci{ 51762306a36Sopenharmony_ci int err; 51862306a36Sopenharmony_ci struct net_device *dev = __dev_get_by_name(net, ifr->ifr_name); 51962306a36Sopenharmony_ci const struct net_device_ops *ops; 52062306a36Sopenharmony_ci netdevice_tracker dev_tracker; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci if (!dev) 52362306a36Sopenharmony_ci return -ENODEV; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci ops = dev->netdev_ops; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci switch (cmd) { 52862306a36Sopenharmony_ci case SIOCSIFFLAGS: /* Set interface flags */ 52962306a36Sopenharmony_ci return dev_change_flags(dev, ifr->ifr_flags, NULL); 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci case SIOCSIFMETRIC: /* Set the metric on the interface 53262306a36Sopenharmony_ci (currently unused) */ 53362306a36Sopenharmony_ci return -EOPNOTSUPP; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci case SIOCSIFMTU: /* Set the MTU of a device */ 53662306a36Sopenharmony_ci return dev_set_mtu(dev, ifr->ifr_mtu); 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci case SIOCSIFHWADDR: 53962306a36Sopenharmony_ci if (dev->addr_len > sizeof(struct sockaddr)) 54062306a36Sopenharmony_ci return -EINVAL; 54162306a36Sopenharmony_ci return dev_set_mac_address_user(dev, &ifr->ifr_hwaddr, NULL); 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci case SIOCSIFHWBROADCAST: 54462306a36Sopenharmony_ci if (ifr->ifr_hwaddr.sa_family != dev->type) 54562306a36Sopenharmony_ci return -EINVAL; 54662306a36Sopenharmony_ci memcpy(dev->broadcast, ifr->ifr_hwaddr.sa_data, 54762306a36Sopenharmony_ci min(sizeof(ifr->ifr_hwaddr.sa_data_min), 54862306a36Sopenharmony_ci (size_t)dev->addr_len)); 54962306a36Sopenharmony_ci call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); 55062306a36Sopenharmony_ci return 0; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci case SIOCSIFMAP: 55362306a36Sopenharmony_ci return dev_setifmap(dev, ifr); 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci case SIOCADDMULTI: 55662306a36Sopenharmony_ci if (!ops->ndo_set_rx_mode || 55762306a36Sopenharmony_ci ifr->ifr_hwaddr.sa_family != AF_UNSPEC) 55862306a36Sopenharmony_ci return -EINVAL; 55962306a36Sopenharmony_ci if (!netif_device_present(dev)) 56062306a36Sopenharmony_ci return -ENODEV; 56162306a36Sopenharmony_ci return dev_mc_add_global(dev, ifr->ifr_hwaddr.sa_data); 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci case SIOCDELMULTI: 56462306a36Sopenharmony_ci if (!ops->ndo_set_rx_mode || 56562306a36Sopenharmony_ci ifr->ifr_hwaddr.sa_family != AF_UNSPEC) 56662306a36Sopenharmony_ci return -EINVAL; 56762306a36Sopenharmony_ci if (!netif_device_present(dev)) 56862306a36Sopenharmony_ci return -ENODEV; 56962306a36Sopenharmony_ci return dev_mc_del_global(dev, ifr->ifr_hwaddr.sa_data); 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci case SIOCSIFTXQLEN: 57262306a36Sopenharmony_ci if (ifr->ifr_qlen < 0) 57362306a36Sopenharmony_ci return -EINVAL; 57462306a36Sopenharmony_ci return dev_change_tx_queue_len(dev, ifr->ifr_qlen); 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci case SIOCSIFNAME: 57762306a36Sopenharmony_ci ifr->ifr_newname[IFNAMSIZ-1] = '\0'; 57862306a36Sopenharmony_ci return dev_change_name(dev, ifr->ifr_newname); 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci case SIOCWANDEV: 58162306a36Sopenharmony_ci return dev_siocwandev(dev, &ifr->ifr_settings); 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci case SIOCBRADDIF: 58462306a36Sopenharmony_ci case SIOCBRDELIF: 58562306a36Sopenharmony_ci if (!netif_device_present(dev)) 58662306a36Sopenharmony_ci return -ENODEV; 58762306a36Sopenharmony_ci if (!netif_is_bridge_master(dev)) 58862306a36Sopenharmony_ci return -EOPNOTSUPP; 58962306a36Sopenharmony_ci netdev_hold(dev, &dev_tracker, GFP_KERNEL); 59062306a36Sopenharmony_ci rtnl_unlock(); 59162306a36Sopenharmony_ci err = br_ioctl_call(net, netdev_priv(dev), cmd, ifr, NULL); 59262306a36Sopenharmony_ci netdev_put(dev, &dev_tracker); 59362306a36Sopenharmony_ci rtnl_lock(); 59462306a36Sopenharmony_ci return err; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci case SIOCDEVPRIVATE ... SIOCDEVPRIVATE + 15: 59762306a36Sopenharmony_ci return dev_siocdevprivate(dev, ifr, data, cmd); 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci case SIOCSHWTSTAMP: 60062306a36Sopenharmony_ci return dev_set_hwtstamp(dev, ifr); 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci case SIOCGHWTSTAMP: 60362306a36Sopenharmony_ci return dev_get_hwtstamp(dev, ifr); 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci case SIOCGMIIPHY: 60662306a36Sopenharmony_ci case SIOCGMIIREG: 60762306a36Sopenharmony_ci case SIOCSMIIREG: 60862306a36Sopenharmony_ci return dev_eth_ioctl(dev, ifr, cmd); 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci case SIOCBONDENSLAVE: 61162306a36Sopenharmony_ci case SIOCBONDRELEASE: 61262306a36Sopenharmony_ci case SIOCBONDSETHWADDR: 61362306a36Sopenharmony_ci case SIOCBONDSLAVEINFOQUERY: 61462306a36Sopenharmony_ci case SIOCBONDINFOQUERY: 61562306a36Sopenharmony_ci case SIOCBONDCHANGEACTIVE: 61662306a36Sopenharmony_ci return dev_siocbond(dev, ifr, cmd); 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci /* Unknown ioctl */ 61962306a36Sopenharmony_ci default: 62062306a36Sopenharmony_ci err = -EINVAL; 62162306a36Sopenharmony_ci } 62262306a36Sopenharmony_ci return err; 62362306a36Sopenharmony_ci} 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci/** 62662306a36Sopenharmony_ci * dev_load - load a network module 62762306a36Sopenharmony_ci * @net: the applicable net namespace 62862306a36Sopenharmony_ci * @name: name of interface 62962306a36Sopenharmony_ci * 63062306a36Sopenharmony_ci * If a network interface is not present and the process has suitable 63162306a36Sopenharmony_ci * privileges this function loads the module. If module loading is not 63262306a36Sopenharmony_ci * available in this kernel then it becomes a nop. 63362306a36Sopenharmony_ci */ 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_civoid dev_load(struct net *net, const char *name) 63662306a36Sopenharmony_ci{ 63762306a36Sopenharmony_ci struct net_device *dev; 63862306a36Sopenharmony_ci int no_module; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci rcu_read_lock(); 64162306a36Sopenharmony_ci dev = dev_get_by_name_rcu(net, name); 64262306a36Sopenharmony_ci rcu_read_unlock(); 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci no_module = !dev; 64562306a36Sopenharmony_ci if (no_module && capable(CAP_NET_ADMIN)) 64662306a36Sopenharmony_ci no_module = request_module("netdev-%s", name); 64762306a36Sopenharmony_ci if (no_module && capable(CAP_SYS_MODULE)) 64862306a36Sopenharmony_ci request_module("%s", name); 64962306a36Sopenharmony_ci} 65062306a36Sopenharmony_ciEXPORT_SYMBOL(dev_load); 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci/* 65362306a36Sopenharmony_ci * This function handles all "interface"-type I/O control requests. The actual 65462306a36Sopenharmony_ci * 'doing' part of this is dev_ifsioc above. 65562306a36Sopenharmony_ci */ 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci/** 65862306a36Sopenharmony_ci * dev_ioctl - network device ioctl 65962306a36Sopenharmony_ci * @net: the applicable net namespace 66062306a36Sopenharmony_ci * @cmd: command to issue 66162306a36Sopenharmony_ci * @ifr: pointer to a struct ifreq in user space 66262306a36Sopenharmony_ci * @data: data exchanged with userspace 66362306a36Sopenharmony_ci * @need_copyout: whether or not copy_to_user() should be called 66462306a36Sopenharmony_ci * 66562306a36Sopenharmony_ci * Issue ioctl functions to devices. This is normally called by the 66662306a36Sopenharmony_ci * user space syscall interfaces but can sometimes be useful for 66762306a36Sopenharmony_ci * other purposes. The return value is the return from the syscall if 66862306a36Sopenharmony_ci * positive or a negative errno code on error. 66962306a36Sopenharmony_ci */ 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ciint dev_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr, 67262306a36Sopenharmony_ci void __user *data, bool *need_copyout) 67362306a36Sopenharmony_ci{ 67462306a36Sopenharmony_ci int ret; 67562306a36Sopenharmony_ci char *colon; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci if (need_copyout) 67862306a36Sopenharmony_ci *need_copyout = true; 67962306a36Sopenharmony_ci if (cmd == SIOCGIFNAME) 68062306a36Sopenharmony_ci return dev_ifname(net, ifr); 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci ifr->ifr_name[IFNAMSIZ-1] = 0; 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci colon = strchr(ifr->ifr_name, ':'); 68562306a36Sopenharmony_ci if (colon) 68662306a36Sopenharmony_ci *colon = 0; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci /* 68962306a36Sopenharmony_ci * See which interface the caller is talking about. 69062306a36Sopenharmony_ci */ 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci switch (cmd) { 69362306a36Sopenharmony_ci case SIOCGIFHWADDR: 69462306a36Sopenharmony_ci dev_load(net, ifr->ifr_name); 69562306a36Sopenharmony_ci ret = dev_get_mac_address(&ifr->ifr_hwaddr, net, ifr->ifr_name); 69662306a36Sopenharmony_ci if (colon) 69762306a36Sopenharmony_ci *colon = ':'; 69862306a36Sopenharmony_ci return ret; 69962306a36Sopenharmony_ci /* 70062306a36Sopenharmony_ci * These ioctl calls: 70162306a36Sopenharmony_ci * - can be done by all. 70262306a36Sopenharmony_ci * - atomic and do not require locking. 70362306a36Sopenharmony_ci * - return a value 70462306a36Sopenharmony_ci */ 70562306a36Sopenharmony_ci case SIOCGIFFLAGS: 70662306a36Sopenharmony_ci case SIOCGIFMETRIC: 70762306a36Sopenharmony_ci case SIOCGIFMTU: 70862306a36Sopenharmony_ci case SIOCGIFSLAVE: 70962306a36Sopenharmony_ci case SIOCGIFMAP: 71062306a36Sopenharmony_ci case SIOCGIFINDEX: 71162306a36Sopenharmony_ci case SIOCGIFTXQLEN: 71262306a36Sopenharmony_ci dev_load(net, ifr->ifr_name); 71362306a36Sopenharmony_ci rcu_read_lock(); 71462306a36Sopenharmony_ci ret = dev_ifsioc_locked(net, ifr, cmd); 71562306a36Sopenharmony_ci rcu_read_unlock(); 71662306a36Sopenharmony_ci if (colon) 71762306a36Sopenharmony_ci *colon = ':'; 71862306a36Sopenharmony_ci return ret; 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci case SIOCETHTOOL: 72162306a36Sopenharmony_ci dev_load(net, ifr->ifr_name); 72262306a36Sopenharmony_ci ret = dev_ethtool(net, ifr, data); 72362306a36Sopenharmony_ci if (colon) 72462306a36Sopenharmony_ci *colon = ':'; 72562306a36Sopenharmony_ci return ret; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci /* 72862306a36Sopenharmony_ci * These ioctl calls: 72962306a36Sopenharmony_ci * - require superuser power. 73062306a36Sopenharmony_ci * - require strict serialization. 73162306a36Sopenharmony_ci * - return a value 73262306a36Sopenharmony_ci */ 73362306a36Sopenharmony_ci case SIOCGMIIPHY: 73462306a36Sopenharmony_ci case SIOCGMIIREG: 73562306a36Sopenharmony_ci case SIOCSIFNAME: 73662306a36Sopenharmony_ci dev_load(net, ifr->ifr_name); 73762306a36Sopenharmony_ci if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) 73862306a36Sopenharmony_ci return -EPERM; 73962306a36Sopenharmony_ci rtnl_lock(); 74062306a36Sopenharmony_ci ret = dev_ifsioc(net, ifr, data, cmd); 74162306a36Sopenharmony_ci rtnl_unlock(); 74262306a36Sopenharmony_ci if (colon) 74362306a36Sopenharmony_ci *colon = ':'; 74462306a36Sopenharmony_ci return ret; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci /* 74762306a36Sopenharmony_ci * These ioctl calls: 74862306a36Sopenharmony_ci * - require superuser power. 74962306a36Sopenharmony_ci * - require strict serialization. 75062306a36Sopenharmony_ci * - do not return a value 75162306a36Sopenharmony_ci */ 75262306a36Sopenharmony_ci case SIOCSIFMAP: 75362306a36Sopenharmony_ci case SIOCSIFTXQLEN: 75462306a36Sopenharmony_ci if (!capable(CAP_NET_ADMIN)) 75562306a36Sopenharmony_ci return -EPERM; 75662306a36Sopenharmony_ci fallthrough; 75762306a36Sopenharmony_ci /* 75862306a36Sopenharmony_ci * These ioctl calls: 75962306a36Sopenharmony_ci * - require local superuser power. 76062306a36Sopenharmony_ci * - require strict serialization. 76162306a36Sopenharmony_ci * - do not return a value 76262306a36Sopenharmony_ci */ 76362306a36Sopenharmony_ci case SIOCSIFFLAGS: 76462306a36Sopenharmony_ci case SIOCSIFMETRIC: 76562306a36Sopenharmony_ci case SIOCSIFMTU: 76662306a36Sopenharmony_ci case SIOCSIFHWADDR: 76762306a36Sopenharmony_ci case SIOCSIFSLAVE: 76862306a36Sopenharmony_ci case SIOCADDMULTI: 76962306a36Sopenharmony_ci case SIOCDELMULTI: 77062306a36Sopenharmony_ci case SIOCSIFHWBROADCAST: 77162306a36Sopenharmony_ci case SIOCSMIIREG: 77262306a36Sopenharmony_ci case SIOCBONDENSLAVE: 77362306a36Sopenharmony_ci case SIOCBONDRELEASE: 77462306a36Sopenharmony_ci case SIOCBONDSETHWADDR: 77562306a36Sopenharmony_ci case SIOCBONDCHANGEACTIVE: 77662306a36Sopenharmony_ci case SIOCBRADDIF: 77762306a36Sopenharmony_ci case SIOCBRDELIF: 77862306a36Sopenharmony_ci case SIOCSHWTSTAMP: 77962306a36Sopenharmony_ci if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) 78062306a36Sopenharmony_ci return -EPERM; 78162306a36Sopenharmony_ci fallthrough; 78262306a36Sopenharmony_ci case SIOCBONDSLAVEINFOQUERY: 78362306a36Sopenharmony_ci case SIOCBONDINFOQUERY: 78462306a36Sopenharmony_ci dev_load(net, ifr->ifr_name); 78562306a36Sopenharmony_ci rtnl_lock(); 78662306a36Sopenharmony_ci ret = dev_ifsioc(net, ifr, data, cmd); 78762306a36Sopenharmony_ci rtnl_unlock(); 78862306a36Sopenharmony_ci if (need_copyout) 78962306a36Sopenharmony_ci *need_copyout = false; 79062306a36Sopenharmony_ci return ret; 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci case SIOCGIFMEM: 79362306a36Sopenharmony_ci /* Get the per device memory space. We can add this but 79462306a36Sopenharmony_ci * currently do not support it */ 79562306a36Sopenharmony_ci case SIOCSIFMEM: 79662306a36Sopenharmony_ci /* Set the per device memory buffer space. 79762306a36Sopenharmony_ci * Not applicable in our case */ 79862306a36Sopenharmony_ci case SIOCSIFLINK: 79962306a36Sopenharmony_ci return -ENOTTY; 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci /* 80262306a36Sopenharmony_ci * Unknown or private ioctl. 80362306a36Sopenharmony_ci */ 80462306a36Sopenharmony_ci default: 80562306a36Sopenharmony_ci if (cmd == SIOCWANDEV || 80662306a36Sopenharmony_ci cmd == SIOCGHWTSTAMP || 80762306a36Sopenharmony_ci (cmd >= SIOCDEVPRIVATE && 80862306a36Sopenharmony_ci cmd <= SIOCDEVPRIVATE + 15)) { 80962306a36Sopenharmony_ci dev_load(net, ifr->ifr_name); 81062306a36Sopenharmony_ci rtnl_lock(); 81162306a36Sopenharmony_ci ret = dev_ifsioc(net, ifr, data, cmd); 81262306a36Sopenharmony_ci rtnl_unlock(); 81362306a36Sopenharmony_ci return ret; 81462306a36Sopenharmony_ci } 81562306a36Sopenharmony_ci return -ENOTTY; 81662306a36Sopenharmony_ci } 81762306a36Sopenharmony_ci} 818