1 // SPDX-License-Identifier: GPL-2.0-only
8 struct ethnl_req_info base
;
11 struct wol_reply_data
{
12 struct ethnl_reply_data base
;
13 struct ethtool_wolinfo wol
;
17 #define WOL_REPDATA(__reply_base) \
18 container_of(__reply_base, struct wol_reply_data, base)
20 const struct nla_policy ethnl_wol_get_policy
[] = {
21 [ETHTOOL_A_WOL_HEADER
] =
22 NLA_POLICY_NESTED(ethnl_header_policy
),
25 static int wol_prepare_data(const struct ethnl_req_info
*req_base
,
26 struct ethnl_reply_data
*reply_base
,
27 struct genl_info
*info
)
29 struct wol_reply_data
*data
= WOL_REPDATA(reply_base
);
30 struct net_device
*dev
= reply_base
->dev
;
33 if (!dev
->ethtool_ops
->get_wol
)
36 ret
= ethnl_ops_begin(dev
);
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
= info
&& (data
->wol
.supported
& WAKE_MAGICSECURE
);
47 static int wol_reply_size(const struct ethnl_req_info
*req_base
,
48 const struct ethnl_reply_data
*reply_base
)
50 bool compact
= req_base
->flags
& ETHTOOL_FLAG_COMPACT_BITSETS
;
51 const struct wol_reply_data
*data
= WOL_REPDATA(reply_base
);
54 len
= ethnl_bitset32_size(&data
->wol
.wolopts
, &data
->wol
.supported
,
55 WOL_MODE_COUNT
, wol_mode_names
, compact
);
58 if (data
->show_sopass
)
59 len
+= nla_total_size(sizeof(data
->wol
.sopass
));
64 static int wol_fill_reply(struct sk_buff
*skb
,
65 const struct ethnl_req_info
*req_base
,
66 const struct ethnl_reply_data
*reply_base
)
68 bool compact
= req_base
->flags
& ETHTOOL_FLAG_COMPACT_BITSETS
;
69 const struct wol_reply_data
*data
= WOL_REPDATA(reply_base
);
72 ret
= ethnl_put_bitset32(skb
, ETHTOOL_A_WOL_MODES
, &data
->wol
.wolopts
,
73 &data
->wol
.supported
, WOL_MODE_COUNT
,
74 wol_mode_names
, compact
);
77 if (data
->show_sopass
&&
78 nla_put(skb
, ETHTOOL_A_WOL_SOPASS
, sizeof(data
->wol
.sopass
),
85 const struct ethnl_request_ops ethnl_wol_request_ops
= {
86 .request_cmd
= ETHTOOL_MSG_WOL_GET
,
87 .reply_cmd
= ETHTOOL_MSG_WOL_GET_REPLY
,
88 .hdr_attr
= ETHTOOL_A_WOL_HEADER
,
89 .req_info_size
= sizeof(struct wol_req_info
),
90 .reply_data_size
= sizeof(struct wol_reply_data
),
92 .prepare_data
= wol_prepare_data
,
93 .reply_size
= wol_reply_size
,
94 .fill_reply
= wol_fill_reply
,
99 const struct nla_policy ethnl_wol_set_policy
[] = {
100 [ETHTOOL_A_WOL_HEADER
] =
101 NLA_POLICY_NESTED(ethnl_header_policy
),
102 [ETHTOOL_A_WOL_MODES
] = { .type
= NLA_NESTED
},
103 [ETHTOOL_A_WOL_SOPASS
] = { .type
= NLA_BINARY
,
107 int ethnl_set_wol(struct sk_buff
*skb
, struct genl_info
*info
)
109 struct ethtool_wolinfo wol
= { .cmd
= ETHTOOL_GWOL
};
110 struct ethnl_req_info req_info
= {};
111 struct nlattr
**tb
= info
->attrs
;
112 struct net_device
*dev
;
116 ret
= ethnl_parse_header_dev_get(&req_info
, tb
[ETHTOOL_A_WOL_HEADER
],
117 genl_info_net(info
), info
->extack
,
123 if (!dev
->ethtool_ops
->get_wol
|| !dev
->ethtool_ops
->set_wol
)
127 ret
= ethnl_ops_begin(dev
);
131 dev
->ethtool_ops
->get_wol(dev
, &wol
);
132 ret
= ethnl_update_bitset32(&wol
.wolopts
, WOL_MODE_COUNT
,
133 tb
[ETHTOOL_A_WOL_MODES
], wol_mode_names
,
137 if (wol
.wolopts
& ~wol
.supported
) {
138 NL_SET_ERR_MSG_ATTR(info
->extack
, tb
[ETHTOOL_A_WOL_MODES
],
139 "cannot enable unsupported WoL mode");
143 if (tb
[ETHTOOL_A_WOL_SOPASS
]) {
144 if (!(wol
.supported
& WAKE_MAGICSECURE
)) {
145 NL_SET_ERR_MSG_ATTR(info
->extack
,
146 tb
[ETHTOOL_A_WOL_SOPASS
],
147 "magicsecure not supported, cannot set password");
151 ethnl_update_binary(wol
.sopass
, sizeof(wol
.sopass
),
152 tb
[ETHTOOL_A_WOL_SOPASS
], &mod
);
157 ret
= dev
->ethtool_ops
->set_wol(dev
, &wol
);
160 dev
->wol_enabled
= !!wol
.wolopts
;
161 ethtool_notify(dev
, ETHTOOL_MSG_WOL_NTF
, NULL
);
164 ethnl_ops_complete(dev
);