projects/linux·blob master · refs

1611 lines · 44.6 KiB

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