linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Michal Kubecek <mkubecek@suse.cz>
To: netdev@vger.kernel.org
Cc: linux-kernel@vger.kernel.org,
	"John W. Linville" <linville@tuxdriver.com>
Subject: [RFC PATCH ethtool v2 09/23] netlink: add netlink handler for sset (-s)
Date: Mon, 30 Jul 2018 14:56:29 +0200 (CEST)	[thread overview]
Message-ID: <9ba722afe5357ba9ab3eb11ceef318328b9b552d.1532954671.git.mkubecek@suse.cz> (raw)
In-Reply-To: <cover.1532954671.git.mkubecek@suse.cz>

Implement "ethtool -s <dev>" subcommand using netlink interface command
ETHNL_CMD_SET_SETTINGS.

Add specific parsers for wol modes and MAC address (used for wake-on-lan
password here).

Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
---
 ethtool.c          |   9 +-
 netlink/extapi.h   |   1 +
 netlink/netlink.c  |   9 ++
 netlink/netlink.h  |   1 +
 netlink/parser.c   |  34 ++++++-
 netlink/parser.h   |   4 +
 netlink/settings.c | 216 +++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 269 insertions(+), 5 deletions(-)

diff --git a/ethtool.c b/ethtool.c
index bc7969f829f6..0b40b96cf9bf 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -4923,6 +4923,7 @@ static int show_usage(struct cmd_context *ctx);
  */
 #define nl_gdrv		NULL
 #define nl_gset		NULL
