lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Mon, 18 Feb 2019 19:23:00 +0100 (CET)
From:   Michal Kubecek <mkubecek@...e.cz>
To:     netdev@...r.kernel.org
Cc:     David Miller <davem@...emloft.net>, Andrew Lunn <andrew@...n.ch>,
        Jakub Kicinski <jakub.kicinski@...ronome.com>,
        Jiri Pirko <jiri@...nulli.us>, linux-kernel@...r.kernel.org
Subject: [RFC PATCH net-next v3 19/21] ethtool: provide device features in
 GET_SETTINGS request

Add information about network device features (as provided by
ETHTOOL_GFEATURES ioctl command) in GET_SETTINGS reply when
ETH_SETTINGS_IM_FEATURES flag is set in the request.

This request also provides information provided by ETHTOOL_GRXCSUM,
ETHTOOL_GTXCSUM, ETHTOOL_GSG, ETHTOOL_GTSO, ETHTOOL_GUFO, ETHTOOL_GGSO,
ETHTOOL_GFLAGS and ETHTOOL_GGRO ioctl commands.

Signed-off-by: Michal Kubecek <mkubecek@...e.cz>
---
 Documentation/networking/ethtool-netlink.txt |  36 +++++--
 include/uapi/linux/ethtool_netlink.h         |  15 ++-
 net/ethtool/common.h                         |   2 +
 net/ethtool/ioctl.c                          |   2 -
 net/ethtool/settings.c                       | 108 +++++++++++++++++++
 5 files changed, 150 insertions(+), 13 deletions(-)

diff --git a/Documentation/networking/ethtool-netlink.txt b/Documentation/networking/ethtool-netlink.txt
index 538dad93009f..664c922a05eb 100644
--- a/Documentation/networking/ethtool-netlink.txt
+++ b/Documentation/networking/ethtool-netlink.txt
@@ -286,6 +286,7 @@ Info mask bits meaning:
     ETH_SETTINGS_IM_WOLINFO		struct ethtool_wolinfo
     ETH_SETTINGS_IM_MSGLEVEL		msglevel
     ETH_SETTINGS_IM_LINK		link state
+    ETH_SETTINGS_IM_FEATURES		features
 
 Response contents:
 
@@ -306,6 +307,11 @@ Response contents:
         ETHA_WOL_SOPASS			(binary)	SecureOn(tm) password
     ETHA_SETTINGS_MSGLEVEL	(bitfield32)	debug level
     ETHA_SETTINGS_LINK		(u8)		link state
+    ETHA_SETTINGS_FEATURES	(nested)	device features
+        ETHA_FEATURES_HW		(bitset)	dev->hw_features
+        ETHA_FEATURES_WANTED		(bitset)	dev->wanted_features
+        ETHA_FEATURES_ACTIVE		(bitset)	dev->features
+        ETHA_FEATURES_NOCHANGE		(bitset)	NETIF_F_NEVER_CHANGE
 
 Most of the attributes and their values have the same meaning as matching
 members of the corresponding ioctl structures. For ETHA_SETTINGS_LINK_MODES,
@@ -318,13 +324,23 @@ device and value enabled modes.
 For ETHA_SETTINGS_MSGLEVEL, selector reports all flags supported by kernel and
 value flags enabled for the device.
 
+Bitmaps contained in ETHA_SETTINGS_FEATURES have the same meaning as bitmaps
+used in ioctl interference but attribute names are different (they are based
+on corresponding members of struct net_device). Legacy "flags" are not
+provided, if userspace needs them (most likely only ethtool for backward
+compatibility), it can calculate their values from related feature bits
+itself. ETHA_FEATURES_HW uses mask consisting of all features recognized by
+kernel (to provide all names when using verbose bitmap format), remaining
+three use mask equal to value (to save space).
+
 GET_SETTINGS request is allowed for unprivileged user but ETHA_SETTINGS_SOPASS
 is only provided by kernel in response to privileged (netns CAP_NET_ADMIN)
 requests.
 
 GET_SETTINGS requests allow dumps and messages in the same format as response
 to them are broadcasted as notifications on change of these settings using
-netlink or ioctl ethtool interface.
+netlink or ioctl ethtool interface; feature notifications are also sent
+whenever netdev_update_features() or netdev_change_features() is called.
 
 
 Request translation
