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
),
87 const struct nla_policy ethnl_wol_set_policy
[] = {
88 [ETHTOOL_A_WOL_HEADER
] =
89 NLA_POLICY_NESTED(ethnl_header_policy
),
90 [ETHTOOL_A_WOL_MODES
] = { .type
= NLA_NESTED
},
91 [ETHTOOL_A_WOL_SOPASS
] = { .type
= NLA_BINARY
,
96 ethnl_set_wol_validate(struct ethnl_req_info
*req_info
, struct genl_info
*info
)
98 const struct ethtool_ops
*ops
= req_info
->dev
->ethtool_ops
;
100 return ops
->get_wol
&& ops
->set_wol
? 1 : -EOPNOTSUPP
;
104 ethnl_set_wol(struct ethnl_req_info
*req_info
, struct genl_info
*info
)
106 struct ethtool_wolinfo wol
= { .cmd
= ETHTOOL_GWOL
};
107 struct net_device
*dev
= req_info
->dev
;
108 struct nlattr
**tb
= info
->attrs
;
112 dev
->ethtool_ops
->get_wol(dev
, &wol
);
113 ret
= ethnl_update_bitset32(&wol
.wolopts
, WOL_MODE_COUNT
,
114 tb
[ETHTOOL_A_WOL_MODES
], wol_mode_names
,
118 if (wol
.wolopts
& ~wol
.supported
) {
119 NL_SET_ERR_MSG_ATTR(info
->extack
, tb
[ETHTOOL_A_WOL_MODES
],
120 "cannot enable unsupported WoL mode");
123 if (tb
[ETHTOOL_A_WOL_SOPASS
]) {
124 if (!(wol
.supported
& WAKE_MAGICSECURE
)) {
125 NL_SET_ERR_MSG_ATTR(info
->extack
,
126 tb
[ETHTOOL_A_WOL_SOPASS
],
127 "magicsecure not supported, cannot set password");
130 ethnl_update_binary(wol
.sopass
, sizeof(wol
.sopass
),
131 tb
[ETHTOOL_A_WOL_SOPASS
], &mod
);
136 ret
= dev
->ethtool_ops
->set_wol(dev
, &wol
);
139 dev
->wol_enabled
= !!wol
.wolopts
;
143 const struct ethnl_request_ops ethnl_wol_request_ops
= {
144 .request_cmd
= ETHTOOL_MSG_WOL_GET
,
145 .reply_cmd
= ETHTOOL_MSG_WOL_GET_REPLY
,
146 .hdr_attr
= ETHTOOL_A_WOL_HEADER
,
147 .req_info_size
= sizeof(struct wol_req_info
),
148 .reply_data_size
= sizeof(struct wol_reply_data
),
150 .prepare_data
= wol_prepare_data
,
151 .reply_size
= wol_reply_size
,
152 .fill_reply
= wol_fill_reply
,
154 .set_validate
= ethnl_set_wol_validate
,
155 .set
= ethnl_set_wol
,
156 .set_ntf_cmd
= ETHTOOL_MSG_WOL_NTF
,