diff mbox series

[ethtool,2/2] wol: Add support for WAKE_MDA

Message ID 20231011221242.4180589-5-florian.fainelli@broadcom.com (mailing list archive)
State Changes Requested, archived
Delegated to: Michal Kubecek
Headers show
Series None | expand

Commit Message

Florian Fainelli Oct. 11, 2023, 10:12 p.m. UTC
Allow waking-up from a specific MAC destination address, this is
particularly useful with a number of Ethernet PHYs that have limited
buffering and packet matching abilities.

Example:

ethtool -s eth0 wol e mac-da 01:00:5e:00:00:fb

Signed-off-by: Florian Fainelli <florian.fainelli@broadcom.com>
---
 common.c               | 16 ++++++++++++++--
 ethtool.8.in           | 15 +++++++++++----
 ethtool.c              | 26 +++++++++++++++++++++-----
 netlink/desc-ethtool.c |  1 +
 netlink/settings.c     | 25 ++++++++++++++++++++++---
 test-cmdline.c         |  4 ++++
 6 files changed, 73 insertions(+), 14 deletions(-)
diff mbox series

Patch

diff --git a/common.c b/common.c
index b8fd4d5bc0f4..a42d00fe3c0c 100644
--- a/common.c
+++ b/common.c
@@ -120,6 +120,8 @@  static char *unparse_wolopts(int wolopts)
 			*p++ = 's';
 		if (wolopts & WAKE_FILTER)
 			*p++ = 'f';
+		if (wolopts & WAKE_MDA)
+			*p++ = 'e';
 	} else {
 		*p = 'd';
 	}
@@ -129,13 +131,13 @@  static char *unparse_wolopts(int wolopts)
 
 int dump_wol(struct ethtool_wolinfo *wol)
 {
+	int i;
+	int delim = 0;
 	fprintf(stdout, "	Supports Wake-on: %s\n",
 		unparse_wolopts(wol->supported));
 	fprintf(stdout, "	Wake-on: %s\n",
 		unparse_wolopts(wol->wolopts));
 	if (wol->supported & WAKE_MAGICSECURE) {
-		int i;
-		int delim = 0;
 
 		fprintf(stdout, "        SecureOn password: ");
 		for (i = 0; i < SOPASS_MAX; i++) {
@@ -145,6 +147,16 @@  int dump_wol(struct ethtool_wolinfo *wol)
 		}
 		fprintf(stdout, "\n");
 	}
+	delim = 0;
+	if (wol->supported & WAKE_MDA) {
+		fprintf(stdout, "        Destination MAC: ");
+		for (i = 0; i < ETH_ALEN; i++) {
+			fprintf(stdout, "%s%02x", delim ? ":" : "",
+				wol->mac_da[i]);
+			delim = 1;
+		}
+		fprintf(stdout, "\n");
+	}
 
 	return 0;
 }
diff --git a/ethtool.8.in b/ethtool.8.in
index c0c37a427715..c7f457b9b739 100644
--- a/ethtool.8.in
+++ b/ethtool.8.in
@@ -62,7 +62,7 @@ 
 .\"
 .\"	\(*WO - wol flags
 .\"
-.ds WO \fBp\fP|\fBu\fP|\fBm\fP|\fBb\fP|\fBa\fP|\fBg\fP|\fBs\fP|\fBf|\fBd\fP...
+.ds WO \fBp\fP|\fBu\fP|\fBm\fP|\fBb\fP|\fBa\fP|\fBg\fP|\fBs\fP|\fBf|\fBe|\fBd\fP...
 .\"
 .\"	\(*FL - flow type values
 .\"
