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(ðtool_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, ðtool_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 ðtool_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, ðtool_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, ðtool_genl_family, 0, cmd); 338 } 339 340 int ethnl_multicast(struct sk_buff *skb, struct net_device *dev) 341 { 342 return genlmsg_multicast_netns(ðtool_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] = ðnl_strset_request_ops, 381 [ETHTOOL_MSG_LINKINFO_GET] = ðnl_linkinfo_request_ops, 382 [ETHTOOL_MSG_LINKINFO_SET] = ðnl_linkinfo_request_ops, 383 [ETHTOOL_MSG_LINKMODES_GET] = ðnl_linkmodes_request_ops, 384 [ETHTOOL_MSG_LINKMODES_SET] = ðnl_linkmodes_request_ops, 385 [ETHTOOL_MSG_LINKSTATE_GET] = ðnl_linkstate_request_ops, 386 [ETHTOOL_MSG_DEBUG_GET] = ðnl_debug_request_ops, 387 [ETHTOOL_MSG_DEBUG_SET] = ðnl_debug_request_ops, 388 [ETHTOOL_MSG_WOL_GET] = ðnl_wol_request_ops, 389 [ETHTOOL_MSG_WOL_SET] = ðnl_wol_request_ops, 390 [ETHTOOL_MSG_FEATURES_GET] = ðnl_features_request_ops, 391 [ETHTOOL_MSG_PRIVFLAGS_GET] = ðnl_privflags_request_ops, 392 [ETHTOOL_MSG_PRIVFLAGS_SET] = ðnl_privflags_request_ops, 393 [ETHTOOL_MSG_RINGS_GET] = ðnl_rings_request_ops, 394 [ETHTOOL_MSG_RINGS_SET] = ðnl_rings_request_ops, 395 [ETHTOOL_MSG_CHANNELS_GET] = ðnl_channels_request_ops, 396 [ETHTOOL_MSG_CHANNELS_SET] = ðnl_channels_request_ops, 397 [ETHTOOL_MSG_COALESCE_GET] = ðnl_coalesce_request_ops, 398 [ETHTOOL_MSG_COALESCE_SET] = ðnl_coalesce_request_ops, 399 [ETHTOOL_MSG_PAUSE_GET] = ðnl_pause_request_ops, 400 [ETHTOOL_MSG_PAUSE_SET] = ðnl_pause_request_ops, 401 [ETHTOOL_MSG_EEE_GET] = ðnl_eee_request_ops, 402 [ETHTOOL_MSG_EEE_SET] = ðnl_eee_request_ops, 403 [ETHTOOL_MSG_FEC_GET] = ðnl_fec_request_ops, 404 [ETHTOOL_MSG_FEC_SET] = ðnl_fec_request_ops, 405 [ETHTOOL_MSG_TSINFO_GET] = ðnl_tsinfo_request_ops, 406 [ETHTOOL_MSG_MODULE_EEPROM_GET] = ðnl_module_eeprom_request_ops, 407 [ETHTOOL_MSG_STATS_GET] = ðnl_stats_request_ops, 408 [ETHTOOL_MSG_PHC_VCLOCKS_GET] = ðnl_phc_vclocks_request_ops, 409 [ETHTOOL_MSG_MODULE_GET] = ðnl_module_request_ops, 410 [ETHTOOL_MSG_MODULE_SET] = ðnl_module_request_ops, 411 [ETHTOOL_MSG_PSE_GET] = ðnl_pse_request_ops, 412 [ETHTOOL_MSG_PSE_SET] = ðnl_pse_request_ops, 413 [ETHTOOL_MSG_RSS_GET] = ðnl_rss_request_ops, 414 [ETHTOOL_MSG_RSS_SET] = ðnl_rss_request_ops, 415 [ETHTOOL_MSG_PLCA_GET_CFG] = ðnl_plca_cfg_request_ops, 416 [ETHTOOL_MSG_PLCA_SET_CFG] = ðnl_plca_cfg_request_ops, 417 [ETHTOOL_MSG_PLCA_GET_STATUS] = ðnl_plca_status_request_ops, 418 [ETHTOOL_MSG_MM_GET] = ðnl_mm_request_ops, 419 [ETHTOOL_MSG_MM_SET] = ðnl_mm_request_ops, 420 [ETHTOOL_MSG_TSCONFIG_GET] = ðnl_tsconfig_request_ops, 421 [ETHTOOL_MSG_TSCONFIG_SET] = ðnl_tsconfig_request_ops, 422 [ETHTOOL_MSG_PHY_GET] = ðnl_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 ðtool_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] = ðnl_linkinfo_request_ops, 948 [ETHTOOL_MSG_LINKMODES_NTF] = ðnl_linkmodes_request_ops, 949 [ETHTOOL_MSG_DEBUG_NTF] = ðnl_debug_request_ops, 950 [ETHTOOL_MSG_WOL_NTF] = ðnl_wol_request_ops, 951 [ETHTOOL_MSG_FEATURES_NTF] = ðnl_features_request_ops, 952 [ETHTOOL_MSG_PRIVFLAGS_NTF] = ðnl_privflags_request_ops, 953 [ETHTOOL_MSG_RINGS_NTF] = ðnl_rings_request_ops, 954 [ETHTOOL_MSG_CHANNELS_NTF] = ðnl_channels_request_ops, 955 [ETHTOOL_MSG_COALESCE_NTF] = ðnl_coalesce_request_ops, 956 [ETHTOOL_MSG_PAUSE_NTF] = ðnl_pause_request_ops, 957 [ETHTOOL_MSG_EEE_NTF] = ðnl_eee_request_ops, 958 [ETHTOOL_MSG_FEC_NTF] = ðnl_fec_request_ops, 959 [ETHTOOL_MSG_MODULE_NTF] = ðnl_module_request_ops, 960 [ETHTOOL_MSG_PLCA_NTF] = ðnl_plca_cfg_request_ops, 961 [ETHTOOL_MSG_MM_NTF] = ðnl_mm_request_ops, 962 [ETHTOOL_MSG_RSS_NTF] = ðnl_rss_request_ops, 963 [ETHTOOL_MSG_RSS_CREATE_NTF] = ðnl_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, ðtool_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(ðtool_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(ðnl_netdev_notifier); 1569 WARN(ret < 0, "ethtool: net device notifier registration failed"); 1570 return ret; 1571 } 1572 1573 subsys_initcall(ethnl_init); 1574