Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0-only
2
3#include <net/netdev_lock.h>
4#include <net/netdev_queues.h>
5#include <net/sock.h>
6#include <linux/ethtool_netlink.h>
7#include <linux/phy_link_topology.h>
8#include <linux/pm_runtime.h>
9
10#include "module_fw.h"
11#include "netlink.h"
12
13static struct genl_family ethtool_genl_family;
14
15static bool ethnl_ok __read_mostly;
16static u32 ethnl_bcast_seq;
17
18#define ETHTOOL_FLAGS_BASIC (ETHTOOL_FLAG_COMPACT_BITSETS | \
19 ETHTOOL_FLAG_OMIT_REPLY)
20#define ETHTOOL_FLAGS_STATS (ETHTOOL_FLAGS_BASIC | ETHTOOL_FLAG_STATS)
21
22const struct nla_policy ethnl_header_policy[] = {
23 [ETHTOOL_A_HEADER_DEV_INDEX] = { .type = NLA_U32 },
24 [ETHTOOL_A_HEADER_DEV_NAME] = { .type = NLA_NUL_STRING,
25 .len = ALTIFNAMSIZ - 1 },
26 [ETHTOOL_A_HEADER_FLAGS] = NLA_POLICY_MASK(NLA_U32,
27 ETHTOOL_FLAGS_BASIC),
28};
29
30const struct nla_policy ethnl_header_policy_stats[] = {
31 [ETHTOOL_A_HEADER_DEV_INDEX] = { .type = NLA_U32 },
32 [ETHTOOL_A_HEADER_DEV_NAME] = { .type = NLA_NUL_STRING,
33 .len = ALTIFNAMSIZ - 1 },
34 [ETHTOOL_A_HEADER_FLAGS] = NLA_POLICY_MASK(NLA_U32,
35 ETHTOOL_FLAGS_STATS),
36};
37
38const struct nla_policy ethnl_header_policy_phy[] = {
39 [ETHTOOL_A_HEADER_DEV_INDEX] = { .type = NLA_U32 },
40 [ETHTOOL_A_HEADER_DEV_NAME] = { .type = NLA_NUL_STRING,
41 .len = ALTIFNAMSIZ - 1 },
42 [ETHTOOL_A_HEADER_FLAGS] = NLA_POLICY_MASK(NLA_U32,
43 ETHTOOL_FLAGS_BASIC),
44 [ETHTOOL_A_HEADER_PHY_INDEX] = NLA_POLICY_MIN(NLA_U32, 1),
45};
46
47const struct nla_policy ethnl_header_policy_phy_stats[] = {
48 [ETHTOOL_A_HEADER_DEV_INDEX] = { .type = NLA_U32 },
49 [ETHTOOL_A_HEADER_DEV_NAME] = { .type = NLA_NUL_STRING,
50 .len = ALTIFNAMSIZ - 1 },
51 [ETHTOOL_A_HEADER_FLAGS] = NLA_POLICY_MASK(NLA_U32,
52 ETHTOOL_FLAGS_STATS),
53 [ETHTOOL_A_HEADER_PHY_INDEX] = NLA_POLICY_MIN(NLA_U32, 1),
54};
55
56int ethnl_sock_priv_set(struct sk_buff *skb, struct net_device *dev, u32 portid,
57 enum ethnl_sock_type type)
58{
59 struct ethnl_sock_priv *sk_priv;
60
61 sk_priv = genl_sk_priv_get(ðtool_genl_family, NETLINK_CB(skb).sk);
62 if (IS_ERR(sk_priv))
63 return PTR_ERR(sk_priv);
64
65 sk_priv->dev = dev;
66 sk_priv->portid = portid;
67 sk_priv->type = type;
68
69 return 0;
70}
71
72static void ethnl_sock_priv_destroy(void *priv)
73{
74 struct ethnl_sock_priv *sk_priv = priv;
75
76 switch (sk_priv->type) {
77 case ETHTOOL_SOCK_TYPE_MODULE_FW_FLASH:
78 ethnl_module_fw_flash_sock_destroy(sk_priv);
79 break;
80 default:
81 break;
82 }
83}
84
85u32 ethnl_bcast_seq_next(void)
86{
87 ASSERT_RTNL();
88 return ++ethnl_bcast_seq;
89}
90
91int ethnl_ops_begin(struct net_device *dev)
92{
93 int ret;
94
95 if (!dev)
96 return -ENODEV;
97
98 if (dev->dev.parent)
99 pm_runtime_get_sync(dev->dev.parent);
100
101 netdev_ops_assert_locked(dev);
102
103 if (!netif_device_present(dev) ||
104 dev->reg_state >= NETREG_UNREGISTERING) {
105 ret = -ENODEV;
106 goto err;
107 }
108
109 if (dev->ethtool_ops->begin) {
110 ret = dev->ethtool_ops->begin(dev);
111 if (ret)
112 goto err;
113 }
114
115 return 0;
116err:
117 if (dev->dev.parent)
118 pm_runtime_put(dev->dev.parent);
119
120 return ret;
121}
122
123void ethnl_ops_complete(struct net_device *dev)
124{
125 if (dev->ethtool_ops->complete)
126 dev->ethtool_ops->complete(dev);
127
128 if (dev->dev.parent)
129 pm_runtime_put(dev->dev.parent);
130}
131
132/**
133 * ethnl_parse_header_dev_get() - parse request header
134 * @req_info: structure to put results into
135 * @header: nest attribute with request header
136 * @net: request netns
137 * @extack: netlink extack for error reporting
138 * @require_dev: fail if no device identified in header
139 *
140 * Parse request header in nested attribute @nest and puts results into
141 * the structure pointed to by @req_info. Extack from @info is used for error
142 * reporting. If req_info->dev is not null on return, reference to it has
143 * been taken. If error is returned, *req_info is null initialized and no
144 * reference is held.
145 *
146 * Return: 0 on success or negative error code
147 */
148int ethnl_parse_header_dev_get(struct ethnl_req_info *req_info,
149 const struct nlattr *header, struct net *net,
150 struct netlink_ext_ack *extack, bool require_dev)
151{
152 struct nlattr *tb[ARRAY_SIZE(ethnl_header_policy_phy)];
153 const struct nlattr *devname_attr;
154 struct net_device *dev = NULL;
155 u32 flags = 0;
156 int ret;
157
158 if (!header) {
159 if (!require_dev)
160 return 0;
161 NL_SET_ERR_MSG(extack, "request header missing");
162 return -EINVAL;
163 }
164 /* No validation here, command policy should have a nested policy set
165 * for the header, therefore validation should have already been done.
166 */
167 ret = nla_parse_nested(tb, ARRAY_SIZE(ethnl_header_policy_phy) - 1, header,
168 NULL, extack);
169 if (ret < 0)
170 return ret;
171 if (tb[ETHTOOL_A_HEADER_FLAGS])
172 flags = nla_get_u32(tb[ETHTOOL_A_HEADER_FLAGS]);
173
174 devname_attr = tb[ETHTOOL_A_HEADER_DEV_NAME];
175 if (tb[ETHTOOL_A_HEADER_DEV_INDEX]) {
176 u32 ifindex = nla_get_u32(tb[ETHTOOL_A_HEADER_DEV_INDEX]);
177
178 dev = netdev_get_by_index(net, ifindex, &req_info->dev_tracker,
179 GFP_KERNEL);
180 if (!dev) {
181 NL_SET_ERR_MSG_ATTR(extack,
182 tb[ETHTOOL_A_HEADER_DEV_INDEX],
183 "no device matches ifindex");
184 return -ENODEV;
185 }
186 /* if both ifindex and ifname are passed, they must match */
187 if (devname_attr &&
188 strncmp(dev->name, nla_data(devname_attr), IFNAMSIZ)) {
189 netdev_put(dev, &req_info->dev_tracker);
190 NL_SET_ERR_MSG_ATTR(extack, header,
191 "ifindex and name do not match");
192 return -ENODEV;
193 }
194 } else if (devname_attr) {
195 dev = netdev_get_by_name(net, nla_data(devname_attr),
196 &req_info->dev_tracker, GFP_KERNEL);
197 if (!dev) {
198 NL_SET_ERR_MSG_ATTR(extack, devname_attr,
199 "no device matches name");
200 return -ENODEV;
201 }
202 } else if (require_dev) {
203 NL_SET_ERR_MSG_ATTR(extack, header,
204 "neither ifindex nor name specified");
205 return -EINVAL;
206 }
207
208 if (tb[ETHTOOL_A_HEADER_PHY_INDEX]) {
209 if (dev) {
210 req_info->phy_index = nla_get_u32(tb[ETHTOOL_A_HEADER_PHY_INDEX]);
211 } else {
212 NL_SET_ERR_MSG_ATTR(extack, header,
213 "phy_index set without a netdev");
214 return -EINVAL;
215 }
216 }
217
218 req_info->dev = dev;
219 req_info->flags = flags;
220 return 0;
221}
222
223struct phy_device *ethnl_req_get_phydev(const struct ethnl_req_info *req_info,
224 struct nlattr **tb, unsigned int header,
225 struct netlink_ext_ack *extack)
226{
227 struct phy_device *phydev;
228
229 ASSERT_RTNL();
230
231 if (!req_info->dev)
232 return NULL;
233
234 if (!req_info->phy_index)
235 return req_info->dev->phydev;
236
237 phydev = phy_link_topo_get_phy(req_info->dev, req_info->phy_index);
238 if (!phydev && tb) {
239 NL_SET_ERR_MSG_ATTR(extack, tb[header],
240 "no phy matching phyindex");
241 return ERR_PTR(-ENODEV);
242 }
243
244 return phydev;
245}
246
247/**
248 * ethnl_fill_reply_header() - Put common header into a reply message
249 * @skb: skb with the message
250 * @dev: network device to describe in header
251 * @attrtype: attribute type to use for the nest
252 *
253 * Create a nested attribute with attributes describing given network device.
254 *
255 * Return: 0 on success, error value (-EMSGSIZE only) on error
256 */
257int ethnl_fill_reply_header(struct sk_buff *skb, struct net_device *dev,
258 u16 attrtype)
259{
260 struct nlattr *nest;
261
262 if (!dev)
263 return 0;
264 nest = nla_nest_start(skb, attrtype);
265 if (!nest)
266 return -EMSGSIZE;
267
268 if (nla_put_u32(skb, ETHTOOL_A_HEADER_DEV_INDEX, (u32)dev->ifindex) ||
269 nla_put_string(skb, ETHTOOL_A_HEADER_DEV_NAME, dev->name))
270 goto nla_put_failure;
271 /* If more attributes are put into reply header, ethnl_header_size()
272 * must be updated to account for them.
273 */
274
275 nla_nest_end(skb, nest);
276 return 0;
277
278nla_put_failure:
279 nla_nest_cancel(skb, nest);
280 return -EMSGSIZE;
281}
282
283/**
284 * ethnl_reply_init() - Create skb for a reply and fill device identification
285 * @payload: payload length (without netlink and genetlink header)
286 * @dev: device the reply is about (may be null)
287 * @cmd: ETHTOOL_MSG_* message type for reply
288 * @hdr_attrtype: attribute type for common header
289 * @info: genetlink info of the received packet we respond to
290 * @ehdrp: place to store payload pointer returned by genlmsg_new()
291 *
292 * Return: pointer to allocated skb on success, NULL on error
293 */
294struct sk_buff *ethnl_reply_init(size_t payload, struct net_device *dev, u8 cmd,
295 u16 hdr_attrtype, struct genl_info *info,
296 void **ehdrp)
297{
298 struct sk_buff *skb;
299
300 skb = genlmsg_new(payload, GFP_KERNEL);
301 if (!skb)
302 goto err;
303 *ehdrp = genlmsg_put_reply(skb, info, ðtool_genl_family, 0, cmd);
304 if (!*ehdrp)
305 goto err_free;
306
307 if (dev) {
308 int ret;
309
310 ret = ethnl_fill_reply_header(skb, dev, hdr_attrtype);
311 if (ret < 0)
312 goto err_free;
313 }
314 return skb;
315
316err_free:
317 nlmsg_free(skb);
318err:
319 if (info)
320 GENL_SET_ERR_MSG(info, "failed to setup reply message");
321 return NULL;
322}
323
324void *ethnl_dump_put(struct sk_buff *skb, struct netlink_callback *cb, u8 cmd)
325{
326 return genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
327 ðtool_genl_family, 0, cmd);
328}
329
330void *ethnl_bcastmsg_put(struct sk_buff *skb, u8 cmd)
331{
332 return genlmsg_put(skb, 0, ++ethnl_bcast_seq, ðtool_genl_family, 0,
333 cmd);
334}
335
336void *ethnl_unicast_put(struct sk_buff *skb, u32 portid, u32 seq, u8 cmd)
337{
338 return genlmsg_put(skb, portid, seq, ðtool_genl_family, 0, cmd);
339}
340
341int ethnl_multicast(struct sk_buff *skb, struct net_device *dev)
342{
343 return genlmsg_multicast_netns(ðtool_genl_family, dev_net(dev), skb,
344 0, ETHNL_MCGRP_MONITOR, GFP_KERNEL);
345}
346
347/* GET request helpers */
348
349/**
350 * struct ethnl_dump_ctx - context structure for generic dumpit() callback
351 * @ops: request ops of currently processed message type
352 * @req_info: parsed request header of processed request
353 * @reply_data: data needed to compose the reply
354 * @pos_ifindex: saved iteration position - ifindex
355 *
356 * These parameters are kept in struct netlink_callback as context preserved
357 * between iterations. They are initialized by ethnl_default_start() and used
358 * in ethnl_default_dumpit() and ethnl_default_done().
359 */
360struct ethnl_dump_ctx {
361 const struct ethnl_request_ops *ops;
362 struct ethnl_req_info *req_info;
363 struct ethnl_reply_data *reply_data;
364 unsigned long pos_ifindex;
365};
366
367/**
368 * struct ethnl_perphy_dump_ctx - context for dumpit() PHY-aware callbacks
369 * @ethnl_ctx: generic ethnl context
370 * @ifindex: For Filtered DUMP requests, the ifindex of the targeted netdev
371 * @pos_phyindex: iterator position for multi-msg DUMP
372 */
373struct ethnl_perphy_dump_ctx {
374 struct ethnl_dump_ctx ethnl_ctx;
375 unsigned int ifindex;
376 unsigned long pos_phyindex;
377};
378
379static const struct ethnl_request_ops *
380ethnl_default_requests[__ETHTOOL_MSG_USER_CNT] = {
381 [ETHTOOL_MSG_STRSET_GET] = ðnl_strset_request_ops,
382 [ETHTOOL_MSG_LINKINFO_GET] = ðnl_linkinfo_request_ops,
383 [ETHTOOL_MSG_LINKINFO_SET] = ðnl_linkinfo_request_ops,
384 [ETHTOOL_MSG_LINKMODES_GET] = ðnl_linkmodes_request_ops,
385 [ETHTOOL_MSG_LINKMODES_SET] = ðnl_linkmodes_request_ops,
386 [ETHTOOL_MSG_LINKSTATE_GET] = ðnl_linkstate_request_ops,
387 [ETHTOOL_MSG_DEBUG_GET] = ðnl_debug_request_ops,
388 [ETHTOOL_MSG_DEBUG_SET] = ðnl_debug_request_ops,
389 [ETHTOOL_MSG_WOL_GET] = ðnl_wol_request_ops,
390 [ETHTOOL_MSG_WOL_SET] = ðnl_wol_request_ops,
391 [ETHTOOL_MSG_FEATURES_GET] = ðnl_features_request_ops,
392 [ETHTOOL_MSG_PRIVFLAGS_GET] = ðnl_privflags_request_ops,
393 [ETHTOOL_MSG_PRIVFLAGS_SET] = ðnl_privflags_request_ops,
394 [ETHTOOL_MSG_RINGS_GET] = ðnl_rings_request_ops,
395 [ETHTOOL_MSG_RINGS_SET] = ðnl_rings_request_ops,
396 [ETHTOOL_MSG_CHANNELS_GET] = ðnl_channels_request_ops,
397 [ETHTOOL_MSG_CHANNELS_SET] = ðnl_channels_request_ops,
398 [ETHTOOL_MSG_COALESCE_GET] = ðnl_coalesce_request_ops,
399 [ETHTOOL_MSG_COALESCE_SET] = ðnl_coalesce_request_ops,
400 [ETHTOOL_MSG_PAUSE_GET] = ðnl_pause_request_ops,
401 [ETHTOOL_MSG_PAUSE_SET] = ðnl_pause_request_ops,
402 [ETHTOOL_MSG_EEE_GET] = ðnl_eee_request_ops,
403 [ETHTOOL_MSG_EEE_SET] = ðnl_eee_request_ops,
404 [ETHTOOL_MSG_FEC_GET] = ðnl_fec_request_ops,
405 [ETHTOOL_MSG_FEC_SET] = ðnl_fec_request_ops,
406 [ETHTOOL_MSG_TSINFO_GET] = ðnl_tsinfo_request_ops,
407 [ETHTOOL_MSG_MODULE_EEPROM_GET] = ðnl_module_eeprom_request_ops,
408 [ETHTOOL_MSG_STATS_GET] = ðnl_stats_request_ops,
409 [ETHTOOL_MSG_PHC_VCLOCKS_GET] = ðnl_phc_vclocks_request_ops,
410 [ETHTOOL_MSG_MODULE_GET] = ðnl_module_request_ops,
411 [ETHTOOL_MSG_MODULE_SET] = ðnl_module_request_ops,
412 [ETHTOOL_MSG_PSE_GET] = ðnl_pse_request_ops,
413 [ETHTOOL_MSG_PSE_SET] = ðnl_pse_request_ops,
414 [ETHTOOL_MSG_RSS_GET] = ðnl_rss_request_ops,
415 [ETHTOOL_MSG_RSS_SET] = ðnl_rss_request_ops,
416 [ETHTOOL_MSG_PLCA_GET_CFG] = ðnl_plca_cfg_request_ops,
417 [ETHTOOL_MSG_PLCA_SET_CFG] = ðnl_plca_cfg_request_ops,
418 [ETHTOOL_MSG_PLCA_GET_STATUS] = ðnl_plca_status_request_ops,
419 [ETHTOOL_MSG_MM_GET] = ðnl_mm_request_ops,
420 [ETHTOOL_MSG_MM_SET] = ðnl_mm_request_ops,
421 [ETHTOOL_MSG_TSCONFIG_GET] = ðnl_tsconfig_request_ops,
422 [ETHTOOL_MSG_TSCONFIG_SET] = ðnl_tsconfig_request_ops,
423 [ETHTOOL_MSG_PHY_GET] = ðnl_phy_request_ops,
424 [ETHTOOL_MSG_MSE_GET] = ðnl_mse_request_ops,
425};
426
427static struct ethnl_dump_ctx *ethnl_dump_context(struct netlink_callback *cb)
428{
429 return (struct ethnl_dump_ctx *)cb->ctx;
430}
431
432static struct ethnl_perphy_dump_ctx *
433ethnl_perphy_dump_context(struct netlink_callback *cb)
434{
435 return (struct ethnl_perphy_dump_ctx *)cb->ctx;
436}
437
438/**
439 * ethnl_default_parse() - Parse request message
440 * @req_info: pointer to structure to put data into
441 * @info: genl_info from the request
442 * @request_ops: struct request_ops for request type
443 * @require_dev: fail if no device identified in header
444 *
445 * Parse universal request header and call request specific ->parse_request()
446 * callback (if defined) to parse the rest of the message.
447 *
448 * Return: 0 on success or negative error code
449 */
450static int ethnl_default_parse(struct ethnl_req_info *req_info,
451 const struct genl_info *info,
452 const struct ethnl_request_ops *request_ops,
453 bool require_dev)
454{
455 struct nlattr **tb = info->attrs;
456 int ret;
457
458 ret = ethnl_parse_header_dev_get(req_info, tb[request_ops->hdr_attr],
459 genl_info_net(info), info->extack,
460 require_dev);
461 if (ret < 0)
462 return ret;
463
464 if (request_ops->parse_request) {
465 ret = request_ops->parse_request(req_info, info, tb,
466 info->extack);
467 if (ret < 0)
468 goto err_dev;
469 }
470
471 return 0;
472
473err_dev:
474 netdev_put(req_info->dev, &req_info->dev_tracker);
475 req_info->dev = NULL;
476 return ret;
477}
478
479/**
480 * ethnl_init_reply_data() - Initialize reply data for GET request
481 * @reply_data: pointer to embedded struct ethnl_reply_data
482 * @ops: instance of struct ethnl_request_ops describing the layout
483 * @dev: network device to initialize the reply for
484 *
485 * Fills the reply data part with zeros and sets the dev member. Must be called
486 * before calling the ->fill_reply() callback (for each iteration when handling
487 * dump requests).
488 */
489static void ethnl_init_reply_data(struct ethnl_reply_data *reply_data,
490 const struct ethnl_request_ops *ops,
491 struct net_device *dev)
492{
493 memset(reply_data, 0, ops->reply_data_size);
494 reply_data->dev = dev;
495}
496
497/* default ->doit() handler for GET type requests */
498static int ethnl_default_doit(struct sk_buff *skb, struct genl_info *info)
499{
500 struct ethnl_reply_data *reply_data = NULL;
501 struct ethnl_req_info *req_info = NULL;
502 const u8 cmd = info->genlhdr->cmd;
503 const struct ethnl_request_ops *ops;
504 int hdr_len, reply_len;
505 struct sk_buff *rskb;
506 void *reply_payload;
507 int ret;
508
509 ops = ethnl_default_requests[cmd];
510 if (WARN_ONCE(!ops, "cmd %u has no ethnl_request_ops\n", cmd))
511 return -EOPNOTSUPP;
512 if (GENL_REQ_ATTR_CHECK(info, ops->hdr_attr))
513 return -EINVAL;
514
515 req_info = kzalloc(ops->req_info_size, GFP_KERNEL);
516 if (!req_info)
517 return -ENOMEM;
518 reply_data = kmalloc(ops->reply_data_size, GFP_KERNEL);
519 if (!reply_data) {
520 kfree(req_info);
521 return -ENOMEM;
522 }
523
524 ret = ethnl_default_parse(req_info, info, ops, !ops->allow_nodev_do);
525 if (ret < 0)
526 goto err_free;
527 ethnl_init_reply_data(reply_data, ops, req_info->dev);
528
529 rtnl_lock();
530 if (req_info->dev)
531 netdev_lock_ops(req_info->dev);
532 ret = ops->prepare_data(req_info, reply_data, info);
533 if (req_info->dev)
534 netdev_unlock_ops(req_info->dev);
535 rtnl_unlock();
536 if (ret < 0)
537 goto err_dev;
538 ret = ops->reply_size(req_info, reply_data);
539 if (ret < 0)
540 goto err_cleanup;
541 reply_len = ret;
542 ret = -ENOMEM;
543 rskb = ethnl_reply_init(reply_len + ethnl_reply_header_size(),
544 req_info->dev, ops->reply_cmd,
545 ops->hdr_attr, info, &reply_payload);
546 if (!rskb)
547 goto err_cleanup;
548 hdr_len = rskb->len;
549 ret = ops->fill_reply(rskb, req_info, reply_data);
550 if (ret < 0)
551 goto err_msg;
552 WARN_ONCE(rskb->len - hdr_len > reply_len,
553 "ethnl cmd %d: calculated reply length %d, but consumed %d\n",
554 cmd, reply_len, rskb->len - hdr_len);
555 if (ops->cleanup_data)
556 ops->cleanup_data(reply_data);
557
558 genlmsg_end(rskb, reply_payload);
559 netdev_put(req_info->dev, &req_info->dev_tracker);
560 kfree(reply_data);
561 kfree(req_info);
562 return genlmsg_reply(rskb, info);
563
564err_msg:
565 WARN_ONCE(ret == -EMSGSIZE, "calculated message payload length (%d) not sufficient\n", reply_len);
566 nlmsg_free(rskb);
567err_cleanup:
568 if (ops->cleanup_data)
569 ops->cleanup_data(reply_data);
570err_dev:
571 netdev_put(req_info->dev, &req_info->dev_tracker);
572err_free:
573 kfree(reply_data);
574 kfree(req_info);
575 return ret;
576}
577
578static int ethnl_default_dump_one(struct sk_buff *skb, struct net_device *dev,
579 const struct ethnl_dump_ctx *ctx,
580 const struct genl_info *info)
581{
582 void *ehdr;
583 int ret;
584
585 ehdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
586 ðtool_genl_family, NLM_F_MULTI,
587 ctx->ops->reply_cmd);
588 if (!ehdr)
589 return -EMSGSIZE;
590
591 ethnl_init_reply_data(ctx->reply_data, ctx->ops, dev);
592 rtnl_lock();
593 netdev_lock_ops(dev);
594 ret = ctx->ops->prepare_data(ctx->req_info, ctx->reply_data, info);
595 netdev_unlock_ops(dev);
596 rtnl_unlock();
597 if (ret < 0)
598 goto out_cancel;
599 ret = ethnl_fill_reply_header(skb, dev, ctx->ops->hdr_attr);
600 if (ret < 0)
601 goto out;
602 ret = ctx->ops->fill_reply(skb, ctx->req_info, ctx->reply_data);
603
604out:
605 if (ctx->ops->cleanup_data)
606 ctx->ops->cleanup_data(ctx->reply_data);
607out_cancel:
608 ctx->reply_data->dev = NULL;
609 if (ret < 0)
610 genlmsg_cancel(skb, ehdr);
611 else
612 genlmsg_end(skb, ehdr);
613 return ret;
614}
615
616/* Default ->dumpit() handler for GET requests. */
617static int ethnl_default_dumpit(struct sk_buff *skb,
618 struct netlink_callback *cb)
619{
620 struct ethnl_dump_ctx *ctx = ethnl_dump_context(cb);
621 struct net *net = sock_net(skb->sk);
622 netdevice_tracker dev_tracker;
623 struct net_device *dev;
624 int ret = 0;
625
626 rcu_read_lock();
627 for_each_netdev_dump(net, dev, ctx->pos_ifindex) {
628 netdev_hold(dev, &dev_tracker, GFP_ATOMIC);
629 rcu_read_unlock();
630
631 ret = ethnl_default_dump_one(skb, dev, ctx, genl_info_dump(cb));
632
633 rcu_read_lock();
634 netdev_put(dev, &dev_tracker);
635
636 if (ret < 0 && ret != -EOPNOTSUPP) {
637 if (likely(skb->len))
638 ret = skb->len;
639 break;
640 }
641 ret = 0;
642 }
643 rcu_read_unlock();
644
645 return ret;
646}
647
648/* generic ->start() handler for GET requests */
649static int ethnl_default_start(struct netlink_callback *cb)
650{
651 const struct genl_dumpit_info *info = genl_dumpit_info(cb);
652 struct ethnl_dump_ctx *ctx = ethnl_dump_context(cb);
653 struct ethnl_reply_data *reply_data;
654 const struct ethnl_request_ops *ops;
655 struct ethnl_req_info *req_info;
656 struct genlmsghdr *ghdr;
657 int ret;
658
659 BUILD_BUG_ON(sizeof(*ctx) > sizeof(cb->ctx));
660
661 ghdr = nlmsg_data(cb->nlh);
662 ops = ethnl_default_requests[ghdr->cmd];
663 if (WARN_ONCE(!ops, "cmd %u has no ethnl_request_ops\n", ghdr->cmd))
664 return -EOPNOTSUPP;
665 req_info = kzalloc(ops->req_info_size, GFP_KERNEL);
666 if (!req_info)
667 return -ENOMEM;
668 reply_data = kmalloc(ops->reply_data_size, GFP_KERNEL);
669 if (!reply_data) {
670 ret = -ENOMEM;
671 goto free_req_info;
672 }
673
674 ret = ethnl_default_parse(req_info, &info->info, ops, false);
675 if (ret < 0)
676 goto free_reply_data;
677 if (req_info->dev) {
678 /* We ignore device specification in dump requests but as the
679 * same parser as for non-dump (doit) requests is used, it
680 * would take reference to the device if it finds one
681 */
682 netdev_put(req_info->dev, &req_info->dev_tracker);
683 req_info->dev = NULL;
684 }
685
686 ctx->ops = ops;
687 ctx->req_info = req_info;
688 ctx->reply_data = reply_data;
689 ctx->pos_ifindex = 0;
690
691 return 0;
692
693free_reply_data:
694 kfree(reply_data);
695free_req_info:
696 kfree(req_info);
697
698 return ret;
699}
700
701/* per-PHY ->start() handler for GET requests */
702static int ethnl_perphy_start(struct netlink_callback *cb)
703{
704 struct ethnl_perphy_dump_ctx *phy_ctx = ethnl_perphy_dump_context(cb);
705 const struct genl_dumpit_info *info = genl_dumpit_info(cb);
706 struct ethnl_dump_ctx *ctx = &phy_ctx->ethnl_ctx;
707 struct ethnl_reply_data *reply_data;
708 const struct ethnl_request_ops *ops;
709 struct ethnl_req_info *req_info;
710 struct genlmsghdr *ghdr;
711 int ret;
712
713 BUILD_BUG_ON(sizeof(*ctx) > sizeof(cb->ctx));
714
715 ghdr = nlmsg_data(cb->nlh);
716 ops = ethnl_default_requests[ghdr->cmd];
717 if (WARN_ONCE(!ops, "cmd %u has no ethnl_request_ops\n", ghdr->cmd))
718 return -EOPNOTSUPP;
719 req_info = kzalloc(ops->req_info_size, GFP_KERNEL);
720 if (!req_info)
721 return -ENOMEM;
722 reply_data = kmalloc(ops->reply_data_size, GFP_KERNEL);
723 if (!reply_data) {
724 ret = -ENOMEM;
725 goto free_req_info;
726 }
727
728 /* Unlike per-dev dump, don't ignore dev. The dump handler
729 * will notice it and dump PHYs from given dev. We only keep track of
730 * the dev's ifindex, .dumpit() will grab and release the netdev itself.
731 */
732 ret = ethnl_default_parse(req_info, &info->info, ops, false);
733 if (ret < 0)
734 goto free_reply_data;
735 if (req_info->dev) {
736 phy_ctx->ifindex = req_info->dev->ifindex;
737 netdev_put(req_info->dev, &req_info->dev_tracker);
738 req_info->dev = NULL;
739 }
740
741 ctx->ops = ops;
742 ctx->req_info = req_info;
743 ctx->reply_data = reply_data;
744 ctx->pos_ifindex = 0;
745
746 return 0;
747
748free_reply_data:
749 kfree(reply_data);
750free_req_info:
751 kfree(req_info);
752
753 return ret;
754}
755
756static int ethnl_perphy_dump_one_dev(struct sk_buff *skb,
757 struct ethnl_perphy_dump_ctx *ctx,
758 const struct genl_info *info)
759{
760 struct ethnl_dump_ctx *ethnl_ctx = &ctx->ethnl_ctx;
761 struct net_device *dev = ethnl_ctx->req_info->dev;
762 struct phy_device_node *pdn;
763 int ret;
764
765 if (!dev->link_topo)
766 return 0;
767
768 xa_for_each_start(&dev->link_topo->phys, ctx->pos_phyindex, pdn,
769 ctx->pos_phyindex) {
770 ethnl_ctx->req_info->phy_index = ctx->pos_phyindex;
771
772 /* We can re-use the original dump_one as ->prepare_data in
773 * commands use ethnl_req_get_phydev(), which gets the PHY from
774 * the req_info->phy_index
775 */
776 ret = ethnl_default_dump_one(skb, dev, ethnl_ctx, info);
777 if (ret)
778 return ret;
779 }
780
781 ctx->pos_phyindex = 0;
782
783 return 0;
784}
785
786static int ethnl_perphy_dump_all_dev(struct sk_buff *skb,
787 struct ethnl_perphy_dump_ctx *ctx,
788 const struct genl_info *info)
789{
790 struct ethnl_dump_ctx *ethnl_ctx = &ctx->ethnl_ctx;
791 struct net *net = sock_net(skb->sk);
792 netdevice_tracker dev_tracker;
793 struct net_device *dev;
794 int ret = 0;
795
796 rcu_read_lock();
797 for_each_netdev_dump(net, dev, ethnl_ctx->pos_ifindex) {
798 netdev_hold(dev, &dev_tracker, GFP_ATOMIC);
799 rcu_read_unlock();
800
801 /* per-PHY commands use ethnl_req_get_phydev(), which needs the
802 * net_device in the req_info
803 */
804 ethnl_ctx->req_info->dev = dev;
805 ret = ethnl_perphy_dump_one_dev(skb, ctx, info);
806
807 rcu_read_lock();
808 netdev_put(dev, &dev_tracker);
809 ethnl_ctx->req_info->dev = NULL;
810
811 if (ret < 0 && ret != -EOPNOTSUPP) {
812 if (likely(skb->len))
813 ret = skb->len;
814 break;
815 }
816 ret = 0;
817 }
818 rcu_read_unlock();
819
820 return ret;
821}
822
823/* per-PHY ->dumpit() handler for GET requests. */
824static int ethnl_perphy_dumpit(struct sk_buff *skb,
825 struct netlink_callback *cb)
826{
827 struct ethnl_perphy_dump_ctx *ctx = ethnl_perphy_dump_context(cb);
828 const struct genl_dumpit_info *info = genl_dumpit_info(cb);
829 struct ethnl_dump_ctx *ethnl_ctx = &ctx->ethnl_ctx;
830 int ret = 0;
831
832 if (ctx->ifindex) {
833 netdevice_tracker dev_tracker;
834 struct net_device *dev;
835
836 dev = netdev_get_by_index(genl_info_net(&info->info),
837 ctx->ifindex, &dev_tracker,
838 GFP_KERNEL);
839 if (!dev)
840 return -ENODEV;
841
842 ethnl_ctx->req_info->dev = dev;
843 ret = ethnl_perphy_dump_one_dev(skb, ctx, genl_info_dump(cb));
844
845 if (ret < 0 && ret != -EOPNOTSUPP && likely(skb->len))
846 ret = skb->len;
847
848 netdev_put(dev, &dev_tracker);
849 } else {
850 ret = ethnl_perphy_dump_all_dev(skb, ctx, genl_info_dump(cb));
851 }
852
853 return ret;
854}
855
856/* per-PHY ->done() handler for GET requests */
857static int ethnl_perphy_done(struct netlink_callback *cb)
858{
859 struct ethnl_perphy_dump_ctx *ctx = ethnl_perphy_dump_context(cb);
860 struct ethnl_dump_ctx *ethnl_ctx = &ctx->ethnl_ctx;
861
862 kfree(ethnl_ctx->reply_data);
863 kfree(ethnl_ctx->req_info);
864
865 return 0;
866}
867
868/* default ->done() handler for GET requests */
869static int ethnl_default_done(struct netlink_callback *cb)
870{
871 struct ethnl_dump_ctx *ctx = ethnl_dump_context(cb);
872
873 kfree(ctx->reply_data);
874 kfree(ctx->req_info);
875
876 return 0;
877}
878
879static int ethnl_default_set_doit(struct sk_buff *skb, struct genl_info *info)
880{
881 const struct ethnl_request_ops *ops;
882 const u8 cmd = info->genlhdr->cmd;
883 struct ethnl_req_info *req_info;
884 struct net_device *dev;
885 int ret;
886
887 ops = ethnl_default_requests[cmd];
888 if (WARN_ONCE(!ops, "cmd %u has no ethnl_request_ops\n", cmd))
889 return -EOPNOTSUPP;
890 if (GENL_REQ_ATTR_CHECK(info, ops->hdr_attr))
891 return -EINVAL;
892
893 req_info = kzalloc(ops->req_info_size, GFP_KERNEL);
894 if (!req_info)
895 return -ENOMEM;
896
897 ret = ethnl_default_parse(req_info, info, ops, true);
898 if (ret < 0)
899 goto out_free_req;
900
901 if (ops->set_validate) {
902 ret = ops->set_validate(req_info, info);
903 /* 0 means nothing to do */
904 if (ret <= 0)
905 goto out_dev;
906 }
907
908 dev = req_info->dev;
909
910 rtnl_lock();
911 netdev_lock_ops(dev);
912 dev->cfg_pending = kmemdup(dev->cfg, sizeof(*dev->cfg),
913 GFP_KERNEL_ACCOUNT);
914 if (!dev->cfg_pending) {
915 ret = -ENOMEM;
916 goto out_tie_cfg;
917 }
918
919 ret = ethnl_ops_begin(dev);
920 if (ret < 0)
921 goto out_free_cfg;
922
923 ret = ops->set(req_info, info);
924 if (ret < 0)
925 goto out_ops;
926
927 swap(dev->cfg, dev->cfg_pending);
928 if (!ret)
929 goto out_ops;
930 ethnl_notify(dev, ops->set_ntf_cmd, req_info);
931
932 ret = 0;
933out_ops:
934 ethnl_ops_complete(dev);
935out_free_cfg:
936 kfree(dev->cfg_pending);
937out_tie_cfg:
938 dev->cfg_pending = dev->cfg;
939 netdev_unlock_ops(dev);
940 rtnl_unlock();
941out_dev:
942 ethnl_parse_header_dev_put(req_info);
943out_free_req:
944 kfree(req_info);
945 return ret;
946}
947
948static const struct ethnl_request_ops *
949ethnl_default_notify_ops[ETHTOOL_MSG_KERNEL_MAX + 1] = {
950 [ETHTOOL_MSG_LINKINFO_NTF] = ðnl_linkinfo_request_ops,
951 [ETHTOOL_MSG_LINKMODES_NTF] = ðnl_linkmodes_request_ops,
952 [ETHTOOL_MSG_DEBUG_NTF] = ðnl_debug_request_ops,
953 [ETHTOOL_MSG_WOL_NTF] = ðnl_wol_request_ops,
954 [ETHTOOL_MSG_FEATURES_NTF] = ðnl_features_request_ops,
955 [ETHTOOL_MSG_PRIVFLAGS_NTF] = ðnl_privflags_request_ops,
956 [ETHTOOL_MSG_RINGS_NTF] = ðnl_rings_request_ops,
957 [ETHTOOL_MSG_CHANNELS_NTF] = ðnl_channels_request_ops,
958 [ETHTOOL_MSG_COALESCE_NTF] = ðnl_coalesce_request_ops,
959 [ETHTOOL_MSG_PAUSE_NTF] = ðnl_pause_request_ops,
960 [ETHTOOL_MSG_EEE_NTF] = ðnl_eee_request_ops,
961 [ETHTOOL_MSG_FEC_NTF] = ðnl_fec_request_ops,
962 [ETHTOOL_MSG_MODULE_NTF] = ðnl_module_request_ops,
963 [ETHTOOL_MSG_PLCA_NTF] = ðnl_plca_cfg_request_ops,
964 [ETHTOOL_MSG_MM_NTF] = ðnl_mm_request_ops,
965 [ETHTOOL_MSG_RSS_NTF] = ðnl_rss_request_ops,
966 [ETHTOOL_MSG_RSS_CREATE_NTF] = ðnl_rss_request_ops,
967};
968
969/* default notification handler */
970static void ethnl_default_notify(struct net_device *dev, unsigned int cmd,
971 const struct ethnl_req_info *orig_req_info)
972{
973 struct ethnl_reply_data *reply_data;
974 const struct ethnl_request_ops *ops;
975 struct ethnl_req_info *req_info;
976 struct genl_info info;
977 struct sk_buff *skb;
978 void *reply_payload;
979 int reply_len;
980 int ret;
981
982 genl_info_init_ntf(&info, ðtool_genl_family, cmd);
983
984 if (WARN_ONCE(cmd > ETHTOOL_MSG_KERNEL_MAX ||
985 !ethnl_default_notify_ops[cmd],
986 "unexpected notification type %u\n", cmd))
987 return;
988 ops = ethnl_default_notify_ops[cmd];
989 req_info = kzalloc(ops->req_info_size, GFP_KERNEL);
990 if (!req_info)
991 return;
992 reply_data = kmalloc(ops->reply_data_size, GFP_KERNEL);
993 if (!reply_data) {
994 kfree(req_info);
995 return;
996 }
997
998 req_info->dev = dev;
999 req_info->flags |= ETHTOOL_FLAG_COMPACT_BITSETS;
1000 if (orig_req_info) {
1001 req_info->phy_index = orig_req_info->phy_index;
1002 memcpy(&req_info[1], &orig_req_info[1],
1003 ops->req_info_size - sizeof(*req_info));
1004 }
1005
1006 netdev_ops_assert_locked(dev);
1007
1008 ethnl_init_reply_data(reply_data, ops, dev);
1009 ret = ops->prepare_data(req_info, reply_data, &info);
1010 if (ret < 0)
1011 goto err_rep;
1012 ret = ops->reply_size(req_info, reply_data);
1013 if (ret < 0)
1014 goto err_cleanup;
1015 reply_len = ret + ethnl_reply_header_size();
1016 skb = genlmsg_new(reply_len, GFP_KERNEL);
1017 if (!skb)
1018 goto err_cleanup;
1019 reply_payload = ethnl_bcastmsg_put(skb, cmd);
1020 if (!reply_payload)
1021 goto err_skb;
1022 ret = ethnl_fill_reply_header(skb, dev, ops->hdr_attr);
1023 if (ret < 0)
1024 goto err_msg;
1025 ret = ops->fill_reply(skb, req_info, reply_data);
1026 if (ret < 0)
1027 goto err_msg;
1028 if (ops->cleanup_data)
1029 ops->cleanup_data(reply_data);
1030
1031 genlmsg_end(skb, reply_payload);
1032 kfree(reply_data);
1033 kfree(req_info);
1034 ethnl_multicast(skb, dev);
1035 return;
1036
1037err_msg:
1038 WARN_ONCE(ret == -EMSGSIZE,
1039 "calculated message payload length (%d) not sufficient\n",
1040 reply_len);
1041err_skb:
1042 nlmsg_free(skb);
1043err_cleanup:
1044 if (ops->cleanup_data)
1045 ops->cleanup_data(reply_data);
1046err_rep:
1047 kfree(reply_data);
1048 kfree(req_info);
1049 return;
1050}
1051
1052/* notifications */
1053
1054typedef void (*ethnl_notify_handler_t)(struct net_device *dev, unsigned int cmd,
1055 const struct ethnl_req_info *req_info);
1056
1057static const ethnl_notify_handler_t ethnl_notify_handlers[] = {
1058 [ETHTOOL_MSG_LINKINFO_NTF] = ethnl_default_notify,
1059 [ETHTOOL_MSG_LINKMODES_NTF] = ethnl_default_notify,
1060 [ETHTOOL_MSG_DEBUG_NTF] = ethnl_default_notify,
1061 [ETHTOOL_MSG_WOL_NTF] = ethnl_default_notify,
1062 [ETHTOOL_MSG_FEATURES_NTF] = ethnl_default_notify,
1063 [ETHTOOL_MSG_PRIVFLAGS_NTF] = ethnl_default_notify,
1064 [ETHTOOL_MSG_RINGS_NTF] = ethnl_default_notify,
1065 [ETHTOOL_MSG_CHANNELS_NTF] = ethnl_default_notify,
1066 [ETHTOOL_MSG_COALESCE_NTF] = ethnl_default_notify,
1067 [ETHTOOL_MSG_PAUSE_NTF] = ethnl_default_notify,
1068 [ETHTOOL_MSG_EEE_NTF] = ethnl_default_notify,
1069 [ETHTOOL_MSG_FEC_NTF] = ethnl_default_notify,
1070 [ETHTOOL_MSG_MODULE_NTF] = ethnl_default_notify,
1071 [ETHTOOL_MSG_PLCA_NTF] = ethnl_default_notify,
1072 [ETHTOOL_MSG_MM_NTF] = ethnl_default_notify,
1073 [ETHTOOL_MSG_RSS_NTF] = ethnl_default_notify,
1074 [ETHTOOL_MSG_RSS_CREATE_NTF] = ethnl_default_notify,
1075};
1076
1077void ethnl_notify(struct net_device *dev, unsigned int cmd,
1078 const struct ethnl_req_info *req_info)
1079{
1080 if (unlikely(!ethnl_ok))
1081 return;
1082 ASSERT_RTNL();
1083
1084 if (likely(cmd < ARRAY_SIZE(ethnl_notify_handlers) &&
1085 ethnl_notify_handlers[cmd]))
1086 ethnl_notify_handlers[cmd](dev, cmd, req_info);
1087 else
1088 WARN_ONCE(1, "notification %u not implemented (dev=%s)\n",
1089 cmd, netdev_name(dev));
1090}
1091
1092void ethtool_notify(struct net_device *dev, unsigned int cmd)
1093{
1094 ethnl_notify(dev, cmd, NULL);
1095}
1096EXPORT_SYMBOL(ethtool_notify);
1097
1098static void ethnl_notify_features(struct netdev_notifier_info *info)
1099{
1100 struct net_device *dev = netdev_notifier_info_to_dev(info);
1101
1102 ethtool_notify(dev, ETHTOOL_MSG_FEATURES_NTF);
1103}
1104
1105static int ethnl_netdev_event(struct notifier_block *this, unsigned long event,
1106 void *ptr)
1107{
1108 struct netdev_notifier_info *info = ptr;
1109 struct netlink_ext_ack *extack;
1110 struct net_device *dev;
1111
1112 dev = netdev_notifier_info_to_dev(info);
1113 extack = netdev_notifier_info_to_extack(info);
1114
1115 switch (event) {
1116 case NETDEV_FEAT_CHANGE:
1117 ethnl_notify_features(ptr);
1118 break;
1119 case NETDEV_PRE_UP:
1120 if (dev->ethtool->module_fw_flash_in_progress) {
1121 NL_SET_ERR_MSG(extack, "Can't set port up while flashing module firmware");
1122 return NOTIFY_BAD;
1123 }
1124 }
1125
1126 return NOTIFY_DONE;
1127}
1128
1129static struct notifier_block ethnl_netdev_notifier = {
1130 .notifier_call = ethnl_netdev_event,
1131};
1132
1133/* genetlink setup */
1134
1135static const struct genl_ops ethtool_genl_ops[] = {
1136 {
1137 .cmd = ETHTOOL_MSG_STRSET_GET,
1138 .doit = ethnl_default_doit,
1139 .start = ethnl_default_start,
1140 .dumpit = ethnl_default_dumpit,
1141 .done = ethnl_default_done,
1142 .policy = ethnl_strset_get_policy,
1143 .maxattr = ARRAY_SIZE(ethnl_strset_get_policy) - 1,
1144 },
1145 {
1146 .cmd = ETHTOOL_MSG_LINKINFO_GET,
1147 .doit = ethnl_default_doit,
1148 .start = ethnl_default_start,
1149 .dumpit = ethnl_default_dumpit,
1150 .done = ethnl_default_done,
1151 .policy = ethnl_linkinfo_get_policy,
1152 .maxattr = ARRAY_SIZE(ethnl_linkinfo_get_policy) - 1,
1153 },
1154 {
1155 .cmd = ETHTOOL_MSG_LINKINFO_SET,
1156 .flags = GENL_UNS_ADMIN_PERM,
1157 .doit = ethnl_default_set_doit,
1158 .policy = ethnl_linkinfo_set_policy,
1159 .maxattr = ARRAY_SIZE(ethnl_linkinfo_set_policy) - 1,
1160 },
1161 {
1162 .cmd = ETHTOOL_MSG_LINKMODES_GET,
1163 .doit = ethnl_default_doit,
1164 .start = ethnl_default_start,
1165 .dumpit = ethnl_default_dumpit,
1166 .done = ethnl_default_done,
1167 .policy = ethnl_linkmodes_get_policy,
1168 .maxattr = ARRAY_SIZE(ethnl_linkmodes_get_policy) - 1,
1169 },
1170 {
1171 .cmd = ETHTOOL_MSG_LINKMODES_SET,
1172 .flags = GENL_UNS_ADMIN_PERM,
1173 .doit = ethnl_default_set_doit,
1174 .policy = ethnl_linkmodes_set_policy,
1175 .maxattr = ARRAY_SIZE(ethnl_linkmodes_set_policy) - 1,
1176 },
1177 {
1178 .cmd = ETHTOOL_MSG_LINKSTATE_GET,
1179 .doit = ethnl_default_doit,
1180 .start = ethnl_default_start,
1181 .dumpit = ethnl_default_dumpit,
1182 .done = ethnl_default_done,
1183 .policy = ethnl_linkstate_get_policy,
1184 .maxattr = ARRAY_SIZE(ethnl_linkstate_get_policy) - 1,
1185 },
1186 {
1187 .cmd = ETHTOOL_MSG_DEBUG_GET,
1188 .doit = ethnl_default_doit,
1189 .start = ethnl_default_start,
1190 .dumpit = ethnl_default_dumpit,
1191 .done = ethnl_default_done,
1192 .policy = ethnl_debug_get_policy,
1193 .maxattr = ARRAY_SIZE(ethnl_debug_get_policy) - 1,
1194 },
1195 {
1196 .cmd = ETHTOOL_MSG_DEBUG_SET,
1197 .flags = GENL_UNS_ADMIN_PERM,
1198 .doit = ethnl_default_set_doit,
1199 .policy = ethnl_debug_set_policy,
1200 .maxattr = ARRAY_SIZE(ethnl_debug_set_policy) - 1,
1201 },
1202 {
1203 .cmd = ETHTOOL_MSG_WOL_GET,
1204 .flags = GENL_UNS_ADMIN_PERM,
1205 .doit = ethnl_default_doit,
1206 .start = ethnl_default_start,
1207 .dumpit = ethnl_default_dumpit,
1208 .done = ethnl_default_done,
1209 .policy = ethnl_wol_get_policy,
1210 .maxattr = ARRAY_SIZE(ethnl_wol_get_policy) - 1,
1211 },
1212 {
1213 .cmd = ETHTOOL_MSG_WOL_SET,
1214 .flags = GENL_UNS_ADMIN_PERM,
1215 .doit = ethnl_default_set_doit,
1216 .policy = ethnl_wol_set_policy,
1217 .maxattr = ARRAY_SIZE(ethnl_wol_set_policy) - 1,
1218 },
1219 {
1220 .cmd = ETHTOOL_MSG_FEATURES_GET,
1221 .doit = ethnl_default_doit,
1222 .start = ethnl_default_start,
1223 .dumpit = ethnl_default_dumpit,
1224 .done = ethnl_default_done,
1225 .policy = ethnl_features_get_policy,
1226 .maxattr = ARRAY_SIZE(ethnl_features_get_policy) - 1,
1227 },
1228 {
1229 .cmd = ETHTOOL_MSG_FEATURES_SET,
1230 .flags = GENL_UNS_ADMIN_PERM,
1231 .doit = ethnl_set_features,
1232 .policy = ethnl_features_set_policy,
1233 .maxattr = ARRAY_SIZE(ethnl_features_set_policy) - 1,
1234 },
1235 {
1236 .cmd = ETHTOOL_MSG_PRIVFLAGS_GET,
1237 .doit = ethnl_default_doit,
1238 .start = ethnl_default_start,
1239 .dumpit = ethnl_default_dumpit,
1240 .done = ethnl_default_done,
1241 .policy = ethnl_privflags_get_policy,
1242 .maxattr = ARRAY_SIZE(ethnl_privflags_get_policy) - 1,
1243 },
1244 {
1245 .cmd = ETHTOOL_MSG_PRIVFLAGS_SET,
1246 .flags = GENL_UNS_ADMIN_PERM,
1247 .doit = ethnl_default_set_doit,
1248 .policy = ethnl_privflags_set_policy,
1249 .maxattr = ARRAY_SIZE(ethnl_privflags_set_policy) - 1,
1250 },
1251 {
1252 .cmd = ETHTOOL_MSG_RINGS_GET,
1253 .doit = ethnl_default_doit,
1254 .start = ethnl_default_start,
1255 .dumpit = ethnl_default_dumpit,
1256 .done = ethnl_default_done,
1257 .policy = ethnl_rings_get_policy,
1258 .maxattr = ARRAY_SIZE(ethnl_rings_get_policy) - 1,
1259 },
1260 {
1261 .cmd = ETHTOOL_MSG_RINGS_SET,
1262 .flags = GENL_UNS_ADMIN_PERM,
1263 .doit = ethnl_default_set_doit,
1264 .policy = ethnl_rings_set_policy,
1265 .maxattr = ARRAY_SIZE(ethnl_rings_set_policy) - 1,
1266 },
1267 {
1268 .cmd = ETHTOOL_MSG_CHANNELS_GET,
1269 .doit = ethnl_default_doit,
1270 .start = ethnl_default_start,
1271 .dumpit = ethnl_default_dumpit,
1272 .done = ethnl_default_done,
1273 .policy = ethnl_channels_get_policy,
1274 .maxattr = ARRAY_SIZE(ethnl_channels_get_policy) - 1,
1275 },
1276 {
1277 .cmd = ETHTOOL_MSG_CHANNELS_SET,
1278 .flags = GENL_UNS_ADMIN_PERM,
1279 .doit = ethnl_default_set_doit,
1280 .policy = ethnl_channels_set_policy,
1281 .maxattr = ARRAY_SIZE(ethnl_channels_set_policy) - 1,
1282 },
1283 {
1284 .cmd = ETHTOOL_MSG_COALESCE_GET,
1285 .doit = ethnl_default_doit,
1286 .start = ethnl_default_start,
1287 .dumpit = ethnl_default_dumpit,
1288 .done = ethnl_default_done,
1289 .policy = ethnl_coalesce_get_policy,
1290 .maxattr = ARRAY_SIZE(ethnl_coalesce_get_policy) - 1,
1291 },
1292 {
1293 .cmd = ETHTOOL_MSG_COALESCE_SET,
1294 .flags = GENL_UNS_ADMIN_PERM,
1295 .doit = ethnl_default_set_doit,
1296 .policy = ethnl_coalesce_set_policy,
1297 .maxattr = ARRAY_SIZE(ethnl_coalesce_set_policy) - 1,
1298 },
1299 {
1300 .cmd = ETHTOOL_MSG_PAUSE_GET,
1301 .doit = ethnl_default_doit,
1302 .start = ethnl_default_start,
1303 .dumpit = ethnl_default_dumpit,
1304 .done = ethnl_default_done,
1305 .policy = ethnl_pause_get_policy,
1306 .maxattr = ARRAY_SIZE(ethnl_pause_get_policy) - 1,
1307 },
1308 {
1309 .cmd = ETHTOOL_MSG_PAUSE_SET,
1310 .flags = GENL_UNS_ADMIN_PERM,
1311 .doit = ethnl_default_set_doit,
1312 .policy = ethnl_pause_set_policy,
1313 .maxattr = ARRAY_SIZE(ethnl_pause_set_policy) - 1,
1314 },
1315 {
1316 .cmd = ETHTOOL_MSG_EEE_GET,
1317 .doit = ethnl_default_doit,
1318 .start = ethnl_default_start,
1319 .dumpit = ethnl_default_dumpit,
1320 .done = ethnl_default_done,
1321 .policy = ethnl_eee_get_policy,
1322 .maxattr = ARRAY_SIZE(ethnl_eee_get_policy) - 1,
1323 },
1324 {
1325 .cmd = ETHTOOL_MSG_EEE_SET,
1326 .flags = GENL_UNS_ADMIN_PERM,
1327 .doit = ethnl_default_set_doit,
1328 .policy = ethnl_eee_set_policy,
1329 .maxattr = ARRAY_SIZE(ethnl_eee_set_policy) - 1,
1330 },
1331 {
1332 .cmd = ETHTOOL_MSG_TSINFO_GET,
1333 .doit = ethnl_default_doit,
1334 .start = ethnl_tsinfo_start,
1335 .dumpit = ethnl_tsinfo_dumpit,
1336 .done = ethnl_tsinfo_done,
1337 .policy = ethnl_tsinfo_get_policy,
1338 .maxattr = ARRAY_SIZE(ethnl_tsinfo_get_policy) - 1,
1339 },
1340 {
1341 .cmd = ETHTOOL_MSG_CABLE_TEST_ACT,
1342 .flags = GENL_UNS_ADMIN_PERM,
1343 .doit = ethnl_act_cable_test,
1344 .policy = ethnl_cable_test_act_policy,
1345 .maxattr = ARRAY_SIZE(ethnl_cable_test_act_policy) - 1,
1346 },
1347 {
1348 .cmd = ETHTOOL_MSG_CABLE_TEST_TDR_ACT,
1349 .flags = GENL_UNS_ADMIN_PERM,
1350 .doit = ethnl_act_cable_test_tdr,
1351 .policy = ethnl_cable_test_tdr_act_policy,
1352 .maxattr = ARRAY_SIZE(ethnl_cable_test_tdr_act_policy) - 1,
1353 },
1354 {
1355 .cmd = ETHTOOL_MSG_TUNNEL_INFO_GET,
1356 .doit = ethnl_tunnel_info_doit,
1357 .start = ethnl_tunnel_info_start,
1358 .dumpit = ethnl_tunnel_info_dumpit,
1359 .policy = ethnl_tunnel_info_get_policy,
1360 .maxattr = ARRAY_SIZE(ethnl_tunnel_info_get_policy) - 1,
1361 },
1362 {
1363 .cmd = ETHTOOL_MSG_FEC_GET,
1364 .doit = ethnl_default_doit,
1365 .start = ethnl_default_start,
1366 .dumpit = ethnl_default_dumpit,
1367 .done = ethnl_default_done,
1368 .policy = ethnl_fec_get_policy,
1369 .maxattr = ARRAY_SIZE(ethnl_fec_get_policy) - 1,
1370 },
1371 {
1372 .cmd = ETHTOOL_MSG_FEC_SET,
1373 .flags = GENL_UNS_ADMIN_PERM,
1374 .doit = ethnl_default_set_doit,
1375 .policy = ethnl_fec_set_policy,
1376 .maxattr = ARRAY_SIZE(ethnl_fec_set_policy) - 1,
1377 },
1378 {
1379 .cmd = ETHTOOL_MSG_MODULE_EEPROM_GET,
1380 .flags = GENL_UNS_ADMIN_PERM,
1381 .doit = ethnl_default_doit,
1382 .start = ethnl_default_start,
1383 .dumpit = ethnl_default_dumpit,
1384 .done = ethnl_default_done,
1385 .policy = ethnl_module_eeprom_get_policy,
1386 .maxattr = ARRAY_SIZE(ethnl_module_eeprom_get_policy) - 1,
1387 },
1388 {
1389 .cmd = ETHTOOL_MSG_STATS_GET,
1390 .doit = ethnl_default_doit,
1391 .start = ethnl_default_start,
1392 .dumpit = ethnl_default_dumpit,
1393 .done = ethnl_default_done,
1394 .policy = ethnl_stats_get_policy,
1395 .maxattr = ARRAY_SIZE(ethnl_stats_get_policy) - 1,
1396 },
1397 {
1398 .cmd = ETHTOOL_MSG_PHC_VCLOCKS_GET,
1399 .doit = ethnl_default_doit,
1400 .start = ethnl_default_start,
1401 .dumpit = ethnl_default_dumpit,
1402 .done = ethnl_default_done,
1403 .policy = ethnl_phc_vclocks_get_policy,
1404 .maxattr = ARRAY_SIZE(ethnl_phc_vclocks_get_policy) - 1,
1405 },
1406 {
1407 .cmd = ETHTOOL_MSG_MODULE_GET,
1408 .doit = ethnl_default_doit,
1409 .start = ethnl_default_start,
1410 .dumpit = ethnl_default_dumpit,
1411 .done = ethnl_default_done,
1412 .policy = ethnl_module_get_policy,
1413 .maxattr = ARRAY_SIZE(ethnl_module_get_policy) - 1,
1414 },
1415 {
1416 .cmd = ETHTOOL_MSG_MODULE_SET,
1417 .flags = GENL_UNS_ADMIN_PERM,
1418 .doit = ethnl_default_set_doit,
1419 .policy = ethnl_module_set_policy,
1420 .maxattr = ARRAY_SIZE(ethnl_module_set_policy) - 1,
1421 },
1422 {
1423 .cmd = ETHTOOL_MSG_PSE_GET,
1424 .doit = ethnl_default_doit,
1425 .start = ethnl_perphy_start,
1426 .dumpit = ethnl_perphy_dumpit,
1427 .done = ethnl_perphy_done,
1428 .policy = ethnl_pse_get_policy,
1429 .maxattr = ARRAY_SIZE(ethnl_pse_get_policy) - 1,
1430 },
1431 {
1432 .cmd = ETHTOOL_MSG_PSE_SET,
1433 .flags = GENL_UNS_ADMIN_PERM,
1434 .doit = ethnl_default_set_doit,
1435 .policy = ethnl_pse_set_policy,
1436 .maxattr = ARRAY_SIZE(ethnl_pse_set_policy) - 1,
1437 },
1438 {
1439 .cmd = ETHTOOL_MSG_RSS_GET,
1440 .doit = ethnl_default_doit,
1441 .start = ethnl_rss_dump_start,
1442 .dumpit = ethnl_rss_dumpit,
1443 .policy = ethnl_rss_get_policy,
1444 .maxattr = ARRAY_SIZE(ethnl_rss_get_policy) - 1,
1445 },
1446 {
1447 .cmd = ETHTOOL_MSG_PLCA_GET_CFG,
1448 .doit = ethnl_default_doit,
1449 .start = ethnl_perphy_start,
1450 .dumpit = ethnl_perphy_dumpit,
1451 .done = ethnl_perphy_done,
1452 .policy = ethnl_plca_get_cfg_policy,
1453 .maxattr = ARRAY_SIZE(ethnl_plca_get_cfg_policy) - 1,
1454 },
1455 {
1456 .cmd = ETHTOOL_MSG_PLCA_SET_CFG,
1457 .flags = GENL_UNS_ADMIN_PERM,
1458 .doit = ethnl_default_set_doit,
1459 .policy = ethnl_plca_set_cfg_policy,
1460 .maxattr = ARRAY_SIZE(ethnl_plca_set_cfg_policy) - 1,
1461 },
1462 {
1463 .cmd = ETHTOOL_MSG_PLCA_GET_STATUS,
1464 .doit = ethnl_default_doit,
1465 .start = ethnl_perphy_start,
1466 .dumpit = ethnl_perphy_dumpit,
1467 .done = ethnl_perphy_done,
1468 .policy = ethnl_plca_get_status_policy,
1469 .maxattr = ARRAY_SIZE(ethnl_plca_get_status_policy) - 1,
1470 },
1471 {
1472 .cmd = ETHTOOL_MSG_MM_GET,
1473 .doit = ethnl_default_doit,
1474 .start = ethnl_default_start,
1475 .dumpit = ethnl_default_dumpit,
1476 .done = ethnl_default_done,
1477 .policy = ethnl_mm_get_policy,
1478 .maxattr = ARRAY_SIZE(ethnl_mm_get_policy) - 1,
1479 },
1480 {
1481 .cmd = ETHTOOL_MSG_MM_SET,
1482 .flags = GENL_UNS_ADMIN_PERM,
1483 .doit = ethnl_default_set_doit,
1484 .policy = ethnl_mm_set_policy,
1485 .maxattr = ARRAY_SIZE(ethnl_mm_set_policy) - 1,
1486 },
1487 {
1488 .cmd = ETHTOOL_MSG_MODULE_FW_FLASH_ACT,
1489 .flags = GENL_UNS_ADMIN_PERM,
1490 .doit = ethnl_act_module_fw_flash,
1491 .policy = ethnl_module_fw_flash_act_policy,
1492 .maxattr = ARRAY_SIZE(ethnl_module_fw_flash_act_policy) - 1,
1493 },
1494 {
1495 .cmd = ETHTOOL_MSG_PHY_GET,
1496 .doit = ethnl_default_doit,
1497 .start = ethnl_perphy_start,
1498 .dumpit = ethnl_perphy_dumpit,
1499 .done = ethnl_perphy_done,
1500 .policy = ethnl_phy_get_policy,
1501 .maxattr = ARRAY_SIZE(ethnl_phy_get_policy) - 1,
1502 },
1503 {
1504 .cmd = ETHTOOL_MSG_TSCONFIG_GET,
1505 .doit = ethnl_default_doit,
1506 .start = ethnl_default_start,
1507 .dumpit = ethnl_default_dumpit,
1508 .done = ethnl_default_done,
1509 .policy = ethnl_tsconfig_get_policy,
1510 .maxattr = ARRAY_SIZE(ethnl_tsconfig_get_policy) - 1,
1511 },
1512 {
1513 .cmd = ETHTOOL_MSG_TSCONFIG_SET,
1514 .flags = GENL_UNS_ADMIN_PERM,
1515 .doit = ethnl_default_set_doit,
1516 .policy = ethnl_tsconfig_set_policy,
1517 .maxattr = ARRAY_SIZE(ethnl_tsconfig_set_policy) - 1,
1518 },
1519 {
1520 .cmd = ETHTOOL_MSG_RSS_SET,
1521 .flags = GENL_UNS_ADMIN_PERM,
1522 .doit = ethnl_default_set_doit,
1523 .policy = ethnl_rss_set_policy,
1524 .maxattr = ARRAY_SIZE(ethnl_rss_set_policy) - 1,
1525 },
1526 {
1527 .cmd = ETHTOOL_MSG_RSS_CREATE_ACT,
1528 .flags = GENL_UNS_ADMIN_PERM,
1529 .doit = ethnl_rss_create_doit,
1530 .policy = ethnl_rss_create_policy,
1531 .maxattr = ARRAY_SIZE(ethnl_rss_create_policy) - 1,
1532 },
1533 {
1534 .cmd = ETHTOOL_MSG_RSS_DELETE_ACT,
1535 .flags = GENL_UNS_ADMIN_PERM,
1536 .doit = ethnl_rss_delete_doit,
1537 .policy = ethnl_rss_delete_policy,
1538 .maxattr = ARRAY_SIZE(ethnl_rss_delete_policy) - 1,
1539 },
1540 {
1541 .cmd = ETHTOOL_MSG_MSE_GET,
1542 .doit = ethnl_default_doit,
1543 .start = ethnl_perphy_start,
1544 .dumpit = ethnl_perphy_dumpit,
1545 .done = ethnl_perphy_done,
1546 .policy = ethnl_mse_get_policy,
1547 .maxattr = ARRAY_SIZE(ethnl_mse_get_policy) - 1,
1548 },
1549};
1550
1551static const struct genl_multicast_group ethtool_nl_mcgrps[] = {
1552 [ETHNL_MCGRP_MONITOR] = { .name = ETHTOOL_MCGRP_MONITOR_NAME },
1553};
1554
1555static struct genl_family ethtool_genl_family __ro_after_init = {
1556 .name = ETHTOOL_GENL_NAME,
1557 .version = ETHTOOL_GENL_VERSION,
1558 .netnsok = true,
1559 .parallel_ops = true,
1560 .ops = ethtool_genl_ops,
1561 .n_ops = ARRAY_SIZE(ethtool_genl_ops),
1562 .resv_start_op = ETHTOOL_MSG_MODULE_GET + 1,
1563 .mcgrps = ethtool_nl_mcgrps,
1564 .n_mcgrps = ARRAY_SIZE(ethtool_nl_mcgrps),
1565 .sock_priv_size = sizeof(struct ethnl_sock_priv),
1566 .sock_priv_destroy = ethnl_sock_priv_destroy,
1567};
1568
1569/* module setup */
1570
1571static int __init ethnl_init(void)
1572{
1573 int ret;
1574
1575 ret = genl_register_family(ðtool_genl_family);
1576 if (WARN(ret < 0, "ethtool: genetlink family registration failed"))
1577 return ret;
1578 ethnl_ok = true;
1579
1580 ret = register_netdevice_notifier(ðnl_netdev_notifier);
1581 WARN(ret < 0, "ethtool: net device notifier registration failed");
1582 return ret;
1583}
1584
1585subsys_initcall(ethnl_init);