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, 11 Dec 2017 14:54:01 +0100 (CET)
From:   Michal Kubecek <mkubecek@...e.cz>
To:     netdev@...r.kernel.org
Cc:     linux-kernel@...r.kernel.org
Subject: [RFC PATCH 5/9] ethtool: implement GET_DRVINFO message

Request the same information as ETHTOOL_GDRVINFO. This is read-only so that
corresponding SET_DRVINFO exists but is only used in kernel replies. Rip
the code to query the driver out of the legacy interface and move it to
a new file ethtool_common.c so that both interfaces can use it.

Signed-off-by: Michal Kubecek <mkubecek@...e.cz>
---
 Documentation/networking/ethtool-netlink.txt | 30 ++++++++++-
 include/uapi/linux/ethtool_netlink.h         | 21 ++++++++
 net/core/Makefile                            |  2 +-
 net/core/ethtool.c                           | 42 +++-------------
 net/core/ethtool_common.c                    | 46 +++++++++++++++++
 net/core/ethtool_common.h                    | 11 ++++
 net/core/ethtool_netlink.c                   | 75 ++++++++++++++++++++++++++++
 7 files changed, 189 insertions(+), 38 deletions(-)
 create mode 100644 net/core/ethtool_common.c
 create mode 100644 net/core/ethtool_common.h

diff --git a/Documentation/networking/ethtool-netlink.txt b/Documentation/networking/ethtool-netlink.txt
index 893e5156f6a7..cb992180b211 100644
--- a/Documentation/networking/ethtool-netlink.txt
+++ b/Documentation/networking/ethtool-netlink.txt
@@ -107,6 +107,9 @@ which the request applies.
 List of message types
 ---------------------
 
+    ETHTOOL_CMD_GET_DRVINFO
+    ETHTOOL_CMD_SET_DRVINFO		response only
+
 All constants use ETHTOOL_CMD_ prefix followed by "GET", "SET" or "ACT" to
 indicate the type.
 
@@ -119,6 +122,31 @@ messages marked as "response only" in the table above.
 Later sections describe the format and semantics of these request messages.
 
 
+GET_DRVINFO
+-----------
+
+GET_DRVINFO request corresponds to ETHTOOL_GDRVINFO ioctl command and provides
+basic driver information. The request doesn't use any attributes and flags,
+info_mask and index field in request header are ignored. Kernel response
+contents:
+
+    ETHA_DRVINFO_DRIVER		(string)	driver name
+    ETHA_DRVINFO_VERSION	(string)	driver version
+    ETHA_DRVINFO_FWVERSION	(string)	firmware version
+    ETHA_DRVINFO_BUSINFO	(string)	device bus address
+    ETHA_DRVINFO_EROM_VER	(string)	expansion ROM version
+    ETHA_DRVINFO_N_PRIV_FLAGS	(u32)		number of private flags
+    ETHA_DRVINFO_N_STATS	(u32)		number of device stats
+    ETHA_DRVINFO_TESTINFO_LEN	(u32)		number of test results
+    ETHA_DRVINFO_EEDUMP_LEN	(u32)		EEPROM dump size
+    ETHA_DRVINFO_REGDUMP_LEN	(u32)		register dump size
+
+The meaning of these follows the corresponding fields of ETHTOOL_GDRVINFO
+response.
+
+All information is read only, SET_DRVINFO request is not implemented.
+
+
 Request translation
 -------------------
 
@@ -130,7 +158,7 @@ ioctl command			netlink command
 ---------------------------------------------------------------------
 ETHTOOL_GSET			n/a
 ETHTOOL_SSET			n/a
-ETHTOOL_GDRVINFO		n/a
+ETHTOOL_GDRVINFO		ETHTOOL_CMD_GET_DRVINFO
 ETHTOOL_GREGS			n/a
 ETHTOOL_GWOL			n/a
 ETHTOOL_SWOL			n/a
diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h
index 6db35f00ea32..d6ab1d73d494 100644
--- a/include/uapi/linux/ethtool_netlink.h
+++ b/include/uapi/linux/ethtool_netlink.h
@@ -21,6 +21,8 @@ struct ethnlmsghdr {
 
 enum {
 	ETHTOOL_CMD_NOOP,
+	ETHTOOL_CMD_GET_DRVINFO,
+	ETHTOOL_CMD_SET_DRVINFO,	/* only for reply */
 
 	__ETHTOOL_CMD_MAX,
 	ETHTOOL_CMD_MAX = (__ETHTOOL_CMD_MAX - 1),
@@ -57,6 +59,25 @@ enum {
 	ETHA_BITSET_MAX = (__ETHA_BITSET_MAX - 1),
 };
 
+/* GET_DRVINFO / SET_DRVINFO */
+
+enum {
+	ETHA_DRVINFO_UNSPEC,
+	ETHA_DRVINFO_DRIVER,			/* string */
+	ETHA_DRVINFO_VERSION,			/* string */
+	ETHA_DRVINFO_FWVERSION,			/* string */
+	ETHA_DRVINFO_BUSINFO,			/* string */
+	ETHA_DRVINFO_EROM_VER,			/* string */
+	ETHA_DRVINFO_N_PRIV_FLAGS,		/* u32 */
+	ETHA_DRVINFO_N_STATS,			/* u32 */
+	ETHA_DRVINFO_TESTINFO_LEN,		/* u32 */
+	ETHA_DRVINFO_EEDUMP_LEN,		/* u32 */
+	ETHA_DRVINFO_REGDUMP_LEN,		/* u32 */
+
+	__ETHA_DRVINFO_MAX,
+	ETHA_DRVINFO_MAX = (__ETHA_DRVINFO_MAX - 1),
+};
+
 /* generic netlink info */
 #define ETHTOOL_GENL_NAME "ethtool"
 #define ETHTOOL_GENL_VERSION 1
diff --git a/net/core/Makefile b/net/core/Makefile
index 617ab2abecdf..3196641c0e70 100644
--- a/net/core/Makefile
+++ b/net/core/Makefile
@@ -11,7 +11,7 @@ obj-$(CONFIG_SYSCTL) += sysctl_net_core.o
 obj-y		     += dev.o ethtool.o dev_addr_lists.o dst.o netevent.o \
 			neighbour.o rtnetlink.o utils.o link_watch.o filter.o \
 			sock_diag.o dev_ioctl.o tso.o sock_reuseport.o \
-			fib_notifier.o
+			fib_notifier.o ethtool_common.o
 
 obj-y += net-sysfs.o
 obj-$(CONFIG_PROC_FS) += net-procfs.o
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index f8fcf450a36e..09e780a748f9 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -26,6 +26,7 @@
 #include <linux/rtnetlink.h>
 #include <linux/sched/signal.h>
 #include <linux/net.h>
+#include "ethtool_common.h"
 
 /*
  * Some useful ethtool_ops methods that're device independent.
@@ -885,45 +886,14 @@ static noinline_for_stack int ethtool_get_drvinfo(struct net_device *dev,
 						  void __user *useraddr)
 {
 	struct ethtool_drvinfo info;
-	const struct ethtool_ops *ops = dev->ethtool_ops;
-
-	memset(&info, 0, sizeof(info));
-	info.cmd = ETHTOOL_GDRVINFO;
-	if (ops->get_drvinfo) {
-		ops->get_drvinfo(dev, &info);
-	} else if (dev->dev.parent && dev->dev.parent->driver) {
-		strlcpy(info.bus_info, dev_name(dev->dev.parent),
-			sizeof(info.bus_info));
-		strlcpy(info.driver, dev->dev.parent->driver->name,
-			sizeof(info.driver));
-	} else {
-		return -EOPNOTSUPP;
-	}
-
-	/*
-	 * this method of obtaining string set info is deprecated;
-	 * Use ETHTOOL_GSSET_INFO instead.
-	 */
-	if (ops->get_sset_count) {
-		int rc;
-
-		rc = ops->get_sset_count(dev, ETH_SS_TEST);
-		if (rc >= 0)
-			info.testinfo_len = rc;
-		rc = ops->get_sset_count(dev, ETH_SS_STATS);
-		if (rc >= 0)
-			info.n_stats = rc;
-		rc = ops->get_sset_count(dev, ETH_SS_PRIV_FLAGS);
-		if (rc >= 0)
-			info.n_priv_flags = rc;
-	}
-	if (ops->get_regs_len)
-		info.regdump_len = ops->get_regs_len(dev);
-	if (ops->get_eeprom_len)
-		info.eedump_len = ops->get_eeprom_len(dev);
+	int rc;
 
+	rc = __ethtool_get_drvinfo(dev, &info);
+	if (rc < 0)
+		return rc;
 	if (copy_to_user(useraddr, &info, sizeof(info)))
 		return -EFAULT;
+
 	return 0;
 }
 
diff --git a/net/core/ethtool_common.c b/net/core/ethtool_common.c
new file mode 100644
index 000000000000..2c0abab0e43c
--- /dev/null
+++ b/net/core/ethtool_common.c
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+
+#include <linux/rtnetlink.h>
+#include "ethtool_common.h"
+
+int __ethtool_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+	const struct ethtool_ops *ops = dev->ethtool_ops;
+
+	memset(info, 0, sizeof(*info));
+	info->cmd = ETHTOOL_GDRVINFO;
+	if (ops->get_drvinfo) {
+		ops->get_drvinfo(dev, info);
+	} else if (dev->dev.parent && dev->dev.parent->driver) {
+		strlcpy(info->bus_info, dev_name(dev->dev.parent),
+			sizeof(info->bus_info));
+		strlcpy(info->driver, dev->dev.parent->driver->name,
+			sizeof(info->driver));
+	} else {
+		return -EOPNOTSUPP;
+	}
+
+	/* this method of obtaining string set info is deprecated;
+	 * Use ETHTOOL_GSSET_INFO instead.
+	 */
+	if (ops->get_sset_count) {
+		int rc;
+
+		rc = ops->get_sset_count(dev, ETH_SS_TEST);
+		if (rc >= 0)
+			info->testinfo_len = rc;
+		rc = ops->get_sset_count(dev, ETH_SS_STATS);
+		if (rc >= 0)
+			info->n_stats = rc;
+		rc = ops->get_sset_count(dev, ETH_SS_PRIV_FLAGS);
+		if (rc >= 0)
+			info->n_priv_flags = rc;
+	}
+	if (ops->get_regs_len)
+		info->regdump_len = ops->get_regs_len(dev);
+	if (ops->get_eeprom_len)
+		info->eedump_len = ops->get_eeprom_len(dev);
+
+	return 0;
+}
+EXPORT_SYMBOL(__ethtool_get_drvinfo);
diff --git a/net/core/ethtool_common.h b/net/core/ethtool_common.h
new file mode 100644
index 000000000000..1f031c1d943a
--- /dev/null
+++ b/net/core/ethtool_common.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+
+#ifndef _ETHTOOL_COMMON_H
+#define _ETHTOOL_COMMON_H
+
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+
+int __ethtool_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info);
+
+#endif /* _ETHTOOL_COMMON_H */
diff --git a/net/core/ethtool_netlink.c b/net/core/ethtool_netlink.c
index 9f287e67f30b..077814fd36bd 100644
--- a/net/core/ethtool_netlink.c
+++ b/net/core/ethtool_netlink.c
@@ -531,9 +531,84 @@ static struct sk_buff *ethnl_reply_init(size_t payload, struct net_device *dev,
 	return rskb;
 }
 
