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