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]
Message-Id: <1127951c1ac8d2fb6fcb3d6caba6f45bcd74a37d.1532953989.git.mkubecek@suse.cz>
Date:   Mon, 30 Jul 2018 14:53:52 +0200 (CEST)
From:   Michal Kubecek <mkubecek@...e.cz>
To:     netdev@...r.kernel.org
Cc:     linux-kernel@...r.kernel.org, Jiri Pirko <jiri@...nulli.us>,
        David Miller <davem@...emloft.net>,
        Florian Fainelli <f.fainelli@...il.com>,
        Roopa Prabhu <roopa@...ulusnetworks.com>,
        Jakub Kicinski <kubakici@...pl>,
        "John W. Linville" <linville@...driver.com>
Subject: [RFC PATCH net-next v2 14/17] ethtool: implement SET_SETTINGS request
 for features

Using ETHNL_SETTINGS_FEATURES attribute, userspace can modify device
features. Actual change is subject to netdev_change_features() sanity
checks so that it can differ from what was requested. Unlike with most
other requests, kernel can reply (if ETHA_FEATURES_WANT_DIFF flag is used)
with a message in the same format but with different semantics: information
about difference between user request and actual result and difference
between old and new state of dev->features.

Signed-off-by: Michal Kubecek <mkubecek@...e.cz>
---
 Documentation/networking/ethtool-netlink.txt |  30 +++--
 include/uapi/linux/ethtool_netlink.h         |   1 +
 net/ethtool/settings.c                       | 127 +++++++++++++++++++
 3 files changed, 150 insertions(+), 8 deletions(-)

diff --git a/Documentation/networking/ethtool-netlink.txt b/Documentation/networking/ethtool-netlink.txt
index c7fe4f518972..307d8c6c6c85 100644
--- a/Documentation/networking/ethtool-netlink.txt
+++ b/Documentation/networking/ethtool-netlink.txt
@@ -285,6 +285,9 @@ to be passed with SET_SETTINGS request:
     ETHA_SETTINGS_SOPASS        (binary)        SecureOn(tm) password
     ETHA_SETTINGS_MSGLVL        (bitfield32)    debug level
     ETHA_SETTINGS_LINK_MODES    (bitset)        device link modes
+    ETHA_SETTINGS_FEATURES	(nested)	device features
+        ETHA_FEATURES_WANTED		(bitset)	wanted features
+        ETHA_FEATURES_WANT_DIFF		(flag)		actual diff
 
 For both bitfield32 types, value and selector work the usual way, i.e. bits
 set in selector are set to corresponding bits from value and the rest is
@@ -299,6 +302,17 @@ autoselection is done on ethtool side with ioctl interface, netlink interface
 is supposed to allow requesting changes without knowing what exactly kernel
 supports.
 
+When changing device features, only ETHA_FEATURES_WANTED is passed. As usual,
+mask defines which bits are to be set and value their values. If the request
+has ETHA_FEATURES_WANT_DIFF flag set, reply will contain a message in the same
+format as response to GET request, except only two bitsets are provided.
+ETHA_FEATURES_WANTED shows difference between requested features and actual
+result (dev->features after the operation); mask shows bits which differ and
+value their values from the original request (new values are negated). Value
+shows changes between old dev->features (before the operation) and new (after
+the operation); mask shows bits which have been changed and value their new
+values.
+
 
 Request translation
 -------------------
@@ -328,30 +342,30 @@ ETHTOOL_SRINGPARAM		n/a
 ETHTOOL_GPAUSEPARAM		n/a
 ETHTOOL_SPAUSEPARAM		n/a
 ETHTOOL_GRXCSUM			ETHNL_CMD_GET_SETTINGS
-ETHTOOL_SRXCSUM			n/a
+ETHTOOL_SRXCSUM			ETHNL_CMD_SET_SETTINGS
 ETHTOOL_GTXCSUM			ETHNL_CMD_GET_SETTINGS
-ETHTOOL_STXCSUM			n/a
+ETHTOOL_STXCSUM			ETHNL_CMD_SET_SETTINGS
 ETHTOOL_GSG			ETHNL_CMD_GET_SETTINGS
-ETHTOOL_SSG			n/a
+ETHTOOL_SSG			ETHNL_CMD_SET_SETTINGS
 ETHTOOL_TEST			n/a
 ETHTOOL_GSTRINGS		ETHNL_CMD_GET_STRSET
 ETHTOOL_PHYS_ID			n/a
 ETHTOOL_GSTATS			n/a
 ETHTOOL_GTSO			ETHNL_CMD_GET_SETTINGS