+/* GET_DRVINFO */
+
+static int ethnl_drvinfo_size(struct ethtool_drvinfo *drvinfo)
+{
+	int len = 0;
+
+	len += ethnl_str_ifne_size(drvinfo->driver);
+	len += ethnl_str_ifne_size(drvinfo->version);
+	len += ethnl_str_ifne_size(drvinfo->fw_version);
+	len += ethnl_str_ifne_size(drvinfo->bus_info);
+	len += ethnl_str_ifne_size(drvinfo->erom_version);
+	/* n_priv_flags, n_stats, testinfo_len, eedump_len, regdump_len */
+	len += 5 * nla_total_size(sizeof(u32));
+
+	return len;
+}
+
+static int ethnl_get_drvinfo(struct sk_buff *skb, struct genl_info *info)
+{
+	struct ethnlmsghdr *ehdr;
+	struct ethtool_drvinfo drvinfo = {};
+	struct net_device *dev;
+	struct sk_buff *rskb;
+	int reply_len;
+	int rc = 0;
+
+	dev = ethnl_dev_get(info);
+	if (IS_ERR(dev))
+		return PTR_ERR(dev);
+	rc = __ethtool_get_drvinfo(dev, &drvinfo);
+	if (rc < 0) {
+		dev_put(dev);
+		GENL_SET_ERR_MSG(info,
+				 "failed to retrieve driver info from driver");
+		return rc;
+	}
+
+	reply_len = ethnl_drvinfo_size(&drvinfo);
+	rskb = ethnl_reply_init(reply_len, dev, ETHTOOL_CMD_SET_DRVINFO, info,
+				&ehdr);
+	dev_put(dev);
+	if (!rskb)
+		return -ENOMEM;
+
+	if (ethnl_put_str_ifne(rskb, ETHA_DRVINFO_DRIVER, drvinfo.driver) ||
+	    ethnl_put_str_ifne(rskb, ETHA_DRVINFO_VERSION, drvinfo.version) ||
+	    ethnl_put_str_ifne(rskb, ETHA_DRVINFO_FWVERSION,
+			       drvinfo.fw_version) ||
+	    ethnl_put_str_ifne(rskb, ETHA_DRVINFO_BUSINFO, drvinfo.bus_info) ||
+	    ethnl_put_str_ifne(rskb, ETHA_DRVINFO_EROM_VER,
+			       drvinfo.erom_version) ||
+	    nla_put_u32(rskb, ETHA_DRVINFO_N_PRIV_FLAGS,
+			drvinfo.n_priv_flags) ||
+	    nla_put_u32(rskb, ETHA_DRVINFO_N_STATS, drvinfo.n_stats) ||
+	    nla_put_u32(rskb, ETHA_DRVINFO_TESTINFO_LEN,
+			drvinfo.testinfo_len) ||
+	    nla_put_u32(rskb, ETHA_DRVINFO_EEDUMP_LEN, drvinfo.eedump_len) ||
+	    nla_put_u32(rskb, ETHA_DRVINFO_REGDUMP_LEN, drvinfo.regdump_len))
+		goto err;
+
+	genlmsg_end(rskb, ehdr);
+	return genlmsg_reply(rskb, info);
+
+err:
+	nlmsg_free(rskb);
+	GENL_SET_ERR_MSG(info, "kernel error, see kernel log for details");
+	WARN_ONCE(1, "calculated message payload length (%d) not sufficient\n",
+		  reply_len);
+	return -EMSGSIZE;
+}
+
 /* genetlink paperwork */
 
 static const struct genl_ops ethtool_genl_ops[] = {
+	{
+		.cmd	= ETHTOOL_CMD_GET_DRVINFO,
+		.doit	= ethnl_get_drvinfo,
+	},
 };
 
 static struct genl_family ethtool_genl_family = {
-- 
2.15.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