@@ -281,7 +281,7 @@  ethtool \- query or control network driver and hardware settings
 .B2 xcvr internal external
 .RB [ wol \ \fIN\fP[\fB/\fP\fIM\fP]
 .RB | \ wol \ \*(WO]
-.RB [ sopass \ \*(MA]
+.RB [ sopass \ \*(MA | mac-da \ \*(MA ]
 .RB [ master-slave \ \*(MS]
 .RB [ msglvl
 .IR N\fP[/\fIM\fP] \ |
@@ -949,14 +949,21 @@  a	Wake on ARP
 g	Wake on MagicPacket\[tm]
 s	Enable SecureOn\[tm] password for MagicPacket\[tm]
 f	Wake on filter(s)
+e	Wake on specific MAC destination address
 d	T{
 Disable (wake on nothing).  This option clears all previous options.
 T}
 .TE
 .TP
 .B sopass \*(MA
-Sets the SecureOn\[tm] password.  The argument to this option must be 6
-bytes in Ethernet MAC hex format (\*(MA).
+Sets the secureon\[tm] password.  The argument to this option must be 6
+bytes in ethernet mac hex format (\*(MA).
+.PP
+.TE
+.TP
+.B mac-da \*(MA
+Sets the destination MAC address to match against.  The argument to this option
+must be 6 bytes in ethernet mac hex format (\*(MA).
 .PP
 .BI msglvl \ N
 .br
diff --git a/ethtool.c b/ethtool.c
index af51220b63cc..513b4ed11623 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -973,6 +973,9 @@  static int parse_wolopts(char *optstr, u32 *data)
 		case 'f':
 			*data |= WAKE_FILTER;
 			break;
+		case 'e':
+			*data |= WAKE_MDA;
+			break;
 		case 'd':
 			*data = 0;
 			break;
@@ -2971,8 +2974,8 @@  static int do_sset(struct cmd_context *ctx)
 	int gset_changed = 0; /* did anything in GSET change? */
 	u32 wol_wanted = 0;
 	int wol_change = 0;
-	u8 sopass_wanted[SOPASS_MAX];
-	int sopass_change = 0;
+	u8 sopass_wanted[SOPASS_MAX], mda_wanted[ETH_ALEN];
+	int sopass_change = 0, mda_change = 0;
 	int gwol_changed = 0; /* did anything in GWOL change? */
 	int msglvl_changed = 0;
 	u32 msglvl_wanted = 0;
@@ -3093,6 +3096,13 @@  static int do_sset(struct cmd_context *ctx)
 				exit_bad_args();
 			get_mac_addr(argp[i], sopass_wanted);
 			sopass_change = 1;
+		} else if (!strcmp(argp[i], "mac-da")) {
+			gwol_changed = 1;
+			i++;
+			if (i >= argc)
+				exit_bad_args();
+			get_mac_addr(argp[i], mda_wanted);
+			mda_change = 1;
 		} else if (!strcmp(argp[i], "msglvl")) {
 			i++;
 			if (i >= argc)
@@ -3295,14 +3305,18 @@  static int do_sset(struct cmd_context *ctx)
 		if (err < 0) {
 			perror("Cannot get current wake-on-lan settings");
 		} else {
+			int i;
 			/* Change everything the user specified. */
 			if (wol_change)
 				wol.wolopts = wol_wanted;
 			if (sopass_change) {
-				int i;
 				for (i = 0; i < SOPASS_MAX; i++)
 					wol.sopass[i] = sopass_wanted[i];
 			}
+			if (mda_change) {
+				for (i = 0; i < ETH_ALEN; i++)
+					wol.mac_da[i] = mda_wanted[i];
+			}
 
 			/* Try to perform the update. */
 			wol.cmd = ETHTOOL_SWOL;
@@ -3315,6 +3329,8 @@  static int do_sset(struct cmd_context *ctx)
 				fprintf(stderr, "  not setting wol\n");
 			if (sopass_change)
 				fprintf(stderr, "  not setting sopass\n");
+			if (mda_change)
+				fprintf(stderr, "  not setting mac-da\n");
 		}
 	}
 
@@ -5669,8 +5685,8 @@  static const struct option args[] = {
 			  "		[ advertise %x[/%x] | mode on|off ... [--] ]\n"
 			  "		[ phyad %d ]\n"
 			  "		[ xcvr internal|external ]\n"
-			  "		[ wol %d[/%d] | p|u|m|b|a|g|s|f|d... ]\n"
-			  "		[ sopass %x:%x:%x:%x:%x:%x ]\n"
+			  "		[ wol %d[/%d] | p|u|m|b|a|g|s|f|e|d... ]\n"
+			  "		[ sopass %x:%x:%x:%x:%x:%x | mac-da %x:%x:%x:%x:%x:%x ]\n"
 			  "		[ msglvl %d[/%d] | type on|off ... [--] ]\n"
 			  "		[ master-slave preferred-master|preferred-slave|forced-master|forced-slave ]\n"
 	},
diff --git a/netlink/desc-ethtool.c b/netlink/desc-ethtool.c
index 661de267262f..78732bc2719c 100644
--- a/netlink/desc-ethtool.c
+++ b/netlink/desc-ethtool.c
@@ -120,6 +120,7 @@  static const struct pretty_nla_desc __wol_desc[] = {
 	NLATTR_DESC_NESTED(ETHTOOL_A_WOL_HEADER, header),
 	NLATTR_DESC_NESTED(ETHTOOL_A_WOL_MODES, bitset),
 	NLATTR_DESC_BINARY(ETHTOOL_A_WOL_SOPASS),
+	NLATTR_DESC_BINARY(ETHTOOL_A_WOL_MAC_DA),
 };
 
 static const struct pretty_nla_desc __features_desc[] = {
diff --git a/netlink/settings.c b/netlink/settings.c
index a506618ba0a4..a13251863af1 100644
--- a/netlink/settings.c
+++ b/netlink/settings.c
@@ -810,6 +810,7 @@  int wol_reply_cb(const struct nlmsghdr *nlhdr, void *data)
 	DECLARE_ATTR_TB_INFO(tb);
 	struct nl_context *nlctx = data;
 	struct ethtool_wolinfo wol = {};
+	unsigned int len;
 	int ret;
 
 	if (nlctx->is_dump || nlctx->is_monitor)
@@ -824,8 +825,6 @@  int wol_reply_cb(const struct nlmsghdr *nlhdr, void *data)
 	if (tb[ETHTOOL_A_WOL_MODES])
 		walk_bitset(tb[ETHTOOL_A_WOL_MODES], NULL, wol_modes_cb, &wol);
 	if (tb[ETHTOOL_A_WOL_SOPASS]) {
-		unsigned int len;
-
 		len = mnl_attr_get_payload_len(tb[ETHTOOL_A_WOL_SOPASS]);
 		if (len != SOPASS_MAX)
 			fprintf(stderr, "invalid SecureOn password length %u (should be %u)\n",
@@ -835,6 +834,16 @@  int wol_reply_cb(const struct nlmsghdr *nlhdr, void *data)
 			       mnl_attr_get_payload(tb[ETHTOOL_A_WOL_SOPASS]),
 			       SOPASS_MAX);
 	}
+	if (tb[ETHTOOL_A_WOL_MAC_DA]) {
+		len = mnl_attr_get_payload_len(tb[ETHTOOL_A_WOL_SOPASS]);
+		if (len != ETH_ALEN)
+			fprintf(stderr, "invalid destinatino MAC address length %u (should be %u)\n",
+				len, ETH_ALEN);
+		else
+			memcpy(wol.mac_da,
+			       mnl_attr_get_payload(tb[ETHTOOL_A_WOL_MAC_DA]),
+			       ETH_ALEN);
+	}
 	print_banner(nlctx);
 	dump_wol(&wol);
 
@@ -1050,10 +1059,11 @@  enum {
 	WAKE_MAGIC_BIT		= 5,
 	WAKE_MAGICSECURE_BIT	= 6,
 	WAKE_FILTER_BIT		= 7,
+	WAKE_MDA_BIT		= 8,
 };
 
 #define WAKE_ALL (WAKE_PHY | WAKE_UCAST | WAKE_MCAST | WAKE_BCAST | WAKE_ARP | \
-		  WAKE_MAGIC | WAKE_MAGICSECURE)
+		  WAKE_MAGIC | WAKE_MAGICSECURE | WAKE_MDA)
 
 static const struct lookup_entry_u8 port_values[] = {
 	{ .arg = "tp",		.val = PORT_TP },
@@ -1112,6 +1122,7 @@  char wol_bit_chars[WOL_MODE_COUNT] = {
 	[WAKE_MAGIC_BIT]	= 'g',
 	[WAKE_MAGICSECURE_BIT]	= 's',
 	[WAKE_FILTER_BIT]	= 'f',
+	[WAKE_MDA_BIT]		= 'e',
 };
 
 const struct char_bitset_parser_data wol_parser_data = {
@@ -1224,6 +1235,14 @@  static const struct param_parser sset_params[] = {
 		.handler_data	= &sopass_parser_data,
 		.min_argc	= 1,
 	},
+	{
+		.arg		= "mac-da",
+		.group		= ETHTOOL_MSG_WOL_SET,
+		.type		= ETHTOOL_A_WOL_MAC_DA,
+		.handler	= nl_parse_byte_str,
+		.handler_data	= &sopass_parser_data,
+		.min_argc	= 1,
+	},
 	{
 		.arg		= "msglvl",
 		.group		= ETHTOOL_MSG_DEBUG_SET,
diff --git a/test-cmdline.c b/test-cmdline.c
index cb803ed1a93d..cfe7d24c065f 100644
--- a/test-cmdline.c
+++ b/test-cmdline.c
@@ -74,6 +74,10 @@  static struct test_case {
 	{ 1, "--change devname sopass 01:23:45:67:89:" },
 	{ 1, "-s devname sopass 01:23:45:67:89" },
 	{ 1, "--change devname sopass" },
+	{ 0, "-s devname mac-da 01:23:45:67:89:ab" },
+	{ 1, "--change devname mac-da 01:23:45:67:89:" },
+	{ 1, "-s devname mac-da 01:23:45:67:89" },
+	{ 1, "--change devname mac-da" },
 	{ 0, "-s devname msglvl 1" },
 	{ 1, "--change devname msglvl" },
 	{ 0, "-s devname msglvl hw on rx_status off" },