diff mbox series

[RFC,net-next,v3,18/21] ethtool: provide link state in GET_SETTINGS request

Message ID 5d1c101f83f74008b68c5ae53ab2d9e2cc87db75.1550513384.git.mkubecek@suse.cz
State RFC
Delegated to: David Miller
Headers show
Series ethtool netlink interface, part 1 | expand

Commit Message

Michal Kubecek Feb. 18, 2019, 6:22 p.m. UTC
Add information about device link state (as provided by ETHTOOL_GLINK ioctl
command) into the GET_SETTINGS reply when ETH_SETTINGS_IM_LINK flag is set
in the request.

Note: we cannot use NLA_FLAG for link state as we need three states: off,
on and unknown.

Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
---
 Documentation/networking/ethtool-netlink.txt |  4 +++-
 include/uapi/linux/ethtool_netlink.h         |  4 +++-
 net/ethtool/common.c                         |  8 ++++++++
 net/ethtool/common.h                         |  1 +
 net/ethtool/ioctl.c                          |  8 ++++----
 net/ethtool/settings.c                       | 11 +++++++++++
 6 files changed, 30 insertions(+), 6 deletions(-)
diff mbox series

Patch

diff --git a/Documentation/networking/ethtool-netlink.txt b/Documentation/networking/ethtool-netlink.txt
index 057eb3213cfe..538dad93009f 100644
--- a/Documentation/networking/ethtool-netlink.txt
+++ b/Documentation/networking/ethtool-netlink.txt
@@ -285,6 +285,7 @@  Info mask bits meaning:
     ETH_SETTINGS_IM_LINKMODES		link modes from link_ksettings
     ETH_SETTINGS_IM_WOLINFO		struct ethtool_wolinfo
     ETH_SETTINGS_IM_MSGLEVEL		msglevel
+    ETH_SETTINGS_IM_LINK		link state
 
 Response contents:
 
@@ -304,6 +305,7 @@  Response contents:
         ETHA_WOL_MODES			(bitfield32)	wake on LAN modes
         ETHA_WOL_SOPASS			(binary)	SecureOn(tm) password
     ETHA_SETTINGS_MSGLEVEL	(bitfield32)	debug level
+    ETHA_SETTINGS_LINK		(u8)		link state
 
 Most of the attributes and their values have the same meaning as matching
 members of the corresponding ioctl structures. For ETHA_SETTINGS_LINK_MODES,
@@ -343,7 +345,7 @@  ETHTOOL_SWOL			n/a
 ETHTOOL_GMSGLVL			ETHNL_CMD_GET_SETTINGS
 ETHTOOL_SMSGLVL			n/a
 ETHTOOL_NWAY_RST		n/a
-ETHTOOL_GLINK			n/a
+ETHTOOL_GLINK			ETHNL_CMD_GET_SETTINGS
 ETHTOOL_GEEPROM			n/a
 ETHTOOL_SEEPROM			n/a
 ETHTOOL_GCOALESCE		n/a
diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h
index 360e20a73f19..06e78d94cacc 100644
--- a/include/uapi/linux/ethtool_netlink.h
+++ b/include/uapi/linux/ethtool_netlink.h
@@ -203,6 +203,7 @@  enum {
 	ETHA_SETTINGS_PEER_MODES,		/* bitset */
 	ETHA_SETTINGS_WOL,			/* nested */
 	ETHA_SETTINGS_MSGLEVEL,			/* bitfield32 */
+	ETHA_SETTINGS_LINK,			/* u8 */
 
 	__ETHA_SETTINGS_CNT,
 	ETHA_SETTINGS_MAX = (__ETHA_SETTINGS_CNT - 1)
@@ -212,8 +213,9 @@  enum {
 #define ETH_SETTINGS_IM_LINKMODES		0x02
 #define ETH_SETTINGS_IM_WOLINFO			0x04
 #define ETH_SETTINGS_IM_MSGLEVEL		0x08
+#define ETH_SETTINGS_IM_LINK			0x10
 
-#define ETH_SETTINGS_IM_ALL			0x0f
+#define ETH_SETTINGS_IM_ALL			0x1f
 
 enum {
 	ETHA_LINKINFO_UNSPEC,
diff --git a/net/ethtool/common.c b/net/ethtool/common.c
index 9fba57f554dd..a188f07bcb4c 100644
--- a/net/ethtool/common.c
+++ b/net/ethtool/common.c
@@ -217,3 +217,11 @@  int __ethtool_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 
 	return 0;
 }
+
+int __ethtool_get_link(struct net_device *dev)
+{
+	if (!dev->ethtool_ops->get_link)
+		return -EOPNOTSUPP;
+
+	return netif_running(dev) && dev->ethtool_ops->get_link(dev);
+}
diff --git a/net/ethtool/common.h b/net/ethtool/common.h
index ed3f1ca54660..e5b5c5c2a4b9 100644
--- a/net/ethtool/common.h
+++ b/net/ethtool/common.h
@@ -18,6 +18,7 @@  phy_tunable_strings[__ETHTOOL_PHY_TUNABLE_COUNT][ETH_GSTRING_LEN];
 int __ethtool_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info);
 int __ethtool_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info);
 int __ethtool_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol);
+int __ethtool_get_link(struct net_device *dev);
 
 bool convert_legacy_settings_to_link_ksettings(
 	struct ethtool_link_ksettings *link_ksettings,
diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c
index 945eaf551a4c..63662a3fa2ae 100644
--- a/net/ethtool/ioctl.c
+++ b/net/ethtool/ioctl.c
@@ -1306,12 +1306,12 @@  static int ethtool_nway_reset(struct net_device *dev)
 static int ethtool_get_link(struct net_device *dev, char __user *useraddr)
 {
 	struct ethtool_value edata = { .cmd = ETHTOOL_GLINK };
+	int link = __ethtool_get_link(dev);
 
-	if (!dev->ethtool_ops->get_link)
-		return -EOPNOTSUPP;
-
-	edata.data = netif_running(dev) && dev->ethtool_ops->get_link(dev);
+	if (link < 0)
+		return link;
 
+	edata.data = link;
 	if (copy_to_user(useraddr, &edata, sizeof(edata)))
 		return -EFAULT;
 	return 0;
diff --git a/net/ethtool/settings.c b/net/ethtool/settings.c
index 58cd2d19a75d..099300901c12 100644
--- a/net/ethtool/settings.c
+++ b/net/ethtool/settings.c
@@ -14,6 +14,7 @@  struct settings_data {
 	struct ethtool_link_settings	*lsettings;
 	struct ethtool_wolinfo		wolinfo;
 	u32				msglevel;
+	int				link;
 	bool				lpm_empty;
 };
 
@@ -27,6 +28,7 @@  static const struct nla_policy get_settings_policy[ETHA_SETTINGS_MAX + 1] = {
 	[ETHA_SETTINGS_PEER_MODES]	= { .type = NLA_REJECT },
 	[ETHA_SETTINGS_WOL]		= { .type = NLA_REJECT },
 	[ETHA_SETTINGS_MSGLEVEL]	= { .type = NLA_REJECT },
+	[ETHA_SETTINGS_LINK]		= { .type = NLA_REJECT },
 };
 
 static int parse_settings(struct common_req_info *req_info,
@@ -99,6 +101,7 @@  static int prepare_settings(struct common_req_info *req_info,
 
 	data->lsettings = &data->ksettings.base;
 	data->lpm_empty = true;
+	data->link = -EOPNOTSUPP;
 
 	ret = ethnl_before_ops(dev);
 	if (ret < 0)
@@ -131,6 +134,8 @@  static int prepare_settings(struct common_req_info *req_info,
 		else
 			req_mask &= ~ETH_SETTINGS_IM_MSGLEVEL;
 	}
+	if (req_mask & ETH_SETTINGS_IM_LINK)
+		data->link = __ethtool_get_link(dev);
 	ethnl_after_ops(dev);
 
 	data->repdata_base.info_mask = req_mask;
@@ -209,6 +214,8 @@  static int settings_size(const struct common_req_info *req_info)
 		len += wol_size();
 	if (info_mask & ETH_SETTINGS_IM_MSGLEVEL)
 		len += nla_total_size(sizeof(struct nla_bitfield32));
+	if (info_mask & ETH_SETTINGS_IM_LINK)
+		len += nla_total_size(sizeof(u32));
 
 	return len;
 }
@@ -324,6 +331,10 @@  static int fill_settings(struct sk_buff *skb,
 				       data->msglevel, NETIF_MSG_ALL))
 			return -EMSGSIZE;
 	}
+	if (info_mask & ETH_SETTINGS_IM_LINK && data->link >= 0) {
+		if (nla_put_u8(skb, ETHA_SETTINGS_LINK, data->link))
+			return -EMSGSIZE;
+	}
 
 	return 0;
 }