/
0017-ethtool-provide-WoL-information-in-SETTINGS_GET-requ.patch
307 lines (277 loc) · 10.4 KB
/
0017-ethtool-provide-WoL-information-in-SETTINGS_GET-requ.patch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
From e537cbc7d0f3aac94d8f6ca745fb0296e0bd5c77 Mon Sep 17 00:00:00 2001
From: Michal Kubecek <mkubecek@suse.cz>
Date: Sat, 16 Feb 2019 15:08:55 +0100
Subject: [PATCH 17/44] ethtool: provide WoL information in SETTINGS_GET
request
Add information about supported and enabled wake on LAN modes into the
SETTINGS_GET reply when ETHTOOL_IM_SETTINGS_WOL flag is set in the request.
The SETTINGS_GET request can be still sent by unprivileged users but in
such case the SecureOn password (if any) is not included in the reply.
Send notification in the same format as reply message when wake on LAN
settings are modified using ioctl interface (ETHTOOL_SWOL command).
Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
---
Documentation/networking/ethtool-netlink.txt | 15 ++++-
include/uapi/linux/ethtool_netlink.h | 15 ++++-
net/ethtool/common.c | 10 ++++
net/ethtool/common.h | 1 +
net/ethtool/ioctl.c | 10 ++--
net/ethtool/settings.c | 60 ++++++++++++++++++++
6 files changed, 104 insertions(+), 7 deletions(-)
diff --git a/Documentation/networking/ethtool-netlink.txt b/Documentation/networking/ethtool-netlink.txt
index dc06e33329a4..9929f574f590 100644
--- a/Documentation/networking/ethtool-netlink.txt
+++ b/Documentation/networking/ethtool-netlink.txt
@@ -251,6 +251,7 @@ Info mask bits meaning:
ETHTOOL_IM_SETTINGS_LINKINFO link settings
ETHTOOL_IM_SETTINGS_LINKMODES link modes and related
ETHTOOL_IM_SETTINGS_LINKSTATE link state
+ ETHTOOL_IM_SETTINGS_WOL struct ethtool_wolinfo
Response contents:
@@ -269,12 +270,22 @@ Response contents:
ETHTOOL_A_LINKMODES_DUPLEX (u8) duplex mode
ETHTOOL_A_SETTINGS_LINK_STATE (nested) link state
ETHTOOL_A_LINKSTATE_LINK (u8) link on/off/unknown
+ ETHTOOL_A_SETTINGS_WOL (nested) wake on LAN settings
+ ETHTOOL_A_WOL_MODES (bitfield32) wake on LAN modes
+ ETHTOOL_A_WOL_SOPASS (binary) SecureOn password
Most of the attributes and their values have the same meaning as matching
members of the corresponding ioctl structures. For ETHTOOL_A_LINKMODES_OURS,
value represents advertised modes and mask represents supported modes.
ETHTOOL_A_LINKMODES_PEER in the reply is a bit list.
+For ETHTOOL_A_WOL_MODES, selector reports wake on LAN modes supported by the
+device and value enabled modes.
+
+SETTINGS_GET request is allowed for unprivileged user but ETHTOOL_A_WOL_SOPASS
+is only provided by kernel in response to privileged (netns CAP_NET_ADMIN)
+requests.
+
SETTINGS_GET requests allow dumps and messages in the same format as response
to them are broadcasted as notifications on change of these settings using
netlink or ioctl ethtool interface.
@@ -321,12 +332,12 @@ ETHTOOL_GSET ETHTOOL_MSG_SETTINGS_GET
ETHTOOL_SSET ETHTOOL_MSG_SETTINGS_SET
ETHTOOL_GDRVINFO n/a
ETHTOOL_GREGS n/a
-ETHTOOL_GWOL n/a
+ETHTOOL_GWOL ETHTOOL_MSG_SETTINGS_GET
ETHTOOL_SWOL n/a
ETHTOOL_GMSGLVL n/a
ETHTOOL_SMSGLVL n/a
ETHTOOL_NWAY_RST n/a
-ETHTOOL_GLINK ETHNL_CMD_GET_SETTINGS
+ETHTOOL_GLINK ETHTOOL_MSG_SETTINGS_GET
ETHTOOL_GEEPROM n/a
ETHTOOL_SEEPROM n/a
ETHTOOL_GCOALESCE n/a
diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h
index 46c13455246f..bb2be3097614 100644
--- a/include/uapi/linux/ethtool_netlink.h
+++ b/include/uapi/linux/ethtool_netlink.h
@@ -159,6 +159,7 @@ enum {
ETHTOOL_A_SETTINGS_LINK_INFO, /* nest - _A_LINKINFO_* */
ETHTOOL_A_SETTINGS_LINK_MODES, /* nest - _A_LINKMODES_* */
ETHTOOL_A_SETTINGS_LINK_STATE, /* nest - _A_LINKSTATE_* */
+ ETHTOOL_A_SETTINGS_WOL, /* nest - _A_WOL_* */
/* add new constants above here */
__ETHTOOL_A_SETTINGS_CNT,
@@ -168,10 +169,12 @@ enum {
#define ETHTOOL_IM_SETTINGS_LINKINFO (1U << 0)
#define ETHTOOL_IM_SETTINGS_LINKMODES (1U << 1)
#define ETHTOOL_IM_SETTINGS_LINKSTATE (1U << 2)
+#define ETHTOOL_IM_SETTINGS_WOL (1U << 3)
#define ETHTOOL_IM_SETTINGS_ALL (ETHTOOL_IM_SETTINGS_LINKINFO | \
ETHTOOL_IM_SETTINGS_LINKMODES | \
- ETHTOOL_IM_SETTINGS_LINKSTATE)
+ ETHTOOL_IM_SETTINGS_LINKSTATE | \
+ ETHTOOL_IM_SETTINGS_WOL)
#define ETHTOOL_RF_SETTINGS_ALL 0
@@ -210,6 +213,16 @@ enum {
ETHTOOL_A_LINKSTATE_MAX = (__ETHTOOL_A_LINKSTATE_CNT - 1)
};
+enum {
+ ETHTOOL_A_WOL_UNSPEC,
+ ETHTOOL_A_WOL_MODES, /* bitfield32 */
+ ETHTOOL_A_WOL_SOPASS, /* binary */
+
+ /* add new constants above here */
+ __ETHTOOL_A_WOL_CNT,
+ ETHTOOL_A_WOL_MAX = (__ETHTOOL_A_WOL_CNT - 1)
+};
+
/* generic netlink info */
#define ETHTOOL_GENL_NAME "ethtool"
#define ETHTOOL_GENL_VERSION 1
diff --git a/net/ethtool/common.c b/net/ethtool/common.c
index b06635ad2620..f4d16b9a4047 100644
--- a/net/ethtool/common.c
+++ b/net/ethtool/common.c
@@ -138,3 +138,13 @@ int __ethtool_get_link(struct net_device *dev)
return netif_running(dev) && dev->ethtool_ops->get_link(dev);
}
+
+int __ethtool_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+ if (!dev->ethtool_ops->get_wol)
+ return -EOPNOTSUPP;
+
+ dev->ethtool_ops->get_wol(dev, wol);
+
+ return 0;
+}
diff --git a/net/ethtool/common.h b/net/ethtool/common.h
index a2c1504576c2..c4dcb80df620 100644
--- a/net/ethtool/common.h
+++ b/net/ethtool/common.h
@@ -16,6 +16,7 @@ extern const char
phy_tunable_strings[__ETHTOOL_PHY_TUNABLE_COUNT][ETH_GSTRING_LEN];
int __ethtool_get_link(struct net_device *dev);
+int __ethtool_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol);
bool convert_legacy_settings_to_link_ksettings(
struct ethtool_link_ksettings *link_ksettings,
diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c
index 853b8c21a5e5..d95fffff3bfe 100644
--- a/net/ethtool/ioctl.c
+++ b/net/ethtool/ioctl.c
@@ -1283,11 +1283,11 @@ static int ethtool_reset(struct net_device *dev, char __user *useraddr)
static int ethtool_get_wol(struct net_device *dev, char __user *useraddr)
{
struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL };
+ int rc;
- if (!dev->ethtool_ops->get_wol)
- return -EOPNOTSUPP;
-
- dev->ethtool_ops->get_wol(dev, &wol);
+ rc = __ethtool_get_wol(dev, &wol);
+ if (rc < 0)
+ return rc;
if (copy_to_user(useraddr, &wol, sizeof(wol)))
return -EFAULT;
@@ -1310,6 +1310,8 @@ static int ethtool_set_wol(struct net_device *dev, char __user *useraddr)
return ret;
dev->wol_enabled = !!wol.wolopts;
+ ethtool_notify(dev, NULL, ETHTOOL_MSG_SETTINGS_NTF,
+ ETHTOOL_IM_SETTINGS_WOL, NULL);
return 0;
}
diff --git a/net/ethtool/settings.c b/net/ethtool/settings.c
index 079d3776df71..fd29d843b2d9 100644
--- a/net/ethtool/settings.c
+++ b/net/ethtool/settings.c
@@ -10,6 +10,7 @@ struct settings_data {
/* everything below here will be reset for each device in dumps */
struct ethnl_reply_data repdata_base;
struct ethtool_link_ksettings ksettings;
+ struct ethtool_wolinfo wolinfo;
struct ethtool_link_settings *lsettings;
int link;
bool lpm_empty;
@@ -115,6 +116,7 @@ settings_get_policy[ETHTOOL_A_SETTINGS_MAX + 1] = {
[ETHTOOL_A_SETTINGS_LINK_INFO] = { .type = NLA_REJECT },
[ETHTOOL_A_SETTINGS_LINK_MODES] = { .type = NLA_REJECT },
[ETHTOOL_A_SETTINGS_LINK_STATE] = { .type = NLA_REJECT },
+ [ETHTOOL_A_SETTINGS_WOL] = { .type = NLA_REJECT },
};
static int ethnl_get_link_ksettings(struct genl_info *info,
@@ -130,6 +132,16 @@ static int ethnl_get_link_ksettings(struct genl_info *info,
return ret;
}
+static int ethnl_get_wol(struct genl_info *info, struct net_device *dev,
+ struct ethtool_wolinfo *wolinfo)
+{
+ int ret = __ethtool_get_wol(dev, wolinfo);
+
+ if (ret < 0 && info)
+ GENL_SET_ERR_MSG(info, "failed to retrieve wol info");
+ return ret;
+}
+
/* prepare_data() handler */
static int settings_prepare(struct ethnl_req_info *req_info,
struct genl_info *info)
@@ -167,6 +179,11 @@ static int settings_prepare(struct ethnl_req_info *req_info,
}
if (req_mask & ETHTOOL_IM_SETTINGS_LINKSTATE)
data->link = __ethtool_get_link(dev);
+ if (req_mask & ETHTOOL_IM_SETTINGS_WOL) {
+ ret = ethnl_get_wol(info, dev, &data->wolinfo);
+ if (ret < 0)
+ req_mask &= ~ETHTOOL_IM_SETTINGS_WOL;
+ }
ethnl_after_ops(dev);
data->repdata_base.info_mask = req_mask;
@@ -224,6 +241,12 @@ static int settings_linkstate_size(int link)
return nla_total_size(nla_total_size(sizeof(u8)));
}
+static int settings_wol_size(void)
+{
+ return nla_total_size(nla_total_size(sizeof(struct nla_bitfield32)) +
+ nla_total_size(SOPASS_MAX));
+}
+
/* reply_size() handler
*
* To keep things simple, reserve space for some attributes which may not
@@ -249,6 +272,8 @@ static int settings_size(const struct ethnl_req_info *req_info)
}
if (info_mask & ETHTOOL_IM_SETTINGS_LINKSTATE)
len += settings_linkstate_size(data->link);
+ if (info_mask & ETHTOOL_IM_SETTINGS_WOL)
+ len += settings_wol_size();
return len;
}
@@ -341,6 +366,34 @@ static int settings_fill_linkstate(struct sk_buff *skb, int link)
return -EMSGSIZE;
}
+static int settings_fill_wolinfo(struct sk_buff *skb,
+ const struct ethtool_wolinfo *wolinfo,
+ bool privileged)
+{
+ struct nlattr *nest;
+
+ nest = nla_nest_start(skb, ETHTOOL_A_SETTINGS_WOL);
+ if (!nest)
+ return -EMSGSIZE;
+ if (nla_put_bitfield32(skb, ETHTOOL_A_WOL_MODES, wolinfo->wolopts,
+ wolinfo->supported))
+ goto nla_put_failure;
+ /* ioctl() restricts read access to wolinfo but the actual
+ * reason is to hide sopass from unprivileged users; netlink
+ * can show wol modes without sopass
+ */
+ if (privileged &&
+ nla_put(skb, ETHTOOL_A_WOL_SOPASS, sizeof(wolinfo->sopass),
+ wolinfo->sopass))
+ goto nla_put_failure;
+ nla_nest_end(skb, nest);
+ return 0;
+
+nla_put_failure:
+ nla_nest_cancel(skb, nest);
+ return -EMSGSIZE;
+}
+
/* fill_reply() handler */
static int settings_fill(struct sk_buff *skb,
const struct ethnl_req_info *req_info)
@@ -367,6 +420,12 @@ static int settings_fill(struct sk_buff *skb,
if (ret < 0)
return ret;
}
+ if (info_mask & ETHTOOL_IM_SETTINGS_WOL) {
+ ret = settings_fill_wolinfo(skb, &data->wolinfo,
+ req_info->privileged);
+ if (ret < 0)
+ return ret;
+ }
return 0;
}
@@ -426,6 +485,7 @@ settings_set_policy[ETHTOOL_A_SETTINGS_MAX + 1] = {
[ETHTOOL_A_SETTINGS_LINK_INFO] = { .type = NLA_NESTED },
[ETHTOOL_A_SETTINGS_LINK_MODES] = { .type = NLA_NESTED },
[ETHTOOL_A_SETTINGS_LINK_STATE] = { .type = NLA_REJECT },
+ [ETHTOOL_A_SETTINGS_WOL] = { .type = NLA_REJECT },
};
static int ethnl_set_link_ksettings(struct genl_info *info,
--
2.22.0