History

ethtool: provide WoL settings with WOL_GET request

Implement WOL_GET request to get wake-on-lan settings for a device, traditionally available via ETHTOOL_GWOL ioctl request. As part of the implementation, provide symbolic names for wake-on-line modes as ETH_SS_WOL_MODES string set.

Michal Kubecek committed 6 years ago

Commit 51ea22b1 parent 0bda7af10 files · +176 −2Browse files

Unified · Split

10 files
  1. Documentation/networking/ethtool-netlink.rst +29 −1
  2. include/uapi/linux/ethtool.h +4 −0
  3. include/uapi/linux/ethtool_netlink.h +15 −0
  4. net/ethtool/Makefile +1 −1
  5. net/ethtool/common.c +12 −0
  6. net/ethtool/common.h +1 −0
  7. net/ethtool/netlink.c +9 −0
  8. net/ethtool/netlink.h +1 −0
  9. net/ethtool/strset.c +5 −0
  10. net/ethtool/wol.c +99 −0
Documentation/networking/ethtool-netlink.rst+29−1
@@ -187,6 +187,7 @@ Userspace to kernel: · 186 unmodified lines
187187 ``ETHTOOL_MSG_LINKSTATE_GET`` get link state
188188 ``ETHTOOL_MSG_DEBUG_GET`` get debugging settings
189189 ``ETHTOOL_MSG_DEBUG_SET`` set debugging settings
190+ ``ETHTOOL_MSG_WOL_GET`` get wake-on-lan settings
190191 ===================================== ================================
191192
192193 Kernel to userspace:
@@ -200,6 +201,7 @@ Kernel to userspace: · 7 unmodified lines
200201 ``ETHTOOL_MSG_LINKSTATE_GET_REPLY`` link state info
201202 ``ETHTOOL_MSG_DEBUG_GET_REPLY`` debugging settings
202203 ``ETHTOOL_MSG_DEBUG_NTF`` debugging settings notification
204+ ``ETHTOOL_MSG_WOL_GET_REPLY`` wake-on-lan settings
203205 ===================================== ================================
204206
205207 ``GET`` requests are sent by userspace applications to retrieve device
@@ -474,6 +476,32 @@ Request contents: · 268 unmodified lines
474476 enabled debugging message types for the device.
475477
476478
479+WOL_GET
480+=======
481+
482+Query device wake-on-lan settings. Unlike most "GET" type requests,
483+``ETHTOOL_MSG_WOL_GET`` requires (netns) ``CAP_NET_ADMIN`` privileges as it
484+(potentially) provides SecureOn(tm) password which is confidential.
485+
486+Request contents:
487+
488+ ==================================== ====== ==========================
489+ ``ETHTOOL_A_WOL_HEADER`` nested request header
490+ ==================================== ====== ==========================
491+
492+Kernel response contents:
493+
494+ ==================================== ====== ==========================
495+ ``ETHTOOL_A_WOL_HEADER`` nested reply header
496+ ``ETHTOOL_A_WOL_MODES`` bitset mask of enabled WoL modes
497+ ``ETHTOOL_A_WOL_SOPASS`` binary SecureOn(tm) password
498+ ==================================== ====== ==========================
499+
500+In reply, ``ETHTOOL_A_WOL_MODES`` mask consists of modes supported by the
501+device, value of modes which are enabled. ``ETHTOOL_A_WOL_SOPASS`` is only
502+included in reply if ``WAKE_MAGICSECURE`` mode is supported.
503+
504+
477505 Request translation
478506 ===================
479507
@@ -490,7 +518,7 @@ have their netlink replacement yet. · 10 unmodified lines
490518 ``ETHTOOL_MSG_LINKMODES_SET``
491519 ``ETHTOOL_GDRVINFO`` n/a
492520 ``ETHTOOL_GREGS`` n/a
493− ``ETHTOOL_GWOL`` n/a
521+ ``ETHTOOL_GWOL`` ``ETHTOOL_MSG_WOL_GET``
494522 ``ETHTOOL_SWOL`` n/a
495523 ``ETHTOOL_GMSGLVL`` ``ETHTOOL_MSG_DEBUG_GET``
496524 ``ETHTOOL_SMSGLVL`` ``ETHTOOL_MSG_DEBUG_SET``
include/uapi/linux/ethtool.h+4−0
@@ -595,6 +595,7 @@ struct ethtool_pauseparam { · 594 unmodified lines
595595 * @ETH_SS_PHY_TUNABLES: PHY tunable names
596596 * @ETH_SS_LINK_MODES: link mode names
597597 * @ETH_SS_MSG_CLASSES: debug message class names
598+ * @ETH_SS_WOL_MODES: wake-on-lan modes
598599 */
599600 enum ethtool_stringset {
600601 ETH_SS_TEST = 0,
@@ -608,6 +609,7 @@ enum ethtool_stringset { · 7 unmodified lines
608609 ETH_SS_PHY_TUNABLES,
609610 ETH_SS_LINK_MODES,
610611 ETH_SS_MSG_CLASSES,
612+ ETH_SS_WOL_MODES,
611613
612614 /* add new constants above here */
613615 ETH_SS_COUNT
@@ -1695,6 +1697,8 @@ static inline int ethtool_validate_duplex(__u8 duplex) · 1081 unmodified lines
16951697 #define WAKE_MAGICSECURE (1 << 6) /* only meaningful if WAKE_MAGIC */
16961698 #define WAKE_FILTER (1 << 7)
16971699
1700+#define WOL_MODE_COUNT 8
1701+
16981702 /* L2-L4 network traffic flow types */
16991703 #define TCP_V4_FLOW 0x01 /* hash or spec (tcp_ip4_spec) */
17001704 #define UDP_V4_FLOW 0x02 /* hash or spec (udp_ip4_spec) */
include/uapi/linux/ethtool_netlink.h+15−0
@@ -22,6 +22,7 @@ enum { · 21 unmodified lines
2222 ETHTOOL_MSG_LINKSTATE_GET,
2323 ETHTOOL_MSG_DEBUG_GET,
2424 ETHTOOL_MSG_DEBUG_SET,
25+ ETHTOOL_MSG_WOL_GET,
2526
2627 /* add new constants above here */
2728 __ETHTOOL_MSG_USER_CNT,
@@ -39,6 +40,7 @@ enum { · 11 unmodified lines
3940 ETHTOOL_MSG_LINKSTATE_GET_REPLY,
4041 ETHTOOL_MSG_DEBUG_GET_REPLY,
4142 ETHTOOL_MSG_DEBUG_NTF,
43+ ETHTOOL_MSG_WOL_GET_REPLY,
4244
4345 /* add new constants above here */
4446 __ETHTOOL_MSG_KERNEL_CNT,
@@ -211,6 +213,19 @@ enum { · 166 unmodified lines
211213 ETHTOOL_A_DEBUG_MAX = __ETHTOOL_A_DEBUG_CNT - 1
212214 };
213215
216+/* WOL */
217+
218+enum {
219+ ETHTOOL_A_WOL_UNSPEC,
220+ ETHTOOL_A_WOL_HEADER, /* nest - _A_HEADER_* */
221+ ETHTOOL_A_WOL_MODES, /* bitset */
222+ ETHTOOL_A_WOL_SOPASS, /* binary */
223+
224+ /* add new constants above here */
225+ __ETHTOOL_A_WOL_CNT,
226+ ETHTOOL_A_WOL_MAX = __ETHTOOL_A_WOL_CNT - 1
227+};
228+
214229 /* generic netlink info */
215230 #define ETHTOOL_GENL_NAME "ethtool"
216231 #define ETHTOOL_GENL_VERSION 1
net/ethtool/Makefile+1−1
@@ -5,4 +5,4 @@ obj-y += ioctl.o common.o · 4 unmodified lines
55 obj-$(CONFIG_ETHTOOL_NETLINK) += ethtool_nl.o
66
77 ethtool_nl-y := netlink.o bitset.o strset.o linkinfo.o linkmodes.o \
8− linkstate.o debug.o
8+ linkstate.o debug.o wol.o
net/ethtool/common.c+12−0
@@ -190,6 +190,18 @@ const char netif_msg_class_names[][ETH_GSTRING_LEN] = { · 189 unmodified lines
190190 };
191191 static_assert(ARRAY_SIZE(netif_msg_class_names) == NETIF_MSG_CLASS_COUNT);
192192
193+const char wol_mode_names[][ETH_GSTRING_LEN] = {
194+ [const_ilog2(WAKE_PHY)] = "phy",
195+ [const_ilog2(WAKE_UCAST)] = "ucast",
196+ [const_ilog2(WAKE_MCAST)] = "mcast",
197+ [const_ilog2(WAKE_BCAST)] = "bcast",
198+ [const_ilog2(WAKE_ARP)] = "arp",
199+ [const_ilog2(WAKE_MAGIC)] = "magic",
200+ [const_ilog2(WAKE_MAGICSECURE)] = "magicsecure",
201+ [const_ilog2(WAKE_FILTER)] = "filter",
202+};
203+static_assert(ARRAY_SIZE(wol_mode_names) == WOL_MODE_COUNT);
204+
193205 /* return false if legacy contained non-0 deprecated fields
194206 * maxtxpkt/maxrxpkt. rest of ksettings always updated
195207 */
net/ethtool/common.h+1−0
@@ -20,6 +20,7 @@ extern const char · 19 unmodified lines
2020 phy_tunable_strings[__ETHTOOL_PHY_TUNABLE_COUNT][ETH_GSTRING_LEN];
2121 extern const char link_mode_names[][ETH_GSTRING_LEN];
2222 extern const char netif_msg_class_names[][ETH_GSTRING_LEN];
23+extern const char wol_mode_names[][ETH_GSTRING_LEN];
2324
2425 int __ethtool_get_link(struct net_device *dev);
2526
net/ethtool/netlink.c+9−0
@@ -214,6 +214,7 @@ ethnl_default_requests[__ETHTOOL_MSG_USER_CNT] = { · 213 unmodified lines
214214 [ETHTOOL_MSG_LINKMODES_GET] = &ethnl_linkmodes_request_ops,
215215 [ETHTOOL_MSG_LINKSTATE_GET] = &ethnl_linkstate_request_ops,
216216 [ETHTOOL_MSG_DEBUG_GET] = &ethnl_debug_request_ops,
217+ [ETHTOOL_MSG_WOL_GET] = &ethnl_wol_request_ops,
217218 };
218219
219220 static struct ethnl_dump_ctx *ethnl_dump_context(struct netlink_callback *cb)
@@ -679,6 +680,14 @@ static const struct genl_ops ethtool_genl_ops[] = { · 459 unmodified lines
679680 .flags = GENL_UNS_ADMIN_PERM,
680681 .doit = ethnl_set_debug,
681682 },
683+ {
684+ .cmd = ETHTOOL_MSG_WOL_GET,
685+ .flags = GENL_UNS_ADMIN_PERM,
686+ .doit = ethnl_default_doit,
687+ .start = ethnl_default_start,
688+ .dumpit = ethnl_default_dumpit,
689+ .done = ethnl_default_done,
690+ },
682691 };
683692
684693 static const struct genl_multicast_group ethtool_nl_mcgrps[] = {
net/ethtool/netlink.h+1−0
@@ -335,6 +335,7 @@ extern const struct ethnl_request_ops ethnl_linkinfo_request_ops; · 334 unmodified lines
335335 extern const struct ethnl_request_ops ethnl_linkmodes_request_ops;
336336 extern const struct ethnl_request_ops ethnl_linkstate_request_ops;
337337 extern const struct ethnl_request_ops ethnl_debug_request_ops;
338+extern const struct ethnl_request_ops ethnl_wol_request_ops;
338339
339340 int ethnl_set_linkinfo(struct sk_buff *skb, struct genl_info *info);
340341 int ethnl_set_linkmodes(struct sk_buff *skb, struct genl_info *info);
net/ethtool/strset.c+5−0
@@ -55,6 +55,11 @@ static const struct strset_info info_template[] = { · 54 unmodified lines
5555 .count = NETIF_MSG_CLASS_COUNT,
5656 .strings = netif_msg_class_names,
5757 },
58+ [ETH_SS_WOL_MODES] = {
59+ .per_dev = false,
60+ .count = WOL_MODE_COUNT,
61+ .strings = wol_mode_names,
62+ },
5863 };
5964
6065 struct strset_req_info {
net/ethtool/wol.c+99−0
@@ -0,0 +1,99 @@
1+// SPDX-License-Identifier: GPL-2.0-only
2+
3+#include "netlink.h"
4+#include "common.h"
5+#include "bitset.h"
6+
7+struct wol_req_info {
8+ struct ethnl_req_info base;
9+};
10+
11+struct wol_reply_data {
12+ struct ethnl_reply_data base;
13+ struct ethtool_wolinfo wol;
14+ bool show_sopass;
15+};
16+
17+#define WOL_REPDATA(__reply_base) \
18+ container_of(__reply_base, struct wol_reply_data, base)
19+
20+static const struct nla_policy
21+wol_get_policy[ETHTOOL_A_WOL_MAX + 1] = {
22+ [ETHTOOL_A_WOL_UNSPEC] = { .type = NLA_REJECT },
23+ [ETHTOOL_A_WOL_HEADER] = { .type = NLA_NESTED },
24+ [ETHTOOL_A_WOL_MODES] = { .type = NLA_REJECT },
25+ [ETHTOOL_A_WOL_SOPASS] = { .type = NLA_REJECT },
26+};
27+
28+static int wol_prepare_data(const struct ethnl_req_info *req_base,
29+ struct ethnl_reply_data *reply_base,
30+ struct genl_info *info)
31+{
32+ struct wol_reply_data *data = WOL_REPDATA(reply_base);
33+ struct net_device *dev = reply_base->dev;
34+ int ret;
35+
36+ if (!dev->ethtool_ops->get_wol)
37+ return -EOPNOTSUPP;
38+
39+ ret = ethnl_ops_begin(dev);
40+ if (ret < 0)
41+ return ret;
42+ dev->ethtool_ops->get_wol(dev, &data->wol);
43+ ethnl_ops_complete(dev);
44+ data->show_sopass = data->wol.supported & WAKE_MAGICSECURE;
45+
46+ return 0;
47+}
48+
49+static int wol_reply_size(const struct ethnl_req_info *req_base,
50+ const struct ethnl_reply_data *reply_base)
51+{
52+ bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS;
53+ const struct wol_reply_data *data = WOL_REPDATA(reply_base);
54+ int len;
55+
56+ len = ethnl_bitset32_size(&data->wol.wolopts, &data->wol.supported,
57+ WOL_MODE_COUNT, wol_mode_names, compact);
58+ if (len < 0)
59+ return len;
60+ if (data->show_sopass)
61+ len += nla_total_size(sizeof(data->wol.sopass));
62+
63+ return len;
64+}
65+
66+static int wol_fill_reply(struct sk_buff *skb,
67+ const struct ethnl_req_info *req_base,
68+ const struct ethnl_reply_data *reply_base)
69+{
70+ bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS;
71+ const struct wol_reply_data *data = WOL_REPDATA(reply_base);
72+ int ret;
73+
74+ ret = ethnl_put_bitset32(skb, ETHTOOL_A_WOL_MODES, &data->wol.wolopts,
75+ &data->wol.supported, WOL_MODE_COUNT,
76+ wol_mode_names, compact);
77+ if (ret < 0)
78+ return ret;
79+ if (data->show_sopass &&
80+ nla_put(skb, ETHTOOL_A_WOL_SOPASS, sizeof(data->wol.sopass),
81+ data->wol.sopass))
82+ return -EMSGSIZE;
83+
84+ return 0;
85+}
86+
87+const struct ethnl_request_ops ethnl_wol_request_ops = {
88+ .request_cmd = ETHTOOL_MSG_WOL_GET,
89+ .reply_cmd = ETHTOOL_MSG_WOL_GET_REPLY,
90+ .hdr_attr = ETHTOOL_A_WOL_HEADER,
91+ .max_attr = ETHTOOL_A_WOL_MAX,
92+ .req_info_size = sizeof(struct wol_req_info),
93+ .reply_data_size = sizeof(struct wol_reply_data),
94+ .request_policy = wol_get_policy,
95+
96+ .prepare_data = wol_prepare_data,
97+ .reply_size = wol_reply_size,
98+ .fill_reply = wol_fill_reply,
99+};