diff mbox series

[net-next,1/2] ethtool: Introduce WAKE_MDA

Message ID 20231011221242.4180589-2-florian.fainelli@broadcom.com (mailing list archive)
State Changes Requested
Delegated to: Netdev Maintainers
Headers show
Series Add WAKE_MDA Wake-on-LAN option | expand

Checks

Context Check Description
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Clearly marked for net-next
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 3237 this patch: 3237
netdev/cc_maintainers warning 6 maintainers not CCed: linux-doc@vger.kernel.org vladimir.oltean@nxp.com piergiorgio.beruto@gmail.com mailhol.vincent@wanadoo.fr gal@nvidia.com jiri@resnulli.us
netdev/build_clang success Errors and warnings before: 1571 this patch: 1571
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 3479 this patch: 3479
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 134 lines checked
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

Florian Fainelli Oct. 11, 2023, 10:12 p.m. UTC
Allow Ethernet PHY and MAC drivers with simplified matching logic to be
waking-up on a custom MAC destination address. This is particularly
useful for Ethernet PHYs which have limited amounts of buffering but can
still wake-up on a custom MAC destination address.

When WAKE_MDA is specified, the "sopass" field in the existing struct
ethtool_wolinfo is re-purposed to hold a custom MAC destination address
to match against.

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

Signed-off-by: Florian Fainelli <florian.fainelli@broadcom.com>
---
 Documentation/networking/ethtool-netlink.rst |  7 ++++++-
 include/uapi/linux/ethtool.h                 | 10 ++++++++--
 include/uapi/linux/ethtool_netlink.h         |  1 +
 net/ethtool/common.c                         |  1 +
 net/ethtool/netlink.h                        |  2 +-
 net/ethtool/wol.c                            | 21 ++++++++++++++++++++
 6 files changed, 38 insertions(+), 4 deletions(-)

Comments