+#define nl_sset		NULL
 #endif
 
 static const struct option {
@@ -4933,19 +4934,19 @@ static const struct option {
 	char *help;
 	char *opthelp;
 } args[] = {
-	{ "-s|--change", 1, do_sset, NULL,
+	{ "-s|--change", 1, do_sset, nl_sset,
 	  "Change generic options",
 	  "		[ speed %d ]\n"
 	  "		[ duplex half|full ]\n"
 	  "		[ port tp|aui|bnc|mii|fibre ]\n"
 	  "		[ mdix auto|on|off ]\n"
 	  "		[ autoneg on|off ]\n"
-	  "		[ advertise %x ]\n"
+	  "		[ advertise %x[/%x] | mode on|off ... [--] ]\n"
 	  "		[ phyad %d ]\n"
 	  "		[ xcvr internal|external ]\n"
-	  "		[ wol p|u|m|b|a|g|s|d... ]\n"
+	  "		[ wol %d[/%d] |  p|u|m|b|a|g|s|d...[/p|u|m|b|a|g|s|d...] ]\n"
 	  "		[ sopass %x:%x:%x:%x:%x:%x ]\n"
-	  "		[ msglvl %d | msglvl type on|off ... ]\n" },
+	  "		[ msglvl %d[/%d] | type on|off ... [--] ]\n" },
 	{ "-a|--show-pause", 1, do_gpause, NULL,
 	  "Show pause options" },
 	{ "-A|--pause", 1, do_spause, NULL,
diff --git a/netlink/extapi.h b/netlink/extapi.h
index 20c9b03b2d3c..66573f0b4304 100644
--- a/netlink/extapi.h
+++ b/netlink/extapi.h
@@ -15,6 +15,7 @@ int netlink_done(struct cmd_context *ctx);
 
 int nl_gdrv(struct cmd_context *ctx);
 int nl_gset(struct cmd_context *ctx);
+int nl_sset(struct cmd_context *ctx);
 int nl_monitor(struct cmd_context *ctx);
 
 void monitor_usage();
diff --git a/netlink/netlink.c b/netlink/netlink.c
index fc87577191f0..8b3dce970fd1 100644
--- a/netlink/netlink.c
+++ b/netlink/netlink.c
@@ -573,6 +573,15 @@ static int get_ethnl_family(struct nl_context *nlctx)
 	return (nlctx->ethnl_fam ? 0 : -EADDRNOTAVAIL);
 }
 
+int nomsg_reply_cb(const struct nlmsghdr *nlhdr, void *data)
+{
+	const struct genlmsghdr *ghdr = (const struct genlmsghdr *)(nlhdr + 1);
+
+	fprintf(stderr, "received unexpected message: len=%u type=%u cmd=%u\n",
+	       nlhdr->nlmsg_len, nlhdr->nlmsg_type, ghdr->cmd);
+	return MNL_CB_OK;
+}
+
 /* initialization */
 
 static int nlctx_init(struct nl_context *nlctx)
diff --git a/netlink/netlink.h b/netlink/netlink.h
index 32c2f9f33ba1..9c23526da627 100644
--- a/netlink/netlink.h
+++ b/netlink/netlink.h
@@ -72,6 +72,7 @@ int attr_cb(const struct nlattr *attr, void *data);
 int ethnl_prep_get_request(struct cmd_context *ctx, unsigned int nlcmd,
 			   uint16_t dev_attrtype);
 int ethnl_send_get_request(struct nl_context *nlctx, mnl_cb_t cb);
+int nomsg_reply_cb(const struct nlmsghdr *nlhdr, void *data);
 int __init_aux_nlctx(struct nl_context *nlctx);
 
 /* put data wrappers */
diff --git a/netlink/parser.c b/netlink/parser.c
index 589004d1f9f9..d1536ecb1d52 100644
--- a/netlink/parser.c
+++ b/netlink/parser.c
@@ -69,7 +69,7 @@ static int parse_x32(const char *arg, u32 *result)
 	return __parse_u32(arg, result, 0, 0xffffffff, 16);
 }
 
-static int parse_u32(const char *arg, u32 *result)
+int parse_u32(const char *arg, u32 *result)
 {
 	if (!arg)
 		return -EINVAL;
@@ -485,6 +485,38 @@ int nl_parse_bitset(struct nl_context *nlctx, uint16_t type, const void *data)
 		return nl_parse_bitset_list(nlctx, type, data);
 }
 
+int nl_parse_mac_addr(struct nl_context *nlctx, uint16_t type, const void *data)
+{
+	const char *arg = *nlctx->argp;
+	u8 val[ETH_ALEN];
+	unsigned int i;
+	const char *p;
+
+	nlctx->argp++;
+	nlctx->argc--;
+
+	p = arg;
+	i = 0;
+	while (i < ETH_ALEN && *p) {
+		char *endp;
+		unsigned long byte = strtoul(p, &endp, 16);
+
+		if ((endp - p > 2) || (*endp && *endp != ':'))
+			goto err;
+		val[i++] = (u8) byte;
+		p = endp + (*endp ? 1 : 0);
+	}
+	if (i < ETH_ALEN)
+		goto err;
+
+	return ethnla_put(nlctx, type, ETH_ALEN, val);
+
+err:
+	fprintf(stderr, "ethtool (%s): invalid value '%s' of parameter '%s'\n",
+		nlctx->cmd, arg, nlctx->param);
+	return -EINVAL;
+}
+
 int nl_parser(struct cmd_context *ctx, const struct param_parser *params,
 	      unsigned int max_type)
 {
diff --git a/netlink/parser.h b/netlink/parser.h
index 7308da25f093..2fd9a8bb23d9 100644
--- a/netlink/parser.h
+++ b/netlink/parser.h
@@ -28,6 +28,8 @@ struct param_parser {
 	unsigned int		min_argc;
 };
 
+int parse_u32(const char *arg, u32 *result);
+
 int nl_parse_direct_u32(struct nl_context *nlctx, uint16_t type,
 			const void *data);
 int nl_parse_direct_u8(struct nl_context *nlctx, uint16_t type,
@@ -38,6 +40,8 @@ int nl_parse_lookup_u8(struct nl_context *nlctx, uint16_t type,
 int nl_parse_bitfield32(struct nl_context *nlctx, uint16_t type,
 			const void *data);
 int nl_parse_bitset(struct nl_context *nlctx, uint16_t type, const void *data);
+int nl_parse_mac_addr(struct nl_context *nlctx, uint16_t type,
+		      const void *data);
 
 int nl_parser(struct cmd_context *ctx, const struct param_parser *params,
 	      unsigned int max_type);
diff --git a/netlink/settings.c b/netlink/settings.c
index 120fc95aad19..b077a96325e5 100644
--- a/netlink/settings.c
+++ b/netlink/settings.c
@@ -5,6 +5,7 @@
 #include "../internal.h"
 #include "../common.h"
 #include "netlink.h"
+#include "parser.h"
 
 /* GET_SETTINGS */
 
@@ -299,3 +300,218 @@ int nl_gset(struct cmd_context *ctx)
 }
 
 }
+
+/* SET_SETTINGS */
+
+enum {
+	WAKE_PHY_BIT		= 0,
+	WAKE_UCAST_BIT		= 1,
+	WAKE_MCAST_BIT		= 2,
+	WAKE_BCAST_BIT		= 3,
+	WAKE_ARP_BIT		= 4,
+	WAKE_MAGIC_BIT		= 5,
+	WAKE_MAGICSECURE_BIT	= 6,
+};
+
+#define WAKE_ALL (WAKE_PHY | WAKE_UCAST | WAKE_MCAST | WAKE_BCAST | WAKE_ARP | \
+		  WAKE_MAGIC | WAKE_MAGICSECURE)
+
+char wol_modes[32] = {
+	[WAKE_PHY_BIT]		= 'p',
+	[WAKE_UCAST_BIT]	= 'u',
+	[WAKE_MCAST_BIT]	= 'm',
+	[WAKE_BCAST_BIT]	= 'b',
+	[WAKE_ARP_BIT]		= 'a',
+	[WAKE_MAGIC_BIT]	= 'g',
+	[WAKE_MAGICSECURE_BIT]	= 's',
+};
+
+static int __nl_parse_wol_modes(struct nl_context *nlctx, const char *str,
+				u32 *result)
+{
+	unsigned int i;
+	const char *p;
+	int ret;
+
+	ret = parse_u32(str, result);
+	if (ret == 0)
+		return 0;
+
+	*result = 0;
+	if (str[0] == 'd' && !str[1])
+		return 0;
+
+	p = str;
+	while (*p) {
+		for (i = 0; i < 32; i++) {
+			if (wol_modes[i] == *p) {
+				*result |= (1U << i);
+				break;
+			}
+		}
+		if (i == 32) {
+			fprintf(stderr,
+				"ethtool (%s): invalid wol modes '%s'\n",
+				nlctx->cmd, str);
+			return -EINVAL;
+		}
+		p++;
+	}
+
+	return 0;
+}
+
+static int nl_parse_wol_modes(struct nl_context *nlctx, uint16_t type,
+			      const void *data)
+{
+	const char *arg = *nlctx->argp;
+	char *mask = strchr(arg, '/');
+	u32 value, selector;
+	int ret;
+
+	nlctx->argp++;
+	nlctx->argc--;
+	if (mask) {
+		*mask = '\0';
+		mask++;
+	}
+
+	ret = __nl_parse_wol_modes(nlctx, arg, &value);
+	if (ret < 0)
+		return ret;
+
+	if (!mask) {
+		selector = ~(u32)0;
+	} else {
+		ret = __nl_parse_wol_modes(nlctx, mask, &selector);
+		if (ret < 0)
+			return ret;
+	}
+
+	return ethnla_put_bitfield32(nlctx, type, value, selector);
+}
+
+static const struct lookup_entry_u32 duplex_values[] = {
+	{ .arg = "half",	.val = DUPLEX_HALF },
+	{ .arg = "full",	.val = DUPLEX_FULL },
+	{}
+};
+
+static const struct lookup_entry_u8 port_values[] = {
+	{ .arg = "tp",		.val = PORT_TP },
+	{ .arg = "aui",		.val = PORT_AUI },
+	{ .arg = "bnc",		.val = PORT_BNC },
+	{ .arg = "mii",		.val = PORT_MII },
+	{ .arg = "fibre",	.val = PORT_FIBRE },
+	{}
+};
+
+static const struct lookup_entry_u8 mdix_values[] = {
+	{ .arg = "auto",	.val = ETH_TP_MDI_AUTO },
+	{ .arg = "on",		.val = ETH_TP_MDI_X },
+	{ .arg = "off",		.val = ETH_TP_MDI },
+	{}
+};
+
+static const struct lookup_entry_u8 autoneg_values[] = {
+	{ .arg = "off",		.val = AUTONEG_DISABLE },
+	{ .arg = "on",		.val = AUTONEG_ENABLE },
+	{}
+};
+
+static const struct param_parser sset_params[] = {
+	{
+		.arg		= "speed",
+		.type		= ETHA_SETTINGS_SPEED,
+		.handler	= nl_parse_direct_u32,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "duplex",
+		.type		= ETHA_SETTINGS_DUPLEX,
+		.handler	= nl_parse_lookup_u8,
+		.handler_data	= duplex_values,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "port",
+		.type		= ETHA_SETTINGS_PORT,
+		.handler	= nl_parse_lookup_u8,
+		.handler_data	= port_values,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "mdix",
+		.type		= ETHA_SETTINGS_TP_MDIX_CTRL,
+		.handler	= nl_parse_lookup_u8,
+		.handler_data	= mdix_values,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "autoneg",
+		.type		= ETHA_SETTINGS_AUTONEG,
+		.handler	= nl_parse_lookup_u8,
+		.handler_data	= autoneg_values,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "advertise",
+		.type		= ETHA_SETTINGS_LINK_MODES,
+		.handler	= nl_parse_bitset,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "phyad",
+		.type		= ETHA_SETTINGS_PHYADDR,
+		.handler	= nl_parse_direct_u8,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "wol",
+		.type		= ETHA_SETTINGS_WOL_MODES,
+		.handler	= nl_parse_wol_modes,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "sopass",
+		.type		= ETHA_SETTINGS_SOPASS,
+		.handler	= nl_parse_mac_addr,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "msglvl",
+		.type		= ETHA_SETTINGS_MSGLVL,
+		.handler	= nl_parse_bitfield32,
+		.handler_data	= flags_msglvl,
+		.min_argc	= 1,
+	},
+	{}
+};
+
+int nl_sset(struct cmd_context *ctx)
+{
+	struct nl_context *nlctx = ctx->nlctx;
+	int ret;
+
+	nlctx->cmd = "-s";
+	nlctx->argp = ctx->argp;
+	nlctx->argc = ctx->argc;
+	ret = msg_init(nlctx, ETHNL_CMD_SET_SETTINGS,
+		       NLM_F_REQUEST | NLM_F_ACK);
+	if (ret < 0)
+		return 2;
+	if (ethnla_put_dev(nlctx, ETHA_SETTINGS_DEV, ctx->devname))
+		return -EMSGSIZE;
+
+	ret = nl_parser(ctx, sset_params, ETHA_SETTINGS_MAX);
+	if (ret < 0)
+		return 2;
+
+	ret = ethnl_sendmsg(nlctx);
+	if (ret < 0)
+		return 75;
+	ret = ethnl_process_reply(nlctx, nomsg_reply_cb);
+	if (ret == 0)
+		return 0;
+	return nlctx->exit_code ?: 75;
+}
-- 
2.18.0


  parent reply	other threads:[~2018-07-30 12:56 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-07-30 12:55 [RFC PATCH ethtool v2 00/23] ethtool netlink interface (userspace side) (WiP) Michal Kubecek
2018-07-30 12:55 ` [RFC PATCH ethtool v2 01/23] move UAPI header copies to a separate directory Michal Kubecek
2018-07-30 12:55 ` [RFC PATCH ethtool v2 02/23] update UAPI header copies Michal Kubecek
2018-07-30 12:55 ` [RFC PATCH ethtool v2 03/23] netlink: add netlink interface Michal Kubecek
2018-07-30 12:56 ` [RFC PATCH ethtool v2 04/23] netlink: add support for string sets Michal Kubecek
2018-07-30 12:56 ` [RFC PATCH ethtool v2 05/23] netlink: add notification monitor Michal Kubecek
2018-07-30 12:56 ` [RFC PATCH ethtool v2 06/23] netlink: add netlink handler for gdrv (-i) Michal Kubecek
2018-07-30 12:56 ` [RFC PATCH ethtool v2 07/23] netlink: add netlink handler for gset (no option) Michal Kubecek
2018-07-30 12:56 ` [RFC PATCH ethtool v2 08/23] netlink: add helpers for command line parsing Michal Kubecek
2018-07-30 12:56 ` Michal Kubecek [this message]
2018-07-30 12:56 ` [RFC PATCH ethtool v2 10/23] netlink: add netlink handler for gfeatures (-k) Michal Kubecek
2018-07-30 12:56 ` [RFC PATCH ethtool v2 11/23] netlink: add netlink handler for sfeatures (-K) Michal Kubecek
2018-07-30 12:56 ` [RFC PATCH ethtool v2 12/23] netlink: add netlink handler for gcoalesce (-c) Michal Kubecek
2018-07-30 12:56 ` [RFC PATCH ethtool v2 13/23] netlink: add netlink handler for gring (-g) Michal Kubecek
2018-07-30 12:56 ` [RFC PATCH ethtool v2 14/23] netlink: add netlink handler for gpause (-a) Michal Kubecek
2018-07-30 12:56 ` [RFC PATCH ethtool v2 15/23] netlink: add netlink handler for gchannels (-l) Michal Kubecek
2018-07-30 12:57 ` [RFC PATCH ethtool v2 16/23] netlink: add netlink handler for geee (--show-eee) Michal Kubecek
2018-07-30 12:57 ` [RFC PATCH ethtool v2 17/23] netlink: add netlink handler for gfec (--show-fec) Michal Kubecek
2018-07-30 12:57 ` [RFC PATCH ethtool v2 18/23] netlink: add netlink handler for scoalesce (-C) Michal Kubecek
2018-07-30 12:57 ` [RFC PATCH ethtool v2 19/23] netlink: add netlink handler for sring (-G) Michal Kubecek
2018-07-30 12:57 ` [RFC PATCH ethtool v2 20/23] netlink: add netlink handler for spause (-A) Michal Kubecek
2018-07-30 12:57 ` [RFC PATCH ethtool v2 21/23] netlink: add netlink handler for schannels (-L) Michal Kubecek
2018-07-30 12:57 ` [RFC PATCH ethtool v2 22/23] netlink: add netlink handler for seee (--set-eee) Michal Kubecek
2018-07-30 12:57 ` [RFC PATCH ethtool v2 23/23] netlink: add netlink handler for sfec (--set-fec) Michal Kubecek

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=9ba722afe5357ba9ab3eb11ceef318328b9b552d.1532954671.git.mkubecek@suse.cz \
    --to=mkubecek@suse.cz \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linville@tuxdriver.com \
    --cc=netdev@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).