-ETHTOOL_STSO			n/a
+ETHTOOL_STSO			ETHNL_CMD_SET_SETTINGS
 ETHTOOL_GPERMADDR		n/a
 ETHTOOL_GUFO			ETHNL_CMD_GET_SETTINGS
-ETHTOOL_SUFO			n/a
+ETHTOOL_SUFO			ETHNL_CMD_SET_SETTINGS
 ETHTOOL_GGSO			ETHNL_CMD_GET_SETTINGS
-ETHTOOL_SGSO			n/a
+ETHTOOL_SGSO			ETHNL_CMD_SET_SETTINGS
 ETHTOOL_GFLAGS			ETHNL_CMD_GET_SETTINGS
-ETHTOOL_SFLAGS			n/a
+ETHTOOL_SFLAGS			ETHNL_CMD_SET_SETTINGS
 ETHTOOL_GPFLAGS			n/a
 ETHTOOL_SPFLAGS			n/a
 ETHTOOL_GRXFH			n/a
 ETHTOOL_SRXFH			n/a
 ETHTOOL_GGRO			ETHNL_CMD_GET_SETTINGS
-ETHTOOL_SGRO			n/a
+ETHTOOL_SGRO			ETHNL_CMD_SET_SETTINGS
 ETHTOOL_GRXRINGS		n/a
 ETHTOOL_GRXCLSRLCNT		n/a
 ETHTOOL_GRXCLSRULE		n/a
diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h
index 06c78b281275..8dfcb9ef4009 100644
--- a/include/uapi/linux/ethtool_netlink.h
+++ b/include/uapi/linux/ethtool_netlink.h
@@ -191,6 +191,7 @@ enum {
 	ETHA_FEATURES_WANTED,			/* bitset */
 	ETHA_FEATURES_ACTIVE,			/* bitset */
 	ETHA_FEATURES_NOCHANGE,			/* bitset */
+	ETHA_FEATURES_WANT_DIFF,		/* flag */
 
 	__ETHA_FEATURES_MAX,
 	ETHA_FEATURES_MAX = (__ETHA_FEATURES_MAX - 1)
diff --git a/net/ethtool/settings.c b/net/ethtool/settings.c
index 678199e621a2..475582b7950c 100644
--- a/net/ethtool/settings.c
+++ b/net/ethtool/settings.c
@@ -1016,6 +1016,122 @@ static int ethnl_update_lsettings(struct genl_info *info, struct nlattr **tb,
 	return 0;
 }
 
+static const struct nla_policy features_policy[ETHA_FEATURES_MAX + 1] = {
+	[ETHA_FEATURES_UNSPEC]		= { .type = NLA_UNSPEC },
+	[ETHA_FEATURES_HW]		= { .type = NLA_NESTED },
+	[ETHA_FEATURES_WANTED]		= { .type = NLA_NESTED },
+	[ETHA_FEATURES_ACTIVE]		= { .type = NLA_NESTED },
+	[ETHA_FEATURES_NOCHANGE]	= { .type = NLA_NESTED },
+	[ETHA_FEATURES_WANT_DIFF]	= { .type = NLA_FLAG },
+};
+
+static void bitmap_from_features(unsigned long *bitmap, netdev_features_t val)
+{
+	const unsigned int words = BITS_TO_LONGS(NETDEV_FEATURE_COUNT);
+	unsigned int i;
+
+	bitmap_zero(bitmap, NETDEV_FEATURE_COUNT);
+	for (i = 0; i < words; i++)
+		bitmap[i] = (unsigned long)(val >> (i * BITS_PER_LONG));
+}
+
+static netdev_features_t features_from_bitmap(unsigned long *bitmap)
+{
+	const unsigned int words = BITS_TO_LONGS(NETDEV_FEATURE_COUNT);
+	netdev_features_t ret = 0;
+	unsigned int i;
+
+	for (i = 0; i < words; i++)
+		ret |= (netdev_features_t)(bitmap[i]) << (i * BITS_PER_LONG);
+	return ret;
+}
+
+int update_features(struct genl_info *info, struct net_device *dev,
+		    const struct nlattr *nest, bool compact)
+{
+	struct nlattr *tb[ETHA_FEATURES_MAX + 1];
+	DECLARE_BITMAP(old_active, NETDEV_FEATURE_COUNT);
+	DECLARE_BITMAP(req_wanted, NETDEV_FEATURE_COUNT);
+	DECLARE_BITMAP(req_mask, NETDEV_FEATURE_COUNT);
+	DECLARE_BITMAP(new_active, NETDEV_FEATURE_COUNT);
+	DECLARE_BITMAP(wanted_diff_mask, NETDEV_FEATURE_COUNT);
+	DECLARE_BITMAP(active_diff_mask, NETDEV_FEATURE_COUNT);
+	struct nlattr *feat_attr;
+	unsigned int reply_len;
+	struct sk_buff *rskb;
+	bool mod = false;
+	void *ehdr;
+	int ret;
+
+	ret = nla_parse_nested(tb, ETHA_FEATURES_MAX, nest, features_policy,
+			       info->extack);
+	if (ret < 0)
+		return ret;
+	if (tb[ETHA_FEATURES_HW] || !tb[ETHA_FEATURES_WANTED] ||
+	    tb[ETHA_FEATURES_ACTIVE] || tb[ETHA_FEATURES_NOCHANGE])
+		return -EINVAL;
+
+	bitmap_from_features(old_active, dev->features);
+	bitmap_copy(req_wanted, old_active, NETDEV_FEATURE_COUNT);
+	bitmap_zero(req_mask, NETDEV_FEATURE_COUNT);
+	mod = ethnl_update_bitset(req_wanted, req_mask, NETDEV_FEATURE_COUNT,
+				  tb[ETHA_FEATURES_WANTED], &ret, feature_names,
+				  info);
+	if (ret < 0 || !mod)
+		return ret;
+
+	dev->wanted_features = features_from_bitmap(req_wanted);
+	netdev_update_features(dev);
+	if (!tb[ETHA_FEATURES_WANT_DIFF])
+		return 0;
+	bitmap_from_features(new_active, dev->features);
+	bitmap_xor(wanted_diff_mask, req_wanted, new_active,
+		   NETDEV_FEATURE_COUNT);
+	bitmap_xor(active_diff_mask, old_active, new_active,
+		   NETDEV_FEATURE_COUNT);
+	bitmap_and(wanted_diff_mask, wanted_diff_mask, req_mask,
+		   NETDEV_FEATURE_COUNT);
+	bitmap_and(req_wanted, req_wanted, wanted_diff_mask,
+		   NETDEV_FEATURE_COUNT);
+	bitmap_and(new_active, new_active, active_diff_mask,
+		   NETDEV_FEATURE_COUNT);
+
+	reply_len = ethnl_bitset_size(compact, NETDEV_FEATURE_COUNT, req_wanted,
+				      wanted_diff_mask, feature_names) +
+		    ethnl_bitset_size(compact, NETDEV_FEATURE_COUNT, new_active,
+				      active_diff_mask, feature_names);
+	reply_len = nla_total_size(reply_len);
+	rskb = ethnl_reply_init(reply_len, dev, ETHNL_CMD_SET_SETTINGS,
+				ETHA_SETTINGS_DEV, info, &ehdr);
+	if (!rskb)
+		goto err;
+	ret = -EMSGSIZE;
+
+	feat_attr = ethnl_nest_start(rskb, ETHA_SETTINGS_FEATURES);
+	if (!feat_attr)
+		goto err;
+	ret = ethnl_put_bitset(rskb, ETHA_FEATURES_WANTED, compact,
+			       NETDEV_FEATURE_COUNT, req_wanted,
+			       wanted_diff_mask, feature_names);
+	if (ret < 0)
+		goto err;
+	ret = ethnl_put_bitset(rskb, ETHA_FEATURES_ACTIVE, compact,
+			       NETDEV_FEATURE_COUNT, new_active,
+			       active_diff_mask, feature_names);
+	if (ret < 0)
+		goto err;
+	nla_nest_end(rskb, feat_attr);
+
+	genlmsg_end(rskb, ehdr);
+	return genlmsg_reply(rskb, info);
+err:
+	WARN_ONCE(ret == -EMSGSIZE,
+		  "calculated message payload length (%d) not sufficient\n",
+		  reply_len);
+	nlmsg_free(rskb);
+	return ret;
+}
+
 int ethnl_set_settings(struct sk_buff *skb, struct genl_info *info)
 {
 	struct nlattr *tb[ETHA_SETTINGS_MAX + 1];
@@ -1092,6 +1208,17 @@ int ethnl_set_settings(struct sk_buff *skb, struct genl_info *info)
 			req_mask |= ETH_SETTINGS_IM_MSGLEVEL;
 		}
 	}
+	if (tb[ETHA_SETTINGS_FEATURES]) {
+		bool compact = tb[ETHA_SETTINGS_COMPACT];
+
+		ret = update_features(info, dev, tb[ETHA_SETTINGS_FEATURES],
+				      compact);
+		if (ret > 0) {
+			req_mask |= ETH_SETTINGS_IM_FEATURES;
+			ret = 0;
+		}
+
+	}
 	ret = 0;
 
 out_unlock:
-- 
2.18.0

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