Michal Kubecek Oct. 11, 2023, 11:08 p.m. UTC | #1
On Wed, Oct 11, 2023 at 03:12:39PM -0700, Florian Fainelli wrote:
> Allow Ethernet PHY and MAC drivers with simplified matching logic to be
> waking-up on a custom MAC destination address. This is particularly
> useful for Ethernet PHYs which have limited amounts of buffering but can
> still wake-up on a custom MAC destination address.
> 
> When WAKE_MDA is specified, the "sopass" field in the existing struct
> ethtool_wolinfo is re-purposed to hold a custom MAC destination address
> to match against.
> 
> Example:
> 	ethtool -s eth0 wol e mac-da 01:00:5e:00:00:fb
> 
> Signed-off-by: Florian Fainelli <florian.fainelli@broadcom.com>
> ---
>  Documentation/networking/ethtool-netlink.rst |  7 ++++++-
>  include/uapi/linux/ethtool.h                 | 10 ++++++++--
>  include/uapi/linux/ethtool_netlink.h         |  1 +
>  net/ethtool/common.c                         |  1 +
>  net/ethtool/netlink.h                        |  2 +-
>  net/ethtool/wol.c                            | 21 ++++++++++++++++++++
>  6 files changed, 38 insertions(+), 4 deletions(-)
> 
[...]
> diff --git a/include/uapi/linux/ethtool.h b/include/uapi/linux/ethtool.h
> index f7fba0dc87e5..8134ac8870bd 100644
> --- a/include/uapi/linux/ethtool.h
> +++ b/include/uapi/linux/ethtool.h
> @@ -207,12 +207,17 @@ struct ethtool_drvinfo {
>   * @wolopts: Bitmask of %WAKE_* flags for enabled Wake-On-Lan modes.
>   * @sopass: SecureOn(tm) password; meaningful only if %WAKE_MAGICSECURE
>   *	is set in @wolopts.
> + * @mac_da: Destination MAC address to match; meaningful only if
> + *	%WAKE_MDA is set in @wolopts.
>   */
>  struct ethtool_wolinfo {
>  	__u32	cmd;
>  	__u32	supported;
>  	__u32	wolopts;
> -	__u8	sopass[SOPASS_MAX];
> +	union {
> +		__u8	sopass[SOPASS_MAX];
> +		__u8	mac_da[ETH_ALEN];
> +	};
>  };

If we use the union here, we should also make sure the request cannot
set both WAKE_MAGICSECURE and WAKE_MDA, otherwise the same data will be
used for two different values (and interpreted in two different ways in
GET requests and notifications).

Another option would be keeping the existing structure for ioctl UAPI
and using another structure (like we did in other cases where we needed
new attributes beyond frozen ioctl structures) so that a combination of
WAKE_MAGICSECURE and WAKE_MDA is possible. (It doesn't seem to make much
sense to me to combine WAKE_MAGICSECURE with other bits but I can't rule
out someone might want that one day.)

[...]
> diff --git a/net/ethtool/wol.c b/net/ethtool/wol.c
> index 0ed56c9ac1bc..13dfcc9bb1e5 100644
> --- a/net/ethtool/wol.c
> +++ b/net/ethtool/wol.c
> @@ -12,6 +12,7 @@ struct wol_reply_data {
>  	struct ethnl_reply_data		base;
>  	struct ethtool_wolinfo		wol;
>  	bool				show_sopass;
> +	bool				show_mac_da;
>  };
>  
>  #define WOL_REPDATA(__reply_base) \
> @@ -41,6 +42,8 @@ static int wol_prepare_data(const struct ethnl_req_info *req_base,
>  	/* do not include password in notifications */
>  	data->show_sopass = !genl_info_is_ntf(info) &&
>  		(data->wol.supported & WAKE_MAGICSECURE);
> +	data->show_mac_da = !genl_info_is_ntf(info) &&
> +		(data->wol.supported & WAKE_MDA);
>  
>  	return 0;
>  }

The test for !genl_info_is_ntf(info) above is meant to prevent the
sopass value (which is supposed to be secret) from being included in
notifications which can be seen by unprivileged users. Is the MAC
address to match also supposed to be secret?

Michal
Florian Fainelli Oct. 12, 2023, 12:21 a.m. UTC | #2
On 10/11/2023 4:08 PM, Michal Kubecek wrote:
> On Wed, Oct 11, 2023 at 03:12:39PM -0700, Florian Fainelli wrote:
>> Allow Ethernet PHY and MAC drivers with simplified matching logic to be
>> waking-up on a custom MAC destination address. This is particularly
>> useful for Ethernet PHYs which have limited amounts of buffering but can
>> still wake-up on a custom MAC destination address.
>>
>> When WAKE_MDA is specified, the "sopass" field in the existing struct
>> ethtool_wolinfo is re-purposed to hold a custom MAC destination address
>> to match against.
>>
>> Example:
>> 	ethtool -s eth0 wol e mac-da 01:00:5e:00:00:fb
>>
>> Signed-off-by: Florian Fainelli <florian.fainelli@broadcom.com>
>> ---
>>   Documentation/networking/ethtool-netlink.rst |  7 ++++++-
>>   include/uapi/linux/ethtool.h                 | 10 ++++++++--
>>   include/uapi/linux/ethtool_netlink.h         |  1 +
>>   net/ethtool/common.c                         |  1 +
>>   net/ethtool/netlink.h                        |  2 +-
>>   net/ethtool/wol.c                            | 21 ++++++++++++++++++++
>>   6 files changed, 38 insertions(+), 4 deletions(-)
>>
> [...]
>> diff --git a/include/uapi/linux/ethtool.h b/include/uapi/linux/ethtool.h
>> index f7fba0dc87e5..8134ac8870bd 100644
>> --- a/include/uapi/linux/ethtool.h
>> +++ b/include/uapi/linux/ethtool.h
>> @@ -207,12 +207,17 @@ struct ethtool_drvinfo {
>>    * @wolopts: Bitmask of %WAKE_* flags for enabled Wake-On-Lan modes.
>>    * @sopass: SecureOn(tm) password; meaningful only if %WAKE_MAGICSECURE
>>    *	is set in @wolopts.
>> + * @mac_da: Destination MAC address to match; meaningful only if
>> + *	%WAKE_MDA is set in @wolopts.
>>    */
>>   struct ethtool_wolinfo {
>>   	__u32	cmd;
>>   	__u32	supported;
>>   	__u32	wolopts;
>> -	__u8	sopass[SOPASS_MAX];
>> +	union {
>> +		__u8	sopass[SOPASS_MAX];
>> +		__u8	mac_da[ETH_ALEN];
>> +	};
>>   };
> 
> If we use the union here, we should also make sure the request cannot
> set both WAKE_MAGICSECURE and WAKE_MDA, otherwise the same data will be
> used for two different values (and interpreted in two different ways in
> GET requests and notifications).
> 
> Another option would be keeping the existing structure for ioctl UAPI
> and using another structure (like we did in other cases where we needed
> new attributes beyond frozen ioctl structures) so that a combination of
> WAKE_MAGICSECURE and WAKE_MDA is possible. (It doesn't seem to make much
> sense to me to combine WAKE_MAGICSECURE with other bits but I can't rule
> out someone might want that one day.)

I am having some second thoughts about this proposed interface as I can 
see a few limitations:

- we can only specify an exact destination MAC address to match, but the 
HW filter underneath is typically implemented using a match + mask so 
you can actually be selective about which bits you want to match on. In 
the use case that I have in mind we would actually want to match both 
multicast MAC destination addresses corresponding to mDNS over IPv4 or IPv6

- in case a MAC/PHY/switch supports multiple filters/slots we would not 
be able to address a specific slot in the matching logic

This sort of brings me back to the original proposal which allowed this:

https://lore.kernel.org/all/20230516231713.2882879-1-florian.fainelli@broadcom.com/

Andrew, what do you think?

> 
> [...]
>> diff --git a/net/ethtool/wol.c b/net/ethtool/wol.c
>> index 0ed56c9ac1bc..13dfcc9bb1e5 100644
>> --- a/net/ethtool/wol.c
>> +++ b/net/ethtool/wol.c
>> @@ -12,6 +12,7 @@ struct wol_reply_data {
>>   	struct ethnl_reply_data		base;
>>   	struct ethtool_wolinfo		wol;
>>   	bool				show_sopass;
>> +	bool				show_mac_da;
>>   };
>>   
>>   #define WOL_REPDATA(__reply_base) \
>> @@ -41,6 +42,8 @@ static int wol_prepare_data(const struct ethnl_req_info *req_base,
>>   	/* do not include password in notifications */
>>   	data->show_sopass = !genl_info_is_ntf(info) &&
>>   		(data->wol.supported & WAKE_MAGICSECURE);
>> +	data->show_mac_da = !genl_info_is_ntf(info) &&
>> +		(data->wol.supported & WAKE_MDA);
>>   
>>   	return 0;
>>   }
> 
> The test for !genl_info_is_ntf(info) above is meant to prevent the
> sopass value (which is supposed to be secret) from being included in
> notifications which can be seen by unprivileged users. Is the MAC
> address to match also supposed to be secret?

Either way could be considered, so I erred on the side of caution.
Andrew Lunn Oct. 12, 2023, 12:45 p.m. UTC | #3
> I am having some second thoughts about this proposed interface as I can see
> a few limitations:
> 
> - we can only specify an exact destination MAC address to match, but the HW
> filter underneath is typically implemented using a match + mask so you can
> actually be selective about which bits you want to match on. In the use case
> that I have in mind we would actually want to match both multicast MAC
> destination addresses corresponding to mDNS over IPv4 or IPv6
> 
> - in case a MAC/PHY/switch supports multiple filters/slots we would not be
> able to address a specific slot in the matching logic
> 
> This sort of brings me back to the original proposal which allowed this:
> 
> https://lore.kernel.org/all/20230516231713.2882879-1-florian.fainelli@broadcom.com/

The Marvell PHY i just looked at supports upto 8 slots, and can match
up to the first 128 bytes of frame data. So it does seem like a more
generic and flexible interface would fit the hardware.

My previous concern was discoverability of the feature. Its not part
of ethtool -s eth0 wol. At minimum, i would suggest something in the
--help text in the wol section and man page pointing to the
alternative way to configure wol. And maybe report via the standard
wol flags that the hardware has the capability to use flow-type WoL?

The example you gave matched on Flow Type: Raw Ethernet. Is it
possible to combine flow types? If i can match on the first 128 bytes
of the frame i might want to go deeper into the frame, so want both
Ethernet and IP matching?

    Andrew
Florian Fainelli Oct. 12, 2023, 6:32 p.m. UTC | #4
On 10/12/23 05:45, Andrew Lunn wrote:
>> I am having some second thoughts about this proposed interface as I can see
>> a few limitations:
>>
>> - we can only specify an exact destination MAC address to match, but the HW
>> filter underneath is typically implemented using a match + mask so you can
>> actually be selective about which bits you want to match on. In the use case
>> that I have in mind we would actually want to match both multicast MAC
>> destination addresses corresponding to mDNS over IPv4 or IPv6
>>
>> - in case a MAC/PHY/switch supports multiple filters/slots we would not be
>> able to address a specific slot in the matching logic
>>
>> This sort of brings me back to the original proposal which allowed this:
>>
>> https://lore.kernel.org/all/20230516231713.2882879-1-florian.fainelli@broadcom.com/
> 
> The Marvell PHY i just looked at supports upto 8 slots, and can match
> up to the first 128 bytes of frame data. So it does seem like a more
> generic and flexible interface would fit the hardware.
> 
> My previous concern was discoverability of the feature. Its not part
> of ethtool -s eth0 wol. At minimum, i would suggest something in the
> --help text in the wol section and man page pointing to the
> alternative way to configure wol. And maybe report via the standard
> wol flags that the hardware has the capability to use flow-type WoL?

WAKE_FILTER is supposed to be set by the driver if it supports waking-up 
from a network filter. That is how you would know that the device 
supports waking-up from a network filter, and then you need to configure 
the filters with ethtool -N (rxnfc).

Where this API is a good fit is that you can specify a filter location 
and the action (-2 = RX_CLS_FLOW_WAKE) to indicate where to install the 
filter and what it should do. Where it may not be such a great fit is 
that it is a two step process, where you need to make sure you install 
filter(s) plus enable WAKE_FILTER from the .set_wol() call.

At the time it was proposed it felt like a reasonable way to program, 
without having "ethtool -s eth0 wol" gain a form of packet matching 
parser. Also, it does not seem to me like we need the operations to be 
necessarily atomic in a single call to the kernel but if we feel like 
this is too difficult to use, we could consider a .set_wol() call that 
supports being passed network filter(s).

> 
> The example you gave matched on Flow Type: Raw Ethernet. Is it
> possible to combine flow types? If i can match on the first 128 bytes
> of the frame i might want to go deeper into the frame, so want both
> Ethernet and IP matching?

AFAICT with neither ethtool nor cls_flower you would be able to match on 
an arbitrary and unstructured N-bytes key + N-bytes mask. You would 
likely need to create two filters here, one for Ethernet, specified with 
the "flow-type ether" and one for each IP version...

You might have a shot with the extended flow representation which 
provides a few bytes of raw filtering, I have not really explored that 
part TBH.
Andrew Lunn Oct. 12, 2023, 8:24 p.m. UTC | #5
> > My previous concern was discoverability of the feature. Its not part
> > of ethtool -s eth0 wol. At minimum, i would suggest something in the
> > --help text in the wol section and man page pointing to the
> > alternative way to configure wol. And maybe report via the standard
> > wol flags that the hardware has the capability to use flow-type WoL?
> 
> WAKE_FILTER is supposed to be set by the driver if it supports waking-up
> from a network filter. That is how you would know that the device supports
> waking-up from a network filter, and then you need to configure the filters
> with ethtool -N (rxnfc).
> 
> Where this API is a good fit is that you can specify a filter location and
> the action (-2 = RX_CLS_FLOW_WAKE) to indicate where to install the filter
> and what it should do. Where it may not be such a great fit is that it is a
> two step process, where you need to make sure you install filter(s) plus
> enable WAKE_FILTER from the .set_wol() call.
> 
> At the time it was proposed it felt like a reasonable way to program,
> without having "ethtool -s eth0 wol" gain a form of packet matching parser.
> Also, it does not seem to me like we need the operations to be necessarily
> atomic in a single call to the kernel but if we feel like this is too
> difficult to use, we could consider a .set_wol() call that supports being
> passed network filter(s).
 
I think two step is fine. I would say anybody using rxnfc is a pretty
advanced user.

But we should clearly define what we expect in terms of ordering and
maybe try to enforce it in the core. Can we make the rxnfc call return
-EBUSY or something and an extack message if WAKE_FILTER has not been
enabled first?

	Andrew
Florian Fainelli Oct. 12, 2023, 9:02 p.m. UTC | #6
On 10/12/23 13:24, Andrew Lunn wrote:
>>> My previous concern was discoverability of the feature. Its not part
>>> of ethtool -s eth0 wol. At minimum, i would suggest something in the
>>> --help text in the wol section and man page pointing to the
>>> alternative way to configure wol. And maybe report via the standard
>>> wol flags that the hardware has the capability to use flow-type WoL?
>>
>> WAKE_FILTER is supposed to be set by the driver if it supports waking-up
>> from a network filter. That is how you would know that the device supports
>> waking-up from a network filter, and then you need to configure the filters
>> with ethtool -N (rxnfc).
>>
>> Where this API is a good fit is that you can specify a filter location and
>> the action (-2 = RX_CLS_FLOW_WAKE) to indicate where to install the filter
>> and what it should do. Where it may not be such a great fit is that it is a
>> two step process, where you need to make sure you install filter(s) plus
>> enable WAKE_FILTER from the .set_wol() call.
>>
>> At the time it was proposed it felt like a reasonable way to program,
>> without having "ethtool -s eth0 wol" gain a form of packet matching parser.
>> Also, it does not seem to me like we need the operations to be necessarily
>> atomic in a single call to the kernel but if we feel like this is too
>> difficult to use, we could consider a .set_wol() call that supports being
>> passed network filter(s).
>   
> I think two step is fine. I would say anybody using rxnfc is a pretty
> advanced user.
> 
> But we should clearly define what we expect in terms of ordering and
> maybe try to enforce it in the core. Can we make the rxnfc call return
> -EBUSY or something and an extack message if WAKE_FILTER has not been
> enabled first?

It might make sense to do it the other way around, that is you must 
install filters first and if none are installed by the time we enable 
WAKE_FILTER in .set_wol(), we error out with -EINVAL?
Andrew Lunn Oct. 12, 2023, 9:18 p.m. UTC | #7
> > But we should clearly define what we expect in terms of ordering and
> > maybe try to enforce it in the core. Can we make the rxnfc call return
> > -EBUSY or something and an extack message if WAKE_FILTER has not been
> > enabled first?
> 
> It might make sense to do it the other way around, that is you must install
> filters first and if none are installed by the time we enable WAKE_FILTER in
> .set_wol(), we error out with -EINVAL?

I was thinking the other way around would be easier for the core to
enforce. When inserting an rxnfc, it can do an ethtool.get_wol(ndev)
and check WAKE_FILTER is set. That seems simpler than doing a
get_rxnfc() and having to look through the results and try to figure
out which are for WoL?

Anyway, you seem to be volunteering to implement this, so either is
fine for me, so long as we do have some central enforcement.

     Andrew
Florian Fainelli Oct. 13, 2023, 4:15 p.m. UTC | #8
On 10/12/23 14:18, Andrew Lunn wrote:
>>> But we should clearly define what we expect in terms of ordering and
>>> maybe try to enforce it in the core. Can we make the rxnfc call return
>>> -EBUSY or something and an extack message if WAKE_FILTER has not been
>>> enabled first?
>>
>> It might make sense to do it the other way around, that is you must install
>> filters first and if none are installed by the time we enable WAKE_FILTER in
>> .set_wol(), we error out with -EINVAL?
> 
> I was thinking the other way around would be easier for the core to
> enforce. When inserting an rxnfc, it can do an ethtool.get_wol(ndev)
> and check WAKE_FILTER is set. That seems simpler than doing a
> get_rxnfc() and having to look through the results and try to figure
> out which are for WoL?

What you propose would be simpler, but I believe it would be more 
logical to:

- install filter(s)
- set ethtool WAKE_FILTER

as the latter acts as a "commit", until that point the filters are 
installed, but may not be effective unless WAKE_FILTER is set and gets 
translated into the appropriate Wake-on-LAN enable bits. Of course 
nothing prevents you from doing the reverse or installing filters after 
setting WAkE_FILTER as long as the system does not go into suspend in 
between, everything should be working.

> 
> Anyway, you seem to be volunteering to implement this, so either is
> fine for me, so long as we do have some central enforcement.

Yes, patches will follow, thanks!
diff mbox series

Patch

diff --git a/Documentation/networking/ethtool-netlink.rst b/Documentation/networking/ethtool-netlink.rst
index 2540c70952ff..b2b1191d5cec 100644
--- a/Documentation/networking/ethtool-netlink.rst
+++ b/Documentation/networking/ethtool-netlink.rst
@@ -708,11 +708,13 @@  Kernel response contents:
   ``ETHTOOL_A_WOL_HEADER``              nested  reply header
   ``ETHTOOL_A_WOL_MODES``               bitset  mask of enabled WoL modes
   ``ETHTOOL_A_WOL_SOPASS``              binary  SecureOn(tm) password
+  ``ETHTOOL_A_WOL_MAC_DA``              binary  Destination matching MAC address
   ====================================  ======  ==========================
 
 In reply, ``ETHTOOL_A_WOL_MODES`` mask consists of modes supported by the
 device, value of modes which are enabled. ``ETHTOOL_A_WOL_SOPASS`` is only
-included in reply if ``WAKE_MAGICSECURE`` mode is supported.
+included in reply if ``WAKE_MAGICSECURE`` mode is supported. ``ETHTOOL_A_WOL_MAC_DA``
+is only included in reply if ``WAKE_MDA`` mode is supported.
 
 
 WOL_SET
@@ -726,10 +728,13 @@  Request contents:
   ``ETHTOOL_A_WOL_HEADER``              nested  request header
   ``ETHTOOL_A_WOL_MODES``               bitset  enabled WoL modes
   ``ETHTOOL_A_WOL_SOPASS``              binary  SecureOn(tm) password
+  ``ETHTOOL_A_WOL_MAC_DA``              binary  Destination matching MAC address
   ====================================  ======  ==========================
 
 ``ETHTOOL_A_WOL_SOPASS`` is only allowed for devices supporting
 ``WAKE_MAGICSECURE`` mode.
+``ETHTOOL_A_WOL_MAC_DA`` is only allowed for devices supporting
+``WAKE_MDA`` mode.
 
 
 FEATURES_GET
diff --git a/include/uapi/linux/ethtool.h b/include/uapi/linux/ethtool.h
index f7fba0dc87e5..8134ac8870bd 100644
--- a/include/uapi/linux/ethtool.h
+++ b/include/uapi/linux/ethtool.h
@@ -207,12 +207,17 @@  struct ethtool_drvinfo {
  * @wolopts: Bitmask of %WAKE_* flags for enabled Wake-On-Lan modes.
  * @sopass: SecureOn(tm) password; meaningful only if %WAKE_MAGICSECURE
  *	is set in @wolopts.
+ * @mac_da: Destination MAC address to match; meaningful only if
+ *	%WAKE_MDA is set in @wolopts.
  */
 struct ethtool_wolinfo {
 	__u32	cmd;
 	__u32	supported;
 	__u32	wolopts;
-	__u8	sopass[SOPASS_MAX];
+	union {
+		__u8	sopass[SOPASS_MAX];
+		__u8	mac_da[ETH_ALEN];
+	};
 };
 
 /* for passing single values */
@@ -1989,8 +1994,9 @@  static inline int ethtool_validate_duplex(__u8 duplex)
 #define WAKE_MAGIC		(1 << 5)
 #define WAKE_MAGICSECURE	(1 << 6) /* only meaningful if WAKE_MAGIC */
 #define WAKE_FILTER		(1 << 7)
+#define WAKE_MDA		(1 << 8)
 
-#define WOL_MODE_COUNT		8
+#define WOL_MODE_COUNT		9
 
 /* L2-L4 network traffic flow types */
 #define	TCP_V4_FLOW	0x01	/* hash or spec (tcp_ip4_spec) */
diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h
index 73e2c10dc2cc..237a0fc68997 100644
--- a/include/uapi/linux/ethtool_netlink.h
+++ b/include/uapi/linux/ethtool_netlink.h
@@ -300,6 +300,7 @@  enum {
 	ETHTOOL_A_WOL_HEADER,			/* nest - _A_HEADER_* */
 	ETHTOOL_A_WOL_MODES,			/* bitset */
 	ETHTOOL_A_WOL_SOPASS,			/* binary */
+	ETHTOOL_A_WOL_MAC_DA,			/* binary */
 
 	/* add new constants above here */
 	__ETHTOOL_A_WOL_CNT,
diff --git a/net/ethtool/common.c b/net/ethtool/common.c
index f5598c5f50de..d1c837f6094c 100644
--- a/net/ethtool/common.c
+++ b/net/ethtool/common.c
@@ -405,6 +405,7 @@  const char wol_mode_names[][ETH_GSTRING_LEN] = {
 	[const_ilog2(WAKE_MAGIC)]	= "magic",
 	[const_ilog2(WAKE_MAGICSECURE)]	= "magicsecure",
 	[const_ilog2(WAKE_FILTER)]	= "filter",
+	[const_ilog2(WAKE_MDA)]		= "mac-da",
 };
 static_assert(ARRAY_SIZE(wol_mode_names) == WOL_MODE_COUNT);
 
diff --git a/net/ethtool/netlink.h b/net/ethtool/netlink.h
index 9a333a8d04c1..5958e4483ced 100644
--- a/net/ethtool/netlink.h
+++ b/net/ethtool/netlink.h
@@ -407,7 +407,7 @@  extern const struct nla_policy ethnl_linkstate_get_policy[ETHTOOL_A_LINKSTATE_HE
 extern const struct nla_policy ethnl_debug_get_policy[ETHTOOL_A_DEBUG_HEADER + 1];
 extern const struct nla_policy ethnl_debug_set_policy[ETHTOOL_A_DEBUG_MSGMASK + 1];
 extern const struct nla_policy ethnl_wol_get_policy[ETHTOOL_A_WOL_HEADER + 1];
-extern const struct nla_policy ethnl_wol_set_policy[ETHTOOL_A_WOL_SOPASS + 1];
+extern const struct nla_policy ethnl_wol_set_policy[ETHTOOL_A_WOL_MAC_DA + 1];
 extern const struct nla_policy ethnl_features_get_policy[ETHTOOL_A_FEATURES_HEADER + 1];
 extern const struct nla_policy ethnl_features_set_policy[ETHTOOL_A_FEATURES_WANTED + 1];
 extern const struct nla_policy ethnl_privflags_get_policy[ETHTOOL_A_PRIVFLAGS_HEADER + 1];
diff --git a/net/ethtool/wol.c b/net/ethtool/wol.c
index 0ed56c9ac1bc..13dfcc9bb1e5 100644
--- a/net/ethtool/wol.c
+++ b/net/ethtool/wol.c
@@ -12,6 +12,7 @@  struct wol_reply_data {
 	struct ethnl_reply_data		base;
 	struct ethtool_wolinfo		wol;
 	bool				show_sopass;
+	bool				show_mac_da;
 };
 
 #define WOL_REPDATA(__reply_base) \
@@ -41,6 +42,8 @@  static int wol_prepare_data(const struct ethnl_req_info *req_base,
 	/* do not include password in notifications */
 	data->show_sopass = !genl_info_is_ntf(info) &&
 		(data->wol.supported & WAKE_MAGICSECURE);
+	data->show_mac_da = !genl_info_is_ntf(info) &&
+		(data->wol.supported & WAKE_MDA);
 
 	return 0;
 }
@@ -58,6 +61,8 @@  static int wol_reply_size(const struct ethnl_req_info *req_base,
 		return len;
 	if (data->show_sopass)
 		len += nla_total_size(sizeof(data->wol.sopass));
+	if (data->show_mac_da)
+		len += nla_total_size(sizeof(data->wol.mac_da));
 
 	return len;
 }
@@ -79,6 +84,10 @@  static int wol_fill_reply(struct sk_buff *skb,
 	    nla_put(skb, ETHTOOL_A_WOL_SOPASS, sizeof(data->wol.sopass),
 		    data->wol.sopass))
 		return -EMSGSIZE;
+	if (data->show_mac_da &&
+	    nla_put(skb, ETHTOOL_A_WOL_MAC_DA, sizeof(data->wol.mac_da),
+		    data->wol.mac_da))
+		return -EMSGSIZE;
 
 	return 0;
 }
@@ -91,6 +100,8 @@  const struct nla_policy ethnl_wol_set_policy[] = {
 	[ETHTOOL_A_WOL_MODES]		= { .type = NLA_NESTED },
 	[ETHTOOL_A_WOL_SOPASS]		= { .type = NLA_BINARY,
 					    .len = SOPASS_MAX },
+	[ETHTOOL_A_WOL_MAC_DA]		= { .type = NLA_BINARY,
+					    .len = ETH_ALEN }
 };
 
 static int
@@ -131,6 +142,16 @@  ethnl_set_wol(struct ethnl_req_info *req_info, struct genl_info *info)
 		ethnl_update_binary(wol.sopass, sizeof(wol.sopass),
 				    tb[ETHTOOL_A_WOL_SOPASS], &mod);
 	}
+	if (tb[ETHTOOL_A_WOL_MAC_DA]) {
+		if (!(wol.supported & WAKE_MDA)) {
+			NL_SET_ERR_MSG_ATTR(info->extack,
+					    tb[ETHTOOL_A_WOL_MAC_DA],
+					    "mac-da not supported, cannot set MAC");
+			return -EINVAL;
+		}
+		ethnl_update_binary(wol.mac_da, sizeof(wol.mac_da),
+				    tb[ETHTOOL_A_WOL_MAC_DA], &mod);
+	}
 
 	if (!mod)
 		return 0;