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 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
},
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
)
32 struct wol_reply_data
*data
= WOL_REPDATA(reply_base
);
33 struct net_device
*dev
= reply_base
->dev
;
36 if (!dev
->ethtool_ops
->get_wol
)
39 ret
= ethnl_ops_begin(dev
);
42 dev
->ethtool_ops
->get_wol(dev
, &data
->wol
);
43 ethnl_ops_complete(dev
);
44 /* do not include password in notifications */
45 data
->show_sopass
= info
&& (data
->wol
.supported
& WAKE_MAGICSECURE
);
50 static int wol_reply_size(const struct ethnl_req_info
*req_base
,
51 const struct ethnl_reply_data
*reply_base
)
53 bool compact
= req_base
->flags
& ETHTOOL_FLAG_COMPACT_BITSETS
;
54 const struct wol_reply_data
*data
= WOL_REPDATA(reply_base
);
57 len
= ethnl_bitset32_size(&data
->wol
.wolopts
, &data
->wol
.supported
,
58 WOL_MODE_COUNT
, wol_mode_names
, compact
);
61 if (data
->show_sopass
)
62 len
+= nla_total_size(sizeof(data
->wol
.sopass
));
67 static int wol_fill_reply(struct sk_buff
*skb
,
68 const struct ethnl_req_info
*req_base
,
69 const struct ethnl_reply_data
*reply_base
)
71 bool compact
= req_base
->flags
& ETHTOOL_FLAG_COMPACT_BITSETS
;
72 const struct wol_reply_data
*data
= WOL_REPDATA(reply_base
);
75 ret
= ethnl_put_bitset32(skb
, ETHTOOL_A_WOL_MODES
, &data
->wol
.wolopts
,
76 &data
->wol
.supported
, WOL_MODE_COUNT
,
77 wol_mode_names
, compact
);
80 if (data
->show_sopass
&&
81 nla_put(skb
, ETHTOOL_A_WOL_SOPASS
, sizeof(data
->wol
.sopass
),
88 const struct ethnl_request_ops ethnl_wol_request_ops
= {
89 .request_cmd
= ETHTOOL_MSG_WOL_GET
,
90 .reply_cmd
= ETHTOOL_MSG_WOL_GET_REPLY
,
91 .hdr_attr
= ETHTOOL_A_WOL_HEADER
,
92 .max_attr
= ETHTOOL_A_WOL_MAX
,
93 .req_info_size
= sizeof(struct wol_req_info
),
94 .reply_data_size
= sizeof(struct wol_reply_data
),
95 .request_policy
= wol_get_policy
,
97 .prepare_data
= wol_prepare_data
,
98 .reply_size
= wol_reply_size
,
99 .fill_reply
= wol_fill_reply
,
104 static const struct nla_policy
105 wol_set_policy
[ETHTOOL_A_WOL_MAX
+ 1] = {
106 [ETHTOOL_A_WOL_UNSPEC
] = { .type
= NLA_REJECT
},
107 [ETHTOOL_A_WOL_HEADER
] = { .type
= NLA_NESTED
},
108 [ETHTOOL_A_WOL_MODES
] = { .type
= NLA_NESTED
},
109 [ETHTOOL_A_WOL_SOPASS
] = { .type
= NLA_BINARY
,
113 int ethnl_set_wol(struct sk_buff
*skb
, struct genl_info
*info
)
115 struct ethtool_wolinfo wol
= { .cmd
= ETHTOOL_GWOL
};
116 struct nlattr
*tb
[ETHTOOL_A_WOL_MAX
+ 1];
117 struct ethnl_req_info req_info
= {};
118 struct net_device
*dev
;
122 ret
= nlmsg_parse(info
->nlhdr
, GENL_HDRLEN
, tb
, ETHTOOL_A_WOL_MAX
,
123 wol_set_policy
, info
->extack
);
126 ret
= ethnl_parse_header_dev_get(&req_info
, tb
[ETHTOOL_A_WOL_HEADER
],
127 genl_info_net(info
), info
->extack
,
133 if (!dev
->ethtool_ops
->get_wol
|| !dev
->ethtool_ops
->set_wol
)
137 ret
= ethnl_ops_begin(dev
);
141 dev
->ethtool_ops
->get_wol(dev
, &wol
);
142 ret
= ethnl_update_bitset32(&wol
.wolopts
, WOL_MODE_COUNT
,
143 tb
[ETHTOOL_A_WOL_MODES
], wol_mode_names
,
147 if (wol
.wolopts
& ~wol
.supported
) {
148 NL_SET_ERR_MSG_ATTR(info
->extack
, tb
[ETHTOOL_A_WOL_MODES
],
149 "cannot enable unsupported WoL mode");
153 if (tb
[ETHTOOL_A_WOL_SOPASS
]) {
154 if (!(wol
.supported
& WAKE_MAGICSECURE
)) {
155 NL_SET_ERR_MSG_ATTR(info
->extack
,
156 tb
[ETHTOOL_A_WOL_SOPASS
],
157 "magicsecure not supported, cannot set password");
161 ethnl_update_binary(wol
.sopass
, sizeof(wol
.sopass
),
162 tb
[ETHTOOL_A_WOL_SOPASS
], &mod
);
167 ret
= dev
->ethtool_ops
->set_wol(dev
, &wol
);
170 dev
->wol_enabled
= !!wol
.wolopts
;
171 ethtool_notify(dev
, ETHTOOL_MSG_WOL_NTF
, NULL
);
174 ethnl_ops_complete(dev
);