Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/net/ethtool/wol.c
26278 views
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
const struct nla_policy ethnl_wol_get_policy[] = {
21
[ETHTOOL_A_WOL_HEADER] =
22
NLA_POLICY_NESTED(ethnl_header_policy),
23
};
24
25
static int wol_prepare_data(const struct ethnl_req_info *req_base,
26
struct ethnl_reply_data *reply_base,
27
const struct genl_info *info)
28
{
29
struct wol_reply_data *data = WOL_REPDATA(reply_base);
30
struct net_device *dev = reply_base->dev;
31
int ret;
32
33
if (!dev->ethtool_ops->get_wol)
34
return -EOPNOTSUPP;
35
36
ret = ethnl_ops_begin(dev);
37
if (ret < 0)
38
return ret;
39
dev->ethtool_ops->get_wol(dev, &data->wol);
40
ethnl_ops_complete(dev);
41
/* do not include password in notifications */
42
data->show_sopass = !genl_info_is_ntf(info) &&
43
(data->wol.supported & WAKE_MAGICSECURE);
44
45
return 0;
46
}
47
48
static int wol_reply_size(const struct ethnl_req_info *req_base,
49
const struct ethnl_reply_data *reply_base)
50
{
51
bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS;
52
const struct wol_reply_data *data = WOL_REPDATA(reply_base);
53
int len;
54
55
len = ethnl_bitset32_size(&data->wol.wolopts, &data->wol.supported,
56
WOL_MODE_COUNT, wol_mode_names, compact);
57
if (len < 0)
58
return len;
59
if (data->show_sopass)
60
len += nla_total_size(sizeof(data->wol.sopass));
61
62
return len;
63
}
64
65
static int wol_fill_reply(struct sk_buff *skb,
66
const struct ethnl_req_info *req_base,
67
const struct ethnl_reply_data *reply_base)
68
{
69
bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS;
70
const struct wol_reply_data *data = WOL_REPDATA(reply_base);
71
int ret;
72
73
ret = ethnl_put_bitset32(skb, ETHTOOL_A_WOL_MODES, &data->wol.wolopts,
74
&data->wol.supported, WOL_MODE_COUNT,
75
wol_mode_names, compact);
76
if (ret < 0)
77
return ret;
78
if (data->show_sopass &&
79
nla_put(skb, ETHTOOL_A_WOL_SOPASS, sizeof(data->wol.sopass),
80
data->wol.sopass))
81
return -EMSGSIZE;
82
83
return 0;
84
}
85
86
/* WOL_SET */
87
88
const struct nla_policy ethnl_wol_set_policy[] = {
89
[ETHTOOL_A_WOL_HEADER] =
90
NLA_POLICY_NESTED(ethnl_header_policy),
91
[ETHTOOL_A_WOL_MODES] = { .type = NLA_NESTED },
92
[ETHTOOL_A_WOL_SOPASS] = { .type = NLA_BINARY,
93
.len = SOPASS_MAX },
94
};
95
96
static int
97
ethnl_set_wol_validate(struct ethnl_req_info *req_info, struct genl_info *info)
98
{
99
const struct ethtool_ops *ops = req_info->dev->ethtool_ops;
100
101
return ops->get_wol && ops->set_wol ? 1 : -EOPNOTSUPP;
102
}
103
104
static int
105
ethnl_set_wol(struct ethnl_req_info *req_info, struct genl_info *info)
106
{
107
struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL };
108
struct net_device *dev = req_info->dev;
109
struct nlattr **tb = info->attrs;
110
bool mod = false;
111
int ret;
112
113
dev->ethtool_ops->get_wol(dev, &wol);
114
ret = ethnl_update_bitset32(&wol.wolopts, WOL_MODE_COUNT,
115
tb[ETHTOOL_A_WOL_MODES], wol_mode_names,
116
info->extack, &mod);
117
if (ret < 0)
118
return ret;
119
if (wol.wolopts & ~wol.supported) {
120
NL_SET_ERR_MSG_ATTR(info->extack, tb[ETHTOOL_A_WOL_MODES],
121
"cannot enable unsupported WoL mode");
122
return -EINVAL;
123
}
124
if (tb[ETHTOOL_A_WOL_SOPASS]) {
125
if (!(wol.supported & WAKE_MAGICSECURE)) {
126
NL_SET_ERR_MSG_ATTR(info->extack,
127
tb[ETHTOOL_A_WOL_SOPASS],
128
"magicsecure not supported, cannot set password");
129
return -EINVAL;
130
}
131
ethnl_update_binary(wol.sopass, sizeof(wol.sopass),
132
tb[ETHTOOL_A_WOL_SOPASS], &mod);
133
}
134
135
if (!mod)
136
return 0;
137
ret = dev->ethtool_ops->set_wol(dev, &wol);
138
if (ret)
139
return ret;
140
dev->ethtool->wol_enabled = !!wol.wolopts;
141
return 1;
142
}
143
144
const struct ethnl_request_ops ethnl_wol_request_ops = {
145
.request_cmd = ETHTOOL_MSG_WOL_GET,
146
.reply_cmd = ETHTOOL_MSG_WOL_GET_REPLY,
147
.hdr_attr = ETHTOOL_A_WOL_HEADER,
148
.req_info_size = sizeof(struct wol_req_info),
149
.reply_data_size = sizeof(struct wol_reply_data),
150
151
.prepare_data = wol_prepare_data,
152
.reply_size = wol_reply_size,
153
.fill_reply = wol_fill_reply,
154
155
.set_validate = ethnl_set_wol_validate,
156
.set = ethnl_set_wol,
157
.set_ntf_cmd = ETHTOOL_MSG_WOL_NTF,
158
};
159
160