xref: /linux-6.15/net/core/dev_ioctl.c (revision ed3ba9b6)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
296b45cbdSCong Wang #include <linux/kmod.h>
396b45cbdSCong Wang #include <linux/netdevice.h>
4b0e99d03SArnd Bergmann #include <linux/inetdevice.h>
596b45cbdSCong Wang #include <linux/etherdevice.h>
696b45cbdSCong Wang #include <linux/rtnetlink.h>
796b45cbdSCong Wang #include <linux/net_tstamp.h>
8fd770e85SVladimir Oltean #include <linux/phylib_stubs.h>
935f7cad1SKory Maincent #include <linux/ptp_clock_kernel.h>
1096b45cbdSCong Wang #include <linux/wireless.h>
11ad2f99aeSArnd Bergmann #include <linux/if_bridge.h>
125a178186SVladimir Oltean #include <net/dsa_stubs.h>
1396b45cbdSCong Wang #include <net/netdev_lock.h>
1496b45cbdSCong Wang #include <net/wext.h>
156264f58cSJakub Kicinski 
166264f58cSJakub Kicinski #include "dev.h"
1796b45cbdSCong Wang 
1896b45cbdSCong Wang /*
1996b45cbdSCong Wang  *	Map an interface index to its name (SIOCGIFNAME)
2096b45cbdSCong Wang  */
2196b45cbdSCong Wang 
2296b45cbdSCong Wang /*
2396b45cbdSCong Wang  *	We need this ioctl for efficient implementation of the
2496b45cbdSCong Wang  *	if_indextoname() function required by the IPv6 API.  Without
2596b45cbdSCong Wang  *	it, we would have to search all the interfaces to find a
2696b45cbdSCong Wang  *	match.  --pb
2796b45cbdSCong Wang  */
2844c02a2cSAl Viro 
dev_ifname(struct net * net,struct ifreq * ifr)2996b45cbdSCong Wang static int dev_ifname(struct net *net, struct ifreq *ifr)
3044c02a2cSAl Viro {
3144c02a2cSAl Viro 	ifr->ifr_name[IFNAMSIZ-1] = 0;
3296b45cbdSCong Wang 	return netdev_get_name(net, ifr->ifr_name, ifr->ifr_ifindex);
3396b45cbdSCong Wang }
3496b45cbdSCong Wang 
3596b45cbdSCong Wang /*
3696b45cbdSCong Wang  *	Perform a SIOCGIFCONF call. This structure will change
3796b45cbdSCong Wang  *	size eventually, and there is nothing I can do about it.
3896b45cbdSCong Wang  *	Thus we will need a 'compatibility mode'.
39876f0bf9SArnd Bergmann  */
dev_ifconf(struct net * net,struct ifconf __user * uifc)4096b45cbdSCong Wang int dev_ifconf(struct net *net, struct ifconf __user *uifc)
4196b45cbdSCong Wang {
42876f0bf9SArnd Bergmann 	struct net_device *dev;
43876f0bf9SArnd Bergmann 	void __user *pos;
44876f0bf9SArnd Bergmann 	size_t size;
4596b45cbdSCong Wang 	int len, total = 0, done;
46876f0bf9SArnd Bergmann 
47876f0bf9SArnd Bergmann 	/* both the ifconf and the ifreq structures are slightly different */
48876f0bf9SArnd Bergmann 	if (in_compat_syscall()) {
4996b45cbdSCong Wang 		struct compat_ifconf ifc32;
50876f0bf9SArnd Bergmann 
51876f0bf9SArnd Bergmann 		if (copy_from_user(&ifc32, uifc, sizeof(struct compat_ifconf)))
5296b45cbdSCong Wang 			return -EFAULT;
53876f0bf9SArnd Bergmann 
54876f0bf9SArnd Bergmann 		pos = compat_ptr(ifc32.ifcbuf);
55876f0bf9SArnd Bergmann 		len = ifc32.ifc_len;
56876f0bf9SArnd Bergmann 		size = sizeof(struct compat_ifreq);
57876f0bf9SArnd Bergmann 	} else {
5896b45cbdSCong Wang 		struct ifconf ifc;
59876f0bf9SArnd Bergmann 
60876f0bf9SArnd Bergmann 		if (copy_from_user(&ifc, uifc, sizeof(struct ifconf)))
61876f0bf9SArnd Bergmann 			return -EFAULT;
62876f0bf9SArnd Bergmann 
63876f0bf9SArnd Bergmann 		pos = ifc.ifc_buf;
64876f0bf9SArnd Bergmann 		len = ifc.ifc_len;
65876f0bf9SArnd Bergmann 		size = sizeof(struct ifreq);
66876f0bf9SArnd Bergmann 	}
67876f0bf9SArnd Bergmann 
687ed8da17SKuniyuki Iwashima 	/* Loop over the interfaces, and write an info block for each. */
6996b45cbdSCong Wang 	rtnl_net_lock(net);
7096b45cbdSCong Wang 	for_each_netdev(net, dev) {
71b0e99d03SArnd Bergmann 		if (!pos)
7296b45cbdSCong Wang 			done = inet_gifconf(dev, NULL, 0, size);
73b0e99d03SArnd Bergmann 		else
7436fd633eSAl Viro 			done = inet_gifconf(dev, pos + total,
75876f0bf9SArnd Bergmann 					    len - total, size);
767ed8da17SKuniyuki Iwashima 		if (done < 0) {
7796b45cbdSCong Wang 			rtnl_net_unlock(net);
78876f0bf9SArnd Bergmann 			return -EFAULT;
7996b45cbdSCong Wang 		}
8096b45cbdSCong Wang 		total += done;
817ed8da17SKuniyuki Iwashima 	}
8296b45cbdSCong Wang 	rtnl_net_unlock(net);
83876f0bf9SArnd Bergmann 
8496b45cbdSCong Wang 	return put_user(total, &uifc->ifc_len);
8596b45cbdSCong Wang }
86709566d7SArnd Bergmann 
dev_getifmap(struct net_device * dev,struct ifreq * ifr)87709566d7SArnd Bergmann static int dev_getifmap(struct net_device *dev, struct ifreq *ifr)
88709566d7SArnd Bergmann {
89709566d7SArnd Bergmann 	struct ifmap *ifmap = &ifr->ifr_map;
90709566d7SArnd Bergmann 
91709566d7SArnd Bergmann 	if (in_compat_syscall()) {
92709566d7SArnd Bergmann 		struct compat_ifmap *cifmap = (struct compat_ifmap *)ifmap;
93709566d7SArnd Bergmann 
94709566d7SArnd Bergmann 		cifmap->mem_start = dev->mem_start;
95709566d7SArnd Bergmann 		cifmap->mem_end   = dev->mem_end;
96709566d7SArnd Bergmann 		cifmap->base_addr = dev->base_addr;
97709566d7SArnd Bergmann 		cifmap->irq       = dev->irq;
98709566d7SArnd Bergmann 		cifmap->dma       = dev->dma;
99709566d7SArnd Bergmann 		cifmap->port      = dev->if_port;
100709566d7SArnd Bergmann 
101709566d7SArnd Bergmann 		return 0;
102709566d7SArnd Bergmann 	}
103709566d7SArnd Bergmann 
104709566d7SArnd Bergmann 	ifmap->mem_start  = dev->mem_start;
105709566d7SArnd Bergmann 	ifmap->mem_end    = dev->mem_end;
106709566d7SArnd Bergmann 	ifmap->base_addr  = dev->base_addr;
107709566d7SArnd Bergmann 	ifmap->irq        = dev->irq;
108709566d7SArnd Bergmann 	ifmap->dma        = dev->dma;
109709566d7SArnd Bergmann 	ifmap->port       = dev->if_port;
110709566d7SArnd Bergmann 
111709566d7SArnd Bergmann 	return 0;
112709566d7SArnd Bergmann }
113709566d7SArnd Bergmann 
netif_setifmap(struct net_device * dev,struct ifreq * ifr)114709566d7SArnd Bergmann static int netif_setifmap(struct net_device *dev, struct ifreq *ifr)
115709566d7SArnd Bergmann {
116709566d7SArnd Bergmann 	struct compat_ifmap *cifmap = (struct compat_ifmap *)&ifr->ifr_map;
117709566d7SArnd Bergmann 
118709566d7SArnd Bergmann 	if (!dev->netdev_ops->ndo_set_config)
119709566d7SArnd Bergmann 		return -EOPNOTSUPP;
120709566d7SArnd Bergmann 
121709566d7SArnd Bergmann 	if (in_compat_syscall()) {
122709566d7SArnd Bergmann 		struct ifmap ifmap = {
123709566d7SArnd Bergmann 			.mem_start  = cifmap->mem_start,
124709566d7SArnd Bergmann 			.mem_end    = cifmap->mem_end,
125709566d7SArnd Bergmann 			.base_addr  = cifmap->base_addr,
126709566d7SArnd Bergmann 			.irq        = cifmap->irq,
127709566d7SArnd Bergmann 			.dma        = cifmap->dma,
128709566d7SArnd Bergmann 			.port       = cifmap->port,
129709566d7SArnd Bergmann 		};
130709566d7SArnd Bergmann 
131709566d7SArnd Bergmann 		return dev->netdev_ops->ndo_set_config(dev, &ifmap);
132709566d7SArnd Bergmann 	}
133709566d7SArnd Bergmann 
134709566d7SArnd Bergmann 	return dev->netdev_ops->ndo_set_config(dev, &ifr->ifr_map);
135709566d7SArnd Bergmann }
13696b45cbdSCong Wang 
13796b45cbdSCong Wang /*
13896b45cbdSCong Wang  *	Perform the SIOCxIFxxx calls, inside rcu_read_lock()
13996b45cbdSCong Wang  */
dev_ifsioc_locked(struct net * net,struct ifreq * ifr,unsigned int cmd)14096b45cbdSCong Wang static int dev_ifsioc_locked(struct net *net, struct ifreq *ifr, unsigned int cmd)
14196b45cbdSCong Wang {
14296b45cbdSCong Wang 	int err;
14396b45cbdSCong Wang 	struct net_device *dev = dev_get_by_name_rcu(net, ifr->ifr_name);
14496b45cbdSCong Wang 
14596b45cbdSCong Wang 	if (!dev)
14696b45cbdSCong Wang 		return -ENODEV;
14796b45cbdSCong Wang 
14896b45cbdSCong Wang 	switch (cmd) {
14996b45cbdSCong Wang 	case SIOCGIFFLAGS:	/* Get interface flags */
15096b45cbdSCong Wang 		ifr->ifr_flags = (short) dev_get_flags(dev);
15196b45cbdSCong Wang 		return 0;
15296b45cbdSCong Wang 
15396b45cbdSCong Wang 	case SIOCGIFMETRIC:	/* Get the metric on the interface
15496b45cbdSCong Wang 				   (currently unused) */
15596b45cbdSCong Wang 		ifr->ifr_metric = 0;
15696b45cbdSCong Wang 		return 0;
15796b45cbdSCong Wang 
15896b45cbdSCong Wang 	case SIOCGIFMTU:	/* Get the MTU of a device */
15996b45cbdSCong Wang 		ifr->ifr_mtu = dev->mtu;
16096b45cbdSCong Wang 		return 0;
16196b45cbdSCong Wang 
16296b45cbdSCong Wang 	case SIOCGIFSLAVE:
16396b45cbdSCong Wang 		err = -EINVAL;
16496b45cbdSCong Wang 		break;
16596b45cbdSCong Wang 
166709566d7SArnd Bergmann 	case SIOCGIFMAP:
16796b45cbdSCong Wang 		return dev_getifmap(dev, ifr);
16896b45cbdSCong Wang 
16996b45cbdSCong Wang 	case SIOCGIFINDEX:
17096b45cbdSCong Wang 		ifr->ifr_ifindex = dev->ifindex;
17196b45cbdSCong Wang 		return 0;
17296b45cbdSCong Wang 
17396b45cbdSCong Wang 	case SIOCGIFTXQLEN:
17496b45cbdSCong Wang 		ifr->ifr_qlen = dev->tx_queue_len;
17596b45cbdSCong Wang 		return 0;
17696b45cbdSCong Wang 
17796b45cbdSCong Wang 	default:
17896b45cbdSCong Wang 		/* dev_ioctl() should ensure this case
17996b45cbdSCong Wang 		 * is never reached
18096b45cbdSCong Wang 		 */
18196b45cbdSCong Wang 		WARN_ON(1);
18296b45cbdSCong Wang 		err = -ENOTTY;
18396b45cbdSCong Wang 		break;
18496b45cbdSCong Wang 
18596b45cbdSCong Wang 	}
18696b45cbdSCong Wang 	return err;
18796b45cbdSCong Wang }
188b18fe47cSKory Maincent 
net_hwtstamp_validate(const struct kernel_hwtstamp_config * cfg)18996b45cbdSCong Wang int net_hwtstamp_validate(const struct kernel_hwtstamp_config *cfg)
19096b45cbdSCong Wang {
19196b45cbdSCong Wang 	enum hwtstamp_tx_types tx_type;
19296b45cbdSCong Wang 	enum hwtstamp_rx_filters rx_filter;
19396b45cbdSCong Wang 	int tx_type_valid = 0;
19496b45cbdSCong Wang 	int rx_filter_valid = 0;
195d5d5fd8fSVladimir Oltean 
19696b45cbdSCong Wang 	if (cfg->flags & ~HWTSTAMP_FLAG_MASK)
19796b45cbdSCong Wang 		return -EINVAL;
198d5d5fd8fSVladimir Oltean 
199d5d5fd8fSVladimir Oltean 	tx_type = cfg->tx_type;
20096b45cbdSCong Wang 	rx_filter = cfg->rx_filter;
20196b45cbdSCong Wang 
20296b45cbdSCong Wang 	switch (tx_type) {
20396b45cbdSCong Wang 	case HWTSTAMP_TX_OFF:
20496b45cbdSCong Wang 	case HWTSTAMP_TX_ON:
205b6fd7b96SRichard Cochran 	case HWTSTAMP_TX_ONESTEP_SYNC:
20696b45cbdSCong Wang 	case HWTSTAMP_TX_ONESTEP_P2P:
20796b45cbdSCong Wang 		tx_type_valid = 1;
208f76510b4SMichal Kubecek 		break;
209f76510b4SMichal Kubecek 	case __HWTSTAMP_TX_CNT:
210f76510b4SMichal Kubecek 		/* not a real value */
21196b45cbdSCong Wang 		break;
21296b45cbdSCong Wang 	}
21396b45cbdSCong Wang 
21496b45cbdSCong Wang 	switch (rx_filter) {
21596b45cbdSCong Wang 	case HWTSTAMP_FILTER_NONE:
21696b45cbdSCong Wang 	case HWTSTAMP_FILTER_ALL:
21796b45cbdSCong Wang 	case HWTSTAMP_FILTER_SOME:
21896b45cbdSCong Wang 	case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
21996b45cbdSCong Wang 	case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
22096b45cbdSCong Wang 	case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
22196b45cbdSCong Wang 	case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
22296b45cbdSCong Wang 	case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
22396b45cbdSCong Wang 	case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
22496b45cbdSCong Wang 	case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
22596b45cbdSCong Wang 	case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
22696b45cbdSCong Wang 	case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
22796b45cbdSCong Wang 	case HWTSTAMP_FILTER_PTP_V2_EVENT:
22896b45cbdSCong Wang 	case HWTSTAMP_FILTER_PTP_V2_SYNC:
229b8210a9eSMiroslav Lichvar 	case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
230e3412575SMiroslav Lichvar 	case HWTSTAMP_FILTER_NTP_ALL:
231b8210a9eSMiroslav Lichvar 		rx_filter_valid = 1;
232f76510b4SMichal Kubecek 		break;
233f76510b4SMichal Kubecek 	case __HWTSTAMP_FILTER_CNT:
234f76510b4SMichal Kubecek 		/* not a real value */
23596b45cbdSCong Wang 		break;
23696b45cbdSCong Wang 	}
23796b45cbdSCong Wang 
23896b45cbdSCong Wang 	if (!tx_type_valid || !rx_filter_valid)
23996b45cbdSCong Wang 		return -ERANGE;
24096b45cbdSCong Wang 
24196b45cbdSCong Wang 	return 0;
24296b45cbdSCong Wang }
243a7605370SArnd Bergmann 
244aad74d84SFlorian Fainelli /**
245aad74d84SFlorian Fainelli  * dev_get_hwtstamp_phylib() - Get hardware timestamping settings of NIC
246aad74d84SFlorian Fainelli  *	or of attached phylib PHY
2474ee58e1eSVladimir Oltean  * @dev: Network device
2484ee58e1eSVladimir Oltean  * @cfg: Timestamping configuration structure
2494ee58e1eSVladimir Oltean  *
2504ee58e1eSVladimir Oltean  * Helper for calling the default hardware provider timestamping.
2514ee58e1eSVladimir Oltean  *
2524ee58e1eSVladimir Oltean  * Note: phy_mii_ioctl() only handles SIOCSHWTSTAMP (not SIOCGHWTSTAMP), and
2534ee58e1eSVladimir Oltean  * there only exists a phydev->mii_ts->hwtstamp() method. So this will return
2544ee58e1eSVladimir Oltean  * -EOPNOTSUPP for phylib for now, which is still more accurate than letting
2554ee58e1eSVladimir Oltean  * the netdev handle the GET request.
2564ee58e1eSVladimir Oltean  */
dev_get_hwtstamp_phylib(struct net_device * dev,struct kernel_hwtstamp_config * cfg)257fd770e85SVladimir Oltean int dev_get_hwtstamp_phylib(struct net_device *dev,
258fd770e85SVladimir Oltean 			    struct kernel_hwtstamp_config *cfg)
259fd770e85SVladimir Oltean {
260fd770e85SVladimir Oltean 	struct hwtstamp_provider *hwprov;
261fd770e85SVladimir Oltean 
262fd770e85SVladimir Oltean 	hwprov = rtnl_dereference(dev->hwprov);
2632dd35600SKory Maincent 	if (hwprov) {
264fd770e85SVladimir Oltean 		cfg->qualifier = hwprov->desc.qualifier;
265fd770e85SVladimir Oltean 		if (hwprov->source == HWTSTAMP_SOURCE_PHYLIB &&
266fd770e85SVladimir Oltean 		    hwprov->phydev)
267fd770e85SVladimir Oltean 			return phy_hwtstamp_get(hwprov->phydev, cfg);
268fd770e85SVladimir Oltean 
269fd770e85SVladimir Oltean 		if (hwprov->source == HWTSTAMP_SOURCE_NETDEV)
2705e51e50eSKory Maincent 			return dev->netdev_ops->ndo_hwtstamp_get(dev, cfg);
271fd770e85SVladimir Oltean 
272fd770e85SVladimir Oltean 		return -EOPNOTSUPP;
27335f7cad1SKory Maincent 	}
27435f7cad1SKory Maincent 
27535f7cad1SKory Maincent 	if (phy_is_default_hwtstamp(dev->phydev))
27635f7cad1SKory Maincent 		return phy_hwtstamp_get(dev->phydev, cfg);
27735f7cad1SKory Maincent 
27835f7cad1SKory Maincent 	return dev->netdev_ops->ndo_hwtstamp_get(dev, cfg);
27935f7cad1SKory Maincent }
28035f7cad1SKory Maincent 
dev_get_hwtstamp(struct net_device * dev,struct ifreq * ifr)28135f7cad1SKory Maincent static int dev_get_hwtstamp(struct net_device *dev, struct ifreq *ifr)
28235f7cad1SKory Maincent {
28335f7cad1SKory Maincent 	const struct net_device_ops *ops = dev->netdev_ops;
28435f7cad1SKory Maincent 	struct kernel_hwtstamp_config kernel_cfg = {};
28535f7cad1SKory Maincent 	struct hwtstamp_config cfg;
28635f7cad1SKory Maincent 	int err;
28735f7cad1SKory Maincent 
2882dd35600SKory Maincent 	if (!ops->ndo_hwtstamp_get)
2890f7f463dSKory Maincent 		return dev_eth_ioctl(dev, ifr, SIOCGHWTSTAMP); /* legacy */
2900f7f463dSKory Maincent 
291289354f2SJakub Kicinski 	if (!netif_device_present(dev))
292fd770e85SVladimir Oltean 		return -ENODEV;
293fd770e85SVladimir Oltean 
2944ee58e1eSVladimir Oltean 	kernel_cfg.ifr = ifr;
2954ee58e1eSVladimir Oltean 	netdev_lock_ops(dev);
29666f72230SMaxim Georgiev 	err = dev_get_hwtstamp_phylib(dev, &kernel_cfg);
29766f72230SMaxim Georgiev 	netdev_unlock_ops(dev);
29866f72230SMaxim Georgiev 	if (err)
29966f72230SMaxim Georgiev 		return err;
30066f72230SMaxim Georgiev 
30166f72230SMaxim Georgiev 	/* If the request was resolved through an unconverted driver, omit
30266f72230SMaxim Georgiev 	 * the copy_to_user(), since the implementation has already done that
30366f72230SMaxim Georgiev 	 */
30466f72230SMaxim Georgiev 	if (!kernel_cfg.copied_to_user) {
30566f72230SMaxim Georgiev 		hwtstamp_config_from_kernel(&cfg, &kernel_cfg);
30666f72230SMaxim Georgiev 
307e47d01feSMaxim Georgiev 		if (copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)))
308fd770e85SVladimir Oltean 			return -EFAULT;
30966f72230SMaxim Georgiev 	}
31066f72230SMaxim Georgiev 
31166f72230SMaxim Georgiev 	return 0;
312e47d01feSMaxim Georgiev }
313e47d01feSMaxim Georgiev 
314e47d01feSMaxim Georgiev /**
315e47d01feSMaxim Georgiev  * dev_set_hwtstamp_phylib() - Change hardware timestamping of NIC
31666f72230SMaxim Georgiev  *	or of attached phylib PHY
31766f72230SMaxim Georgiev  * @dev: Network device
31866f72230SMaxim Georgiev  * @cfg: Timestamping configuration structure
31966f72230SMaxim Georgiev  * @extack: Netlink extended ack message structure, for error reporting
320e47d01feSMaxim Georgiev  *
32166f72230SMaxim Georgiev  * Helper for enforcing a common policy that phylib timestamping, if available,
32266f72230SMaxim Georgiev  * should take precedence in front of hardware timestamping provided by the
3234ee58e1eSVladimir Oltean  * netdev. If the netdev driver needs to perform specific actions even for PHY
3244ee58e1eSVladimir Oltean  * timestamping to work properly (a switch port must trap the timestamped
325fd770e85SVladimir Oltean  * frames and not forward them), it must set dev->see_all_hwtstamp_requests.
326fd770e85SVladimir Oltean  */
dev_set_hwtstamp_phylib(struct net_device * dev,struct kernel_hwtstamp_config * cfg,struct netlink_ext_ack * extack)327fd770e85SVladimir Oltean int dev_set_hwtstamp_phylib(struct net_device *dev,
328fd770e85SVladimir Oltean 			    struct kernel_hwtstamp_config *cfg,
329fd770e85SVladimir Oltean 			    struct netlink_ext_ack *extack)
330fd770e85SVladimir Oltean {
331fd770e85SVladimir Oltean 	const struct net_device_ops *ops = dev->netdev_ops;
332289354f2SJakub Kicinski 	struct kernel_hwtstamp_config old_cfg = {};
333289354f2SJakub Kicinski 	struct hwtstamp_provider *hwprov;
334289354f2SJakub Kicinski 	struct phy_device *phydev;
335fd770e85SVladimir Oltean 	bool changed = false;
336beb5a9beSAlexander Lobakin 	bool phy_ts;
337fd770e85SVladimir Oltean 	int err;
338011dd3b3SKory Maincent 
339fd770e85SVladimir Oltean 	hwprov = rtnl_dereference(dev->hwprov);
340fd770e85SVladimir Oltean 	if (hwprov) {
341fd770e85SVladimir Oltean 		if (hwprov->source == HWTSTAMP_SOURCE_PHYLIB &&
342fd770e85SVladimir Oltean 		    hwprov->phydev) {
343fd770e85SVladimir Oltean 			phy_ts = true;
34435f7cad1SKory Maincent 			phydev = hwprov->phydev;
34535f7cad1SKory Maincent 		} else if (hwprov->source == HWTSTAMP_SOURCE_NETDEV) {
346fd770e85SVladimir Oltean 			phy_ts = false;
34735f7cad1SKory Maincent 		} else {
348fd770e85SVladimir Oltean 			return -EOPNOTSUPP;
349fd770e85SVladimir Oltean 		}
35035f7cad1SKory Maincent 
35135f7cad1SKory Maincent 		cfg->qualifier = hwprov->desc.qualifier;
35235f7cad1SKory Maincent 	} else {
35335f7cad1SKory Maincent 		phy_ts = phy_is_default_hwtstamp(dev->phydev);
35435f7cad1SKory Maincent 		if (phy_ts)
35535f7cad1SKory Maincent 			phydev = dev->phydev;
35635f7cad1SKory Maincent 	}
35735f7cad1SKory Maincent 
35835f7cad1SKory Maincent 	cfg->source = phy_ts ? HWTSTAMP_SOURCE_PHYLIB : HWTSTAMP_SOURCE_NETDEV;
35935f7cad1SKory Maincent 
36035f7cad1SKory Maincent 	if (phy_ts && dev->see_all_hwtstamp_requests) {
36135f7cad1SKory Maincent 		err = ops->ndo_hwtstamp_get(dev, &old_cfg);
36235f7cad1SKory Maincent 		if (err)
36335f7cad1SKory Maincent 			return err;
36435f7cad1SKory Maincent 	}
36535f7cad1SKory Maincent 
36635f7cad1SKory Maincent 	if (!phy_ts || dev->see_all_hwtstamp_requests) {
36735f7cad1SKory Maincent 		err = ops->ndo_hwtstamp_set(dev, cfg, extack);
36835f7cad1SKory Maincent 		if (err) {
369289354f2SJakub Kicinski 			if (extack->_msg)
370fd770e85SVladimir Oltean 				netdev_err(dev, "%s\n", extack->_msg);
371beb5a9beSAlexander Lobakin 			return err;
372fd770e85SVladimir Oltean 		}
373fd770e85SVladimir Oltean 	}
374fd770e85SVladimir Oltean 
375c35e927cSVladimir Oltean 	if (phy_ts && dev->see_all_hwtstamp_requests)
376fd770e85SVladimir Oltean 		changed = kernel_hwtstamp_config_changed(&old_cfg, cfg);
377beb5a9beSAlexander Lobakin 
378fd770e85SVladimir Oltean 	if (phy_ts) {
379fd770e85SVladimir Oltean 		err = phy_hwtstamp_set(phydev, cfg, extack);
380fd770e85SVladimir Oltean 		if (err) {
381fd770e85SVladimir Oltean 			if (changed)
382fd770e85SVladimir Oltean 				ops->ndo_hwtstamp_set(dev, &old_cfg, NULL);
383fd770e85SVladimir Oltean 			return err;
384fd770e85SVladimir Oltean 		}
385fd770e85SVladimir Oltean 	}
386beb5a9beSAlexander Lobakin 
387c35e927cSVladimir Oltean 	return 0;
388c35e927cSVladimir Oltean }
389289354f2SJakub Kicinski 
dev_set_hwtstamp(struct net_device * dev,struct ifreq * ifr)39035f7cad1SKory Maincent static int dev_set_hwtstamp(struct net_device *dev, struct ifreq *ifr)
391fd770e85SVladimir Oltean {
392fd770e85SVladimir Oltean 	const struct net_device_ops *ops = dev->netdev_ops;
393fd770e85SVladimir Oltean 	struct kernel_hwtstamp_config kernel_cfg = {};
394fd770e85SVladimir Oltean 	struct netlink_ext_ack extack = {};
395fd770e85SVladimir Oltean 	struct hwtstamp_config cfg;
396fd770e85SVladimir Oltean 	int err;
397fd770e85SVladimir Oltean 
398fd770e85SVladimir Oltean 	if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
399fd770e85SVladimir Oltean 		return -EFAULT;
400fd770e85SVladimir Oltean 
4014ee58e1eSVladimir Oltean 	hwtstamp_config_to_kernel(&kernel_cfg, &cfg);
4024ee58e1eSVladimir Oltean 	kernel_cfg.ifr = ifr;
40366f72230SMaxim Georgiev 
404e47d01feSMaxim Georgiev 	err = net_hwtstamp_validate(&kernel_cfg);
40588c0a6b5SVladimir Oltean 	if (err)
406d5d5fd8fSVladimir Oltean 		return err;
4071ca47431SColin Ian King 
408aad74d84SFlorian Fainelli 	err = dsa_conduit_hwtstamp_validate(dev, &kernel_cfg, &extack);
409d5d5fd8fSVladimir Oltean 	if (err) {
410d5d5fd8fSVladimir Oltean 		if (extack._msg)
411d5d5fd8fSVladimir Oltean 			netdev_err(dev, "%s\n", extack._msg);
412c4bffeaaSVladimir Oltean 		return err;
413e47d01feSMaxim Georgiev 	}
414c4bffeaaSVladimir Oltean 
415c4bffeaaSVladimir Oltean 	if (!ops->ndo_hwtstamp_set)
4164ee58e1eSVladimir Oltean 		return dev_eth_ioctl(dev, ifr, SIOCSHWTSTAMP); /* legacy */
4174ee58e1eSVladimir Oltean 
4184ee58e1eSVladimir Oltean 	if (!netif_device_present(dev))
4196ca80638SFlorian Fainelli 		return -ENODEV;
42088c0a6b5SVladimir Oltean 
42188c0a6b5SVladimir Oltean 	netdev_lock_ops(dev);
42288c0a6b5SVladimir Oltean 	err = dev_set_hwtstamp_phylib(dev, &kernel_cfg, &extack);
4233369afbaSFlorian Fainelli 	netdev_unlock_ops(dev);
42488c0a6b5SVladimir Oltean 	if (err)
4253369afbaSFlorian Fainelli 		return err;
42666f72230SMaxim Georgiev 
42766f72230SMaxim Georgiev 	/* The driver may have modified the configuration, so copy the
42866f72230SMaxim Georgiev 	 * updated version of it back to user space
42966f72230SMaxim Georgiev 	 */
43066f72230SMaxim Georgiev 	if (!kernel_cfg.copied_to_user) {
43166f72230SMaxim Georgiev 		hwtstamp_config_from_kernel(&cfg, &kernel_cfg);
432fd770e85SVladimir Oltean 
433fd770e85SVladimir Oltean 		if (copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)))
43466f72230SMaxim Georgiev 			return -EFAULT;
43566f72230SMaxim Georgiev 	}
43666f72230SMaxim Georgiev 
43766f72230SMaxim Georgiev 	return 0;
43866f72230SMaxim Georgiev }
439e47d01feSMaxim Georgiev 
generic_hwtstamp_ioctl_lower(struct net_device * dev,int cmd,struct kernel_hwtstamp_config * kernel_cfg)44066f72230SMaxim Georgiev static int generic_hwtstamp_ioctl_lower(struct net_device *dev, int cmd,
44166f72230SMaxim Georgiev 					struct kernel_hwtstamp_config *kernel_cfg)
44266f72230SMaxim Georgiev {
44366f72230SMaxim Georgiev 	struct ifreq ifrr;
444e47d01feSMaxim Georgiev 	int err;
44566f72230SMaxim Georgiev 
44666f72230SMaxim Georgiev 	strscpy_pad(ifrr.ifr_name, dev->name, IFNAMSIZ);
447aad74d84SFlorian Fainelli 	ifrr.ifr_ifru = kernel_cfg->ifr->ifr_ifru;
448aad74d84SFlorian Fainelli 
449e47d01feSMaxim Georgiev 	err = dev_eth_ioctl(dev, &ifrr, cmd);
450e47d01feSMaxim Georgiev 	if (err)
451e47d01feSMaxim Georgiev 		return err;
452e47d01feSMaxim Georgiev 
453e47d01feSMaxim Georgiev 	kernel_cfg->ifr->ifr_ifru = ifrr.ifr_ifru;
454e47d01feSMaxim Georgiev 	kernel_cfg->copied_to_user = true;
455e47d01feSMaxim Georgiev 
456e47d01feSMaxim Georgiev 	return 0;
457e47d01feSMaxim Georgiev }
458e47d01feSMaxim Georgiev 
generic_hwtstamp_get_lower(struct net_device * dev,struct kernel_hwtstamp_config * kernel_cfg)459e47d01feSMaxim Georgiev int generic_hwtstamp_get_lower(struct net_device *dev,
460e47d01feSMaxim Georgiev 			       struct kernel_hwtstamp_config *kernel_cfg)
461e47d01feSMaxim Georgiev {
462e47d01feSMaxim Georgiev 	const struct net_device_ops *ops = dev->netdev_ops;
463e47d01feSMaxim Georgiev 
464e47d01feSMaxim Georgiev 	if (!netif_device_present(dev))
465e47d01feSMaxim Georgiev 		return -ENODEV;
466e47d01feSMaxim Georgiev 
467e47d01feSMaxim Georgiev 	if (ops->ndo_hwtstamp_get)
468e47d01feSMaxim Georgiev 		return dev_get_hwtstamp_phylib(dev, kernel_cfg);
469e47d01feSMaxim Georgiev 
470e47d01feSMaxim Georgiev 	/* Legacy path: unconverted lower driver */
471e47d01feSMaxim Georgiev 	return generic_hwtstamp_ioctl_lower(dev, SIOCGHWTSTAMP, kernel_cfg);
472e47d01feSMaxim Georgiev }
473e47d01feSMaxim Georgiev EXPORT_SYMBOL(generic_hwtstamp_get_lower);
474e47d01feSMaxim Georgiev 
generic_hwtstamp_set_lower(struct net_device * dev,struct kernel_hwtstamp_config * kernel_cfg,struct netlink_ext_ack * extack)475e47d01feSMaxim Georgiev int generic_hwtstamp_set_lower(struct net_device *dev,
476e47d01feSMaxim Georgiev 			       struct kernel_hwtstamp_config *kernel_cfg,
477fd770e85SVladimir Oltean 			       struct netlink_ext_ack *extack)
478e47d01feSMaxim Georgiev {
479e47d01feSMaxim Georgiev 	const struct net_device_ops *ops = dev->netdev_ops;
480e47d01feSMaxim Georgiev 
481e47d01feSMaxim Georgiev 	if (!netif_device_present(dev))
482e47d01feSMaxim Georgiev 		return -ENODEV;
483e47d01feSMaxim Georgiev 
484e47d01feSMaxim Georgiev 	if (ops->ndo_hwtstamp_set)
485e47d01feSMaxim Georgiev 		return dev_set_hwtstamp_phylib(dev, kernel_cfg, extack);
486e47d01feSMaxim Georgiev 
487e47d01feSMaxim Georgiev 	/* Legacy path: unconverted lower driver */
488e47d01feSMaxim Georgiev 	return generic_hwtstamp_ioctl_lower(dev, SIOCSHWTSTAMP, kernel_cfg);
489e47d01feSMaxim Georgiev }
490e47d01feSMaxim Georgiev EXPORT_SYMBOL(generic_hwtstamp_set_lower);
491e47d01feSMaxim Georgiev 
dev_siocbond(struct net_device * dev,struct ifreq * ifr,unsigned int cmd)492e47d01feSMaxim Georgiev static int dev_siocbond(struct net_device *dev,
493e47d01feSMaxim Georgiev 			struct ifreq *ifr, unsigned int cmd)
494fd770e85SVladimir Oltean {
495e47d01feSMaxim Georgiev 	const struct net_device_ops *ops = dev->netdev_ops;
496e47d01feSMaxim Georgiev 
497e47d01feSMaxim Georgiev 	if (ops->ndo_siocbond) {
498e47d01feSMaxim Georgiev 		int ret = -ENODEV;
499e47d01feSMaxim Georgiev 
500e47d01feSMaxim Georgiev 		netdev_lock_ops(dev);
5013d9d00bdSArnd Bergmann 		if (netif_device_present(dev))
502a7605370SArnd Bergmann 			ret = ops->ndo_siocbond(dev, ifr, cmd);
503a7605370SArnd Bergmann 		netdev_unlock_ops(dev);
504a7605370SArnd Bergmann 
505a7605370SArnd Bergmann 		return ret;
5063d9d00bdSArnd Bergmann 	}
507a7605370SArnd Bergmann 
5083d9d00bdSArnd Bergmann 	return -EOPNOTSUPP;
509a7605370SArnd Bergmann }
510a7605370SArnd Bergmann 
dev_siocdevprivate(struct net_device * dev,struct ifreq * ifr,void __user * data,unsigned int cmd)511a7605370SArnd Bergmann static int dev_siocdevprivate(struct net_device *dev, struct ifreq *ifr,
512a7605370SArnd Bergmann 			      void __user *data, unsigned int cmd)
513a7605370SArnd Bergmann {
514a7605370SArnd Bergmann 	const struct net_device_ops *ops = dev->netdev_ops;
515a7605370SArnd Bergmann 
516a554bf96SArnd Bergmann 	if (ops->ndo_siocdevprivate) {
517a554bf96SArnd Bergmann 		int ret = -ENODEV;
518b9067f5dSArnd Bergmann 
519b9067f5dSArnd Bergmann 		netdev_lock_ops(dev);
520b9067f5dSArnd Bergmann 		if (netif_device_present(dev))
521b9067f5dSArnd Bergmann 			ret = ops->ndo_siocdevprivate(dev, ifr, data, cmd);
522b9067f5dSArnd Bergmann 		netdev_unlock_ops(dev);
523b9067f5dSArnd Bergmann 
524b9067f5dSArnd Bergmann 		return ret;
525b9067f5dSArnd Bergmann 	}
526b9067f5dSArnd Bergmann 
527b9067f5dSArnd Bergmann 	return -EOPNOTSUPP;
52888fc023fSArnd Bergmann }
529b9067f5dSArnd Bergmann 
dev_siocwandev(struct net_device * dev,struct if_settings * ifs)530b9067f5dSArnd Bergmann static int dev_siocwandev(struct net_device *dev, struct if_settings *ifs)
531ad7eab2aSArnd Bergmann {
532ad7eab2aSArnd Bergmann 	const struct net_device_ops *ops = dev->netdev_ops;
533ad7eab2aSArnd Bergmann 
534ad7eab2aSArnd Bergmann 	if (ops->ndo_siocwandev) {
535ad7eab2aSArnd Bergmann 		int ret = -ENODEV;
536ad7eab2aSArnd Bergmann 
537ad7eab2aSArnd Bergmann 		netdev_lock_ops(dev);
538ad7eab2aSArnd Bergmann 		if (netif_device_present(dev))
539ad7eab2aSArnd Bergmann 			ret = ops->ndo_siocwandev(dev, ifs);
540ad7eab2aSArnd Bergmann 		netdev_unlock_ops(dev);
541ad7eab2aSArnd Bergmann 
542ad7eab2aSArnd Bergmann 		return ret;
543ad7eab2aSArnd Bergmann 	}
544ad7eab2aSArnd Bergmann 
54596b45cbdSCong Wang 	return -EOPNOTSUPP;
546*be94cfdbSKuniyuki Iwashima }
54796b45cbdSCong Wang 
548a554bf96SArnd Bergmann /*
549a554bf96SArnd Bergmann  *	Perform the SIOCxIFxxx calls, inside rtnl_net_lock()
55096b45cbdSCong Wang  */
dev_ifsioc(struct net * net,struct ifreq * ifr,void __user * data,unsigned int cmd)55196b45cbdSCong Wang static int dev_ifsioc(struct net *net, struct ifreq *ifr, void __user *data,
55296b45cbdSCong Wang 		      unsigned int cmd)
55396b45cbdSCong Wang {
55496b45cbdSCong Wang 	int err;
55596b45cbdSCong Wang 	struct net_device *dev = __dev_get_by_name(net, ifr->ifr_name);
55696b45cbdSCong Wang 	const struct net_device_ops *ops;
55796b45cbdSCong Wang 
55896b45cbdSCong Wang 	if (!dev)
55996b45cbdSCong Wang 		return -ENODEV;
56096b45cbdSCong Wang 
56196b45cbdSCong Wang 	ops = dev->netdev_ops;
562567c5e13SPetr Machata 
56396b45cbdSCong Wang 	switch (cmd) {
56496b45cbdSCong Wang 	case SIOCSIFFLAGS:	/* Set interface flags */
56596b45cbdSCong Wang 		return dev_change_flags(dev, ifr->ifr_flags, NULL);
56696b45cbdSCong Wang 
56796b45cbdSCong Wang 	case SIOCSIFMETRIC:	/* Set the metric on the interface
56896b45cbdSCong Wang 				   (currently unused) */
56996b45cbdSCong Wang 		return -EOPNOTSUPP;
57096b45cbdSCong Wang 
57196b45cbdSCong Wang 	case SIOCSIFMTU:	/* Set the MTU of a device */
5720254e0c6SWANG Cong 		return dev_set_mtu(dev, ifr->ifr_mtu);
5730254e0c6SWANG Cong 
5743b23a32aSCong Wang 	case SIOCSIFHWADDR:
57596b45cbdSCong Wang 		if (dev->addr_len > sizeof(struct sockaddr))
57696b45cbdSCong Wang 			return -EINVAL;
57796b45cbdSCong Wang 		return dev_set_mac_address_user(dev, &ifr->ifr_hwaddr, NULL);
57896b45cbdSCong Wang 
57996b45cbdSCong Wang 	case SIOCSIFHWBROADCAST:
580b5f0de6dSKees Cook 		if (ifr->ifr_hwaddr.sa_family != dev->type)
58154aeba7fSFabian Frederick 			return -EINVAL;
58296b45cbdSCong Wang 		memcpy(dev->broadcast, ifr->ifr_hwaddr.sa_data,
58396b45cbdSCong Wang 		       min(sizeof(ifr->ifr_hwaddr.sa_data_min),
58496b45cbdSCong Wang 			   (size_t)dev->addr_len));
58596b45cbdSCong Wang 		netdev_lock_ops(dev);
586709566d7SArnd Bergmann 		call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
58796b45cbdSCong Wang 		netdev_unlock_ops(dev);
58896b45cbdSCong Wang 		return 0;
58996b45cbdSCong Wang 
59096b45cbdSCong Wang 	case SIOCSIFMAP:
59196b45cbdSCong Wang 		netdev_lock_ops(dev);
59296b45cbdSCong Wang 		err = netif_setifmap(dev, ifr);
59396b45cbdSCong Wang 		netdev_unlock_ops(dev);
59496b45cbdSCong Wang 		return err;
59596b45cbdSCong Wang 
59696b45cbdSCong Wang 	case SIOCADDMULTI:
59796b45cbdSCong Wang 		if (!ops->ndo_set_rx_mode ||
59896b45cbdSCong Wang 		    ifr->ifr_hwaddr.sa_family != AF_UNSPEC)
59996b45cbdSCong Wang 			return -EINVAL;
60096b45cbdSCong Wang 		if (!netif_device_present(dev))
60196b45cbdSCong Wang 			return -ENODEV;
60296b45cbdSCong Wang 		netdev_lock_ops(dev);
60396b45cbdSCong Wang 		err = dev_mc_add_global(dev, ifr->ifr_hwaddr.sa_data);
60496b45cbdSCong Wang 		netdev_unlock_ops(dev);
60596b45cbdSCong Wang 		return err;
60696b45cbdSCong Wang 
6078dd30201STariq Toukan 	case SIOCDELMULTI:
60896b45cbdSCong Wang 		if (!ops->ndo_set_rx_mode ||
60996b45cbdSCong Wang 		    ifr->ifr_hwaddr.sa_family != AF_UNSPEC)
61096b45cbdSCong Wang 			return -EINVAL;
61196b45cbdSCong Wang 		if (!netif_device_present(dev))
61296b45cbdSCong Wang 			return -ENODEV;
613ad7eab2aSArnd Bergmann 		netdev_lock_ops(dev);
614ad7eab2aSArnd Bergmann 		err = dev_mc_del_global(dev, ifr->ifr_hwaddr.sa_data);
615ad7eab2aSArnd Bergmann 		netdev_unlock_ops(dev);
61600d521b3SVladimir Oltean 		return err;
61700d521b3SVladimir Oltean 
61800d521b3SVladimir Oltean 	case SIOCSIFTXQLEN:
61996b45cbdSCong Wang 		if (ifr->ifr_qlen < 0)
6204ee58e1eSVladimir Oltean 			return -EINVAL;
62196b45cbdSCong Wang 		return dev_change_tx_queue_len(dev, ifr->ifr_qlen);
62200d521b3SVladimir Oltean 
6234ee58e1eSVladimir Oltean 	case SIOCSIFNAME:
6244ee58e1eSVladimir Oltean 		ifr->ifr_newname[IFNAMSIZ-1] = '\0';
62500d521b3SVladimir Oltean 		return dev_change_name(dev, ifr->ifr_newname);
62600d521b3SVladimir Oltean 
62700d521b3SVladimir Oltean 	case SIOCWANDEV:
62800d521b3SVladimir Oltean 		return dev_siocwandev(dev, &ifr->ifr_settings);
62900d521b3SVladimir Oltean 
63000d521b3SVladimir Oltean 	case SIOCDEVPRIVATE ... SIOCDEVPRIVATE + 15:
63100d521b3SVladimir Oltean 		return dev_siocdevprivate(dev, ifr, data, cmd);
63200d521b3SVladimir Oltean 
63300d521b3SVladimir Oltean 	case SIOCSHWTSTAMP:
63400d521b3SVladimir Oltean 		return dev_set_hwtstamp(dev, ifr);
63500d521b3SVladimir Oltean 
63600d521b3SVladimir Oltean 	case SIOCGHWTSTAMP:
63700d521b3SVladimir Oltean 		return dev_get_hwtstamp(dev, ifr);
63800d521b3SVladimir Oltean 
63996b45cbdSCong Wang 	case SIOCGMIIPHY:
64096b45cbdSCong Wang 	case SIOCGMIIREG:
64196b45cbdSCong Wang 	case SIOCSMIIREG:
64296b45cbdSCong Wang 		return dev_eth_ioctl(dev, ifr, cmd);
64396b45cbdSCong Wang 
64496b45cbdSCong Wang 	case SIOCBONDENSLAVE:
64596b45cbdSCong Wang 	case SIOCBONDRELEASE:
64696b45cbdSCong Wang 	case SIOCBONDSETHWADDR:
64796b45cbdSCong Wang 	case SIOCBONDSLAVEINFOQUERY:
64896b45cbdSCong Wang 	case SIOCBONDINFOQUERY:
64996b45cbdSCong Wang 	case SIOCBONDCHANGEACTIVE:
65096b45cbdSCong Wang 		return dev_siocbond(dev, ifr, cmd);
65196b45cbdSCong Wang 
65296b45cbdSCong Wang 	/* Unknown ioctl */
65396b45cbdSCong Wang 	default:
65496b45cbdSCong Wang 		err = -EINVAL;
65596b45cbdSCong Wang 	}
65696b45cbdSCong Wang 	return err;
65796b45cbdSCong Wang }
65896b45cbdSCong Wang 
65996b45cbdSCong Wang /**
66096b45cbdSCong Wang  *	dev_load 	- load a network module
66196b45cbdSCong Wang  *	@net: the applicable net namespace
66296b45cbdSCong Wang  *	@name: name of interface
66396b45cbdSCong Wang  *
66496b45cbdSCong Wang  *	If a network interface is not present and the process has suitable
66596b45cbdSCong Wang  *	privileges this function loads the module. If module loading is not
66696b45cbdSCong Wang  *	available in this kernel then it becomes a nop.
667e020836dSDaniel Borkmann  */
668e020836dSDaniel Borkmann 
dev_load(struct net * net,const char * name)66996b45cbdSCong Wang void dev_load(struct net *net, const char *name)
67096b45cbdSCong Wang {
67196b45cbdSCong Wang 	struct net_device *dev;
67296b45cbdSCong Wang 	int no_module;
67396b45cbdSCong Wang 
67496b45cbdSCong Wang 	rcu_read_lock();
67596b45cbdSCong Wang 	dev = dev_get_by_name_rcu(net, name);
67696b45cbdSCong Wang 	rcu_read_unlock();
67796b45cbdSCong Wang 
67896b45cbdSCong Wang 	no_module = !dev;
67996b45cbdSCong Wang 	if (no_module && capable(CAP_NET_ADMIN))
68096b45cbdSCong Wang 		no_module = request_module("netdev-%s", name);
681b3c0fd61SBart Van Assche 	if (no_module && capable(CAP_SYS_MODULE))
682e5b42483SHeiner Kallweit 		request_module("%s", name);
683b3c0fd61SBart Van Assche }
68496b45cbdSCong Wang EXPORT_SYMBOL(dev_load);
68596b45cbdSCong Wang 
68696b45cbdSCong Wang /*
68796b45cbdSCong Wang  *	This function handles all "interface"-type I/O control requests. The actual
68896b45cbdSCong Wang  *	'doing' part of this is dev_ifsioc above.
68996b45cbdSCong Wang  */
69096b45cbdSCong Wang 
691a554bf96SArnd Bergmann /**
692a554bf96SArnd Bergmann  *	dev_ioctl	-	network device ioctl
69396b45cbdSCong Wang  *	@net: the applicable net namespace
69496b45cbdSCong Wang  *	@cmd: command to issue
69596b45cbdSCong Wang  *	@ifr: pointer to a struct ifreq in user space
69696b45cbdSCong Wang  *	@data: data exchanged with userspace
69744c02a2cSAl Viro  *	@need_copyout: whether or not copy_to_user() should be called
69844c02a2cSAl Viro  *
69996b45cbdSCong Wang  *	Issue ioctl functions to devices. This is normally called by the
70044c02a2cSAl Viro  *	user space syscall interfaces but can sometimes be useful for
70196b45cbdSCong Wang  *	other purposes. The return value is the return from the syscall if
70244c02a2cSAl Viro  *	positive or a negative errno code on error.
70396b45cbdSCong Wang  */
70444c02a2cSAl Viro 
dev_ioctl(struct net * net,unsigned int cmd,struct ifreq * ifr,void __user * data,bool * need_copyout)70596b45cbdSCong Wang int dev_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr,
70696b45cbdSCong Wang 	      void __user *data, bool *need_copyout)
70796b45cbdSCong Wang {
70896b45cbdSCong Wang 	int ret;
70996b45cbdSCong Wang 	char *colon;
71096b45cbdSCong Wang 
71196b45cbdSCong Wang 	if (need_copyout)
71296b45cbdSCong Wang 		*need_copyout = true;
7133b23a32aSCong Wang 	if (cmd == SIOCGIFNAME)
7143b23a32aSCong Wang 		return dev_ifname(net, ifr);
7153b23a32aSCong Wang 
7163b23a32aSCong Wang 	ifr->ifr_name[IFNAMSIZ-1] = 0;
7173b23a32aSCong Wang 
7183b23a32aSCong Wang 	colon = strchr(ifr->ifr_name, ':');
71996b45cbdSCong Wang 	if (colon)
72096b45cbdSCong Wang 		*colon = 0;
72196b45cbdSCong Wang 
72296b45cbdSCong Wang 	/*
72396b45cbdSCong Wang 	 *	See which interface the caller is talking about.
72496b45cbdSCong Wang 	 */
72596b45cbdSCong Wang 
72696b45cbdSCong Wang 	switch (cmd) {
72796b45cbdSCong Wang 	case SIOCGIFHWADDR:
72896b45cbdSCong Wang 		dev_load(net, ifr->ifr_name);
72996b45cbdSCong Wang 		ret = dev_get_mac_address(&ifr->ifr_hwaddr, net, ifr->ifr_name);
73096b45cbdSCong Wang 		if (colon)
73196b45cbdSCong Wang 			*colon = ':';
732b51f26b1SPaul Moore 		return ret;
73396b45cbdSCong Wang 	/*
73444c02a2cSAl Viro 	 *	These ioctl calls:
73596b45cbdSCong Wang 	 *	- can be done by all.
73696b45cbdSCong Wang 	 *	- atomic and do not require locking.
73796b45cbdSCong Wang 	 *	- return a value
73896b45cbdSCong Wang 	 */
73996b45cbdSCong Wang 	case SIOCGIFFLAGS:
74096b45cbdSCong Wang 	case SIOCGIFMETRIC:
741b51f26b1SPaul Moore 	case SIOCGIFMTU:
742a554bf96SArnd Bergmann 	case SIOCGIFSLAVE:
74396b45cbdSCong Wang 	case SIOCGIFMAP:
74496b45cbdSCong Wang 	case SIOCGIFINDEX:
74596b45cbdSCong Wang 	case SIOCGIFTXQLEN:
74696b45cbdSCong Wang 		dev_load(net, ifr->ifr_name);
74796b45cbdSCong Wang 		rcu_read_lock();
74896b45cbdSCong Wang 		ret = dev_ifsioc_locked(net, ifr, cmd);
74996b45cbdSCong Wang 		rcu_read_unlock();
75096b45cbdSCong Wang 		if (colon)
75196b45cbdSCong Wang 			*colon = ':';
75296b45cbdSCong Wang 		return ret;
75396b45cbdSCong Wang 
75496b45cbdSCong Wang 	case SIOCETHTOOL:
75596b45cbdSCong Wang 		dev_load(net, ifr->ifr_name);
756b51f26b1SPaul Moore 		ret = dev_ethtool(net, ifr, data);
75796b45cbdSCong Wang 		if (colon)
75896b45cbdSCong Wang 			*colon = ':';
759*be94cfdbSKuniyuki Iwashima 		return ret;
760*be94cfdbSKuniyuki Iwashima 
761a554bf96SArnd Bergmann 	/*
762*be94cfdbSKuniyuki Iwashima 	 *	These ioctl calls:
763*be94cfdbSKuniyuki Iwashima 	 *	- require superuser power.
76496b45cbdSCong Wang 	 *	- require strict serialization.
76596b45cbdSCong Wang 	 *	- return a value
76696b45cbdSCong Wang 	 */
76796b45cbdSCong Wang 	case SIOCGMIIPHY:
76896b45cbdSCong Wang 	case SIOCGMIIREG:
76996b45cbdSCong Wang 	case SIOCSIFNAME:
77096b45cbdSCong Wang 		dev_load(net, ifr->ifr_name);
77196b45cbdSCong Wang 		if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
77296b45cbdSCong Wang 			return -EPERM;
77396b45cbdSCong Wang 
77496b45cbdSCong Wang 		rtnl_net_lock(net);
77596b45cbdSCong Wang 		ret = dev_ifsioc(net, ifr, data, cmd);
77696b45cbdSCong Wang 		rtnl_net_unlock(net);
77796b45cbdSCong Wang 
778df561f66SGustavo A. R. Silva 		if (colon)
77996b45cbdSCong Wang 			*colon = ':';
78096b45cbdSCong Wang 		return ret;
78196b45cbdSCong Wang 
78296b45cbdSCong Wang 	/*
78396b45cbdSCong Wang 	 *	These ioctl calls:
78496b45cbdSCong Wang 	 *	- require superuser power.
78596b45cbdSCong Wang 	 *	- require strict serialization.
78696b45cbdSCong Wang 	 *	- do not return a value
78796b45cbdSCong Wang 	 */
78896b45cbdSCong Wang 	case SIOCSIFMAP:
78996b45cbdSCong Wang 	case SIOCSIFTXQLEN:
79096b45cbdSCong Wang 		if (!capable(CAP_NET_ADMIN))
79196b45cbdSCong Wang 			return -EPERM;
79296b45cbdSCong Wang 		fallthrough;
79396b45cbdSCong Wang 	/*
79496b45cbdSCong Wang 	 *	These ioctl calls:
79596b45cbdSCong Wang 	 *	- require local superuser power.
79696b45cbdSCong Wang 	 *	- require strict serialization.
79796b45cbdSCong Wang 	 *	- do not return a value
79896b45cbdSCong Wang 	 */
79996b45cbdSCong Wang 	case SIOCSIFFLAGS:
80096b45cbdSCong Wang 	case SIOCSIFMETRIC:
801df561f66SGustavo A. R. Silva 	case SIOCSIFMTU:
80296b45cbdSCong Wang 	case SIOCSIFHWADDR:
80396b45cbdSCong Wang 	case SIOCSIFSLAVE:
804b51f26b1SPaul Moore 	case SIOCADDMULTI:
805*be94cfdbSKuniyuki Iwashima 	case SIOCDELMULTI:
806*be94cfdbSKuniyuki Iwashima 	case SIOCSIFHWBROADCAST:
807a554bf96SArnd Bergmann 	case SIOCSMIIREG:
808*be94cfdbSKuniyuki Iwashima 	case SIOCBONDENSLAVE:
809*be94cfdbSKuniyuki Iwashima 	case SIOCBONDRELEASE:
81044c02a2cSAl Viro 	case SIOCBONDSETHWADDR:
81144c02a2cSAl Viro 	case SIOCBONDCHANGEACTIVE:
81296b45cbdSCong Wang 	case SIOCSHWTSTAMP:
81396b45cbdSCong Wang 		if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
81496b45cbdSCong Wang 			return -EPERM;
81596b45cbdSCong Wang 		fallthrough;
81696b45cbdSCong Wang 	case SIOCBONDSLAVEINFOQUERY:
81796b45cbdSCong Wang 	case SIOCBONDINFOQUERY:
81896b45cbdSCong Wang 		dev_load(net, ifr->ifr_name);
81996b45cbdSCong Wang 
82096b45cbdSCong Wang 		rtnl_net_lock(net);
82196b45cbdSCong Wang 		ret = dev_ifsioc(net, ifr, data, cmd);
82296b45cbdSCong Wang 		rtnl_net_unlock(net);
82396b45cbdSCong Wang 
82496b45cbdSCong Wang 		if (need_copyout)
82596b45cbdSCong Wang 			*need_copyout = false;
82696b45cbdSCong Wang 		return ret;
82796b45cbdSCong Wang 
828fd468c74SBen Hutchings 	case SIOCGIFMEM:
82996b45cbdSCong Wang 		/* Get the per device memory space. We can add this but
83096b45cbdSCong Wang 		 * currently do not support it */
831b51f26b1SPaul Moore 	case SIOCSIFMEM:
832*be94cfdbSKuniyuki Iwashima 		/* Set the per device memory buffer space.
833*be94cfdbSKuniyuki Iwashima 		 * Not applicable in our case */
834a554bf96SArnd Bergmann 	case SIOCSIFLINK:
835*be94cfdbSKuniyuki Iwashima 		return -ENOTTY;
83696b45cbdSCong Wang 
83796b45cbdSCong Wang 	/*
83896b45cbdSCong Wang 	 *	Unknown or private ioctl.
83996b45cbdSCong Wang 	 */
84096b45cbdSCong Wang 	default:
841 		if (cmd == SIOCWANDEV ||
842 		    cmd == SIOCGHWTSTAMP ||
843 		    (cmd >= SIOCDEVPRIVATE &&
844 		     cmd <= SIOCDEVPRIVATE + 15)) {
845 			dev_load(net, ifr->ifr_name);
846 
847 			rtnl_net_lock(net);
848 			ret = dev_ifsioc(net, ifr, data, cmd);
849 			rtnl_net_unlock(net);
850 			return ret;
851 		}
852 		return -ENOTTY;
853 	}
854 }
855