@@ -354,30 +370,30 @@ ETHTOOL_GRINGPARAM		n/a
 ETHTOOL_SRINGPARAM		n/a
 ETHTOOL_GPAUSEPARAM		n/a
 ETHTOOL_SPAUSEPARAM		n/a
-ETHTOOL_GRXCSUM			n/a
+ETHTOOL_GRXCSUM			ETHNL_CMD_GET_SETTINGS
 ETHTOOL_SRXCSUM			n/a
-ETHTOOL_GTXCSUM			n/a
+ETHTOOL_GTXCSUM			ETHNL_CMD_GET_SETTINGS
 ETHTOOL_STXCSUM			n/a
-ETHTOOL_GSG			n/a
+ETHTOOL_GSG			ETHNL_CMD_GET_SETTINGS
 ETHTOOL_SSG			n/a
 ETHTOOL_TEST			n/a
 ETHTOOL_GSTRINGS		ETHNL_CMD_GET_STRSET
 ETHTOOL_PHYS_ID			n/a
 ETHTOOL_GSTATS			n/a
-ETHTOOL_GTSO			n/a
+ETHTOOL_GTSO			ETHNL_CMD_GET_SETTINGS
 ETHTOOL_STSO			n/a
 ETHTOOL_GPERMADDR		ETHNL_CMD_GET_INFO
-ETHTOOL_GUFO			n/a
+ETHTOOL_GUFO			ETHNL_CMD_GET_SETTINGS
 ETHTOOL_SUFO			n/a
-ETHTOOL_GGSO			n/a
+ETHTOOL_GGSO			ETHNL_CMD_GET_SETTINGS
 ETHTOOL_SGSO			n/a
-ETHTOOL_GFLAGS			n/a
+ETHTOOL_GFLAGS			ETHNL_CMD_GET_SETTINGS
 ETHTOOL_SFLAGS			n/a
 ETHTOOL_GPFLAGS			n/a
 ETHTOOL_SPFLAGS			n/a
 ETHTOOL_GRXFH			n/a
 ETHTOOL_SRXFH			n/a
-ETHTOOL_GGRO			n/a
+ETHTOOL_GGRO			ETHNL_CMD_GET_SETTINGS
 ETHTOOL_SGRO			n/a
 ETHTOOL_GRXRINGS		n/a
 ETHTOOL_GRXCLSRLCNT		n/a
@@ -392,7 +408,7 @@ ETHTOOL_GRXNTUPLE		n/a
 ETHTOOL_GSSET_INFO		ETHNL_CMD_GET_STRSET
 ETHTOOL_GRXFHINDIR		n/a
 ETHTOOL_SRXFHINDIR		n/a
-ETHTOOL_GFEATURES		n/a
+ETHTOOL_GFEATURES		ETHNL_CMD_GET_SETTINGS
 ETHTOOL_SFEATURES		n/a
 ETHTOOL_GCHANNELS		n/a
 ETHTOOL_SCHANNELS		n/a
diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h
index 06e78d94cacc..154d7e6a59dd 100644
--- a/include/uapi/linux/ethtool_netlink.h
+++ b/include/uapi/linux/ethtool_netlink.h
@@ -204,6 +204,7 @@ enum {
 	ETHA_SETTINGS_WOL,			/* nested */
 	ETHA_SETTINGS_MSGLEVEL,			/* bitfield32 */
 	ETHA_SETTINGS_LINK,			/* u8 */
+	ETHA_SETTINGS_FEATURES,			/* nest - ETHA_FEATURES_* */
 
 	__ETHA_SETTINGS_CNT,
 	ETHA_SETTINGS_MAX = (__ETHA_SETTINGS_CNT - 1)
@@ -214,8 +215,20 @@ enum {
 #define ETH_SETTINGS_IM_WOLINFO			0x04
 #define ETH_SETTINGS_IM_MSGLEVEL		0x08
 #define ETH_SETTINGS_IM_LINK			0x10
+#define ETH_SETTINGS_IM_FEATURES		0x20
 
-#define ETH_SETTINGS_IM_ALL			0x1f
+#define ETH_SETTINGS_IM_ALL			0x3f
+
+enum {
+	ETHA_FEATURES_UNSPEC,
+	ETHA_FEATURES_HW,			/* bitset */
+	ETHA_FEATURES_WANTED,			/* bitset */
+	ETHA_FEATURES_ACTIVE,			/* bitset */
+	ETHA_FEATURES_NOCHANGE,			/* bitset */
+
+	__ETHA_FEATURES_CNT,
+	ETHA_FEATURES_MAX = (__ETHA_FEATURES_CNT - 1)
+};
 
 enum {
 	ETHA_LINKINFO_UNSPEC,
diff --git a/net/ethtool/common.h b/net/ethtool/common.h
index e5b5c5c2a4b9..cf0b81af2d9f 100644
--- a/net/ethtool/common.h
+++ b/net/ethtool/common.h
@@ -6,6 +6,8 @@
 #include <linux/netdevice.h>
 #include <linux/ethtool.h>
 
+#define ETHTOOL_DEV_FEATURE_WORDS	((NETDEV_FEATURE_COUNT + 31) / 32)
+
 extern const char
 netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN];
 extern const char
diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c
index 63662a3fa2ae..6c3b492a88fe 100644
--- a/net/ethtool/ioctl.c
+++ b/net/ethtool/ioctl.c
@@ -58,8 +58,6 @@ EXPORT_SYMBOL(ethtool_op_get_ts_info);
 
 /* Handlers for each ethtool command */
 
-#define ETHTOOL_DEV_FEATURE_WORDS	((NETDEV_FEATURE_COUNT + 31) / 32)
-
 static int ethtool_get_features(struct net_device *dev, void __user *useraddr)
 {
 	struct ethtool_gfeatures cmd = {
diff --git a/net/ethtool/settings.c b/net/ethtool/settings.c
index 099300901c12..32ee273de879 100644
--- a/net/ethtool/settings.c
+++ b/net/ethtool/settings.c
@@ -16,6 +16,12 @@ struct settings_data {
 	u32				msglevel;
 	int				link;
 	bool				lpm_empty;
+	struct {
+		u32	hw[ETHTOOL_DEV_FEATURE_WORDS];
+		u32	wanted[ETHTOOL_DEV_FEATURE_WORDS];
+		u32	active[ETHTOOL_DEV_FEATURE_WORDS];
+		u32	nochange[ETHTOOL_DEV_FEATURE_WORDS];
+	} features;
 };
 
 static const struct nla_policy get_settings_policy[ETHA_SETTINGS_MAX + 1] = {
@@ -29,6 +35,7 @@ static const struct nla_policy get_settings_policy[ETHA_SETTINGS_MAX + 1] = {
 	[ETHA_SETTINGS_WOL]		= { .type = NLA_REJECT },
 	[ETHA_SETTINGS_MSGLEVEL]	= { .type = NLA_REJECT },
 	[ETHA_SETTINGS_LINK]		= { .type = NLA_REJECT },
+	[ETHA_SETTINGS_FEATURES]	= { .type = NLA_REJECT },
 };
 
 static int parse_settings(struct common_req_info *req_info,
@@ -89,6 +96,24 @@ static int ethnl_get_wol(struct genl_info *info, struct net_device *dev,
 	return ret;
 }
 
+static void features_to_bitmap(u32 *dest, netdev_features_t src)
+{
+	unsigned int i;
+
+	for (i = 0; i < ETHTOOL_DEV_FEATURE_WORDS; i++)
+		dest[i] = (u32)(src >> (32 * i));
+}
+
+static int ethnl_get_features(struct net_device *dev,
+			      struct settings_data *data)
+{
+	features_to_bitmap(data->features.hw, dev->hw_features);
+	features_to_bitmap(data->features.wanted, dev->wanted_features);
+	features_to_bitmap(data->features.active, dev->features);
+	features_to_bitmap(data->features.nochange, NETIF_F_NEVER_CHANGE);
+	return 0;
+}
+
 static int prepare_settings(struct common_req_info *req_info,
 			    struct genl_info *info)
 {
@@ -136,6 +161,8 @@ static int prepare_settings(struct common_req_info *req_info,
 	}
 	if (req_mask & ETH_SETTINGS_IM_LINK)
 		data->link = __ethtool_get_link(dev);
+	if (req_mask & ETH_SETTINGS_IM_FEATURES)
+		ethnl_get_features(dev, data);
 	ethnl_after_ops(dev);
 
 	data->repdata_base.info_mask = req_mask;
@@ -189,6 +216,38 @@ static int wol_size(void)
 			      nla_total_size(SOPASS_MAX));
 }
 
+static int features_size(const struct settings_data *data)
+{
+	unsigned int flags =
+		(data->reqinfo_base.compact ? ETHNL_BITSET_COMPACT : 0) |
+		ETHNL_BITSET_LEGACY_NAMES;
+	int len = 0, ret;
+
+	ret = ethnl_bitset32_size(NETDEV_FEATURE_COUNT, data->features.hw,
+				  NULL, netdev_features_strings, flags);
+	if (ret < 0)
+		return ret;
+	len += ret;
+	flags |= ETHNL_BITSET_LIST;
+	ret = ethnl_bitset32_size(NETDEV_FEATURE_COUNT, data->features.wanted,
+				  NULL, netdev_features_strings, flags);
+	if (ret < 0)
+		return ret;
+	len += ret;
+	ret = ethnl_bitset32_size(NETDEV_FEATURE_COUNT, data->features.active,
+				  NULL, netdev_features_strings, flags);
+	if (ret < 0)
+		return ret;
+	len += ret;
+	ret = ethnl_bitset32_size(NETDEV_FEATURE_COUNT, data->features.nochange,
+				  NULL, netdev_features_strings, flags);
+	if (ret < 0)
+		return ret;
+	len += ret;
+
+	return len;
+}
+
 /* To keep things simple, reserve space for some attributes which may not
  * be added to the message (e.g. ETHA_SETTINGS_SOPASS); therefore the length
  * returned may be bigger than the actual length of the message sent
@@ -216,6 +275,12 @@ static int settings_size(const struct common_req_info *req_info)
 		len += nla_total_size(sizeof(struct nla_bitfield32));
 	if (info_mask & ETH_SETTINGS_IM_LINK)
 		len += nla_total_size(sizeof(u32));
+	if (info_mask & ETH_SETTINGS_IM_FEATURES) {
+		ret = features_size(data);
+		if (ret < 0)
+			return ret;
+		len += ret;
+	}
 
 	return len;
 }
@@ -301,6 +366,44 @@ static int fill_wolinfo(struct sk_buff *skb,
 	return -EMSGSIZE;
 }
 
+static int fill_features(struct sk_buff *skb, const struct settings_data *data)
+{
+	unsigned int flags =
+		(data->reqinfo_base.compact ? ETHNL_BITSET_COMPACT : 0) |
+		ETHNL_BITSET_LEGACY_NAMES;
+	struct nlattr *feat_attr;
+	int ret;
+
+	feat_attr = ethnl_nest_start(skb, ETHA_SETTINGS_FEATURES);
+	if (!feat_attr)
+		return -EMSGSIZE;
+
+	ret = ethnl_put_bitset32(skb, ETHA_FEATURES_HW, NETDEV_FEATURE_COUNT,
+				 data->features.hw, NULL,
+				 netdev_features_strings, flags);
+	if (ret < 0)
+		return ret;
+	flags |= ETHNL_BITSET_LIST;
+	ret = ethnl_put_bitset32(skb, ETHA_FEATURES_WANTED,
+				 NETDEV_FEATURE_COUNT, data->features.wanted,
+				 NULL, netdev_features_strings, flags);
+	if (ret < 0)
+		return ret;
+	ret = ethnl_put_bitset32(skb, ETHA_FEATURES_ACTIVE,
+				 NETDEV_FEATURE_COUNT, data->features.active,
+				 NULL, netdev_features_strings, flags);
+	if (ret < 0)
+		return ret;
+	ret = ethnl_put_bitset32(skb, ETHA_FEATURES_NOCHANGE,
+				 NETDEV_FEATURE_COUNT, data->features.nochange,
+				 NULL, netdev_features_strings, flags);
+	if (ret < 0)
+		return ret;
+
+	nla_nest_end(skb, feat_attr);
+	return 0;
+}
+
 static int fill_settings(struct sk_buff *skb,
 			 const struct common_req_info *req_info)
 {
@@ -335,6 +438,11 @@ static int fill_settings(struct sk_buff *skb,
 		if (nla_put_u8(skb, ETHA_SETTINGS_LINK, data->link))
 			return -EMSGSIZE;
 	}
+	if (info_mask & ETH_SETTINGS_IM_FEATURES) {
+		ret = fill_features(skb, data);
+		if (ret < 0)
+			return ret;
+	}
 
 	return 0;
 }
-- 
2.20.1

Powered by blists - more mailing lists