File Index
Files and directories
Sign in
FILE

netlink.c

File preview with syntax highlighting.

linux-6.19.14/net/ethtool/netlink.c C
   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
  12static struct genl_family ethtool_genl_family;
  13
  14static bool ethnl_ok __read_mostly;
  15static 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
  21const 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
  29const 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
  37const 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
  46const 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
  55int 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
  71static 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
  84u32 ethnl_bcast_seq_next(void)
  85{
  86	ASSERT_RTNL();
  87	return ++ethnl_bcast_seq;
  88}
  89
  90int 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;
 115err:
 116	if (dev->dev.parent)
 117		pm_runtime_put(dev->dev.parent);
 118
 119	return ret;
 120}
 121
 122void 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 */
 147int 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
 222struct 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 */
 256int 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
 277nla_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 */
 293struct 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
 315err_free:
 316	nlmsg_free(skb);
 317err:
 318	if (info)
 319		GENL_SET_ERR_MSG(info, "failed to setup reply message");
 320	return NULL;
 321}
 322
 323void *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
 329void *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
 335void *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
 340int 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 */
 359struct 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 */
 372struct ethnl_perphy_dump_ctx {
 373	struct ethnl_dump_ctx	ethnl_ctx;
 374	unsigned int		ifindex;
 375	unsigned long		pos_phyindex;
 376};
 377
 378static const struct ethnl_request_ops *
 379ethnl_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	[ETHTOOL_MSG_MSE_GET]		= &ethnl_mse_request_ops,
 424};
 425
 426static struct ethnl_dump_ctx *ethnl_dump_context(struct netlink_callback *cb)
 427{
 428	return (struct ethnl_dump_ctx *)cb->ctx;
 429}
 430
 431static struct ethnl_perphy_dump_ctx *
 432ethnl_perphy_dump_context(struct netlink_callback *cb)
 433{
 434	return (struct ethnl_perphy_dump_ctx *)cb->ctx;
 435}
 436
 437/**
 438 * ethnl_default_parse() - Parse request message
 439 * @req_info:    pointer to structure to put data into
 440 * @info:	 genl_info from the request
 441 * @request_ops: struct request_ops for request type
 442 * @require_dev: fail if no device identified in header
 443 *
 444 * Parse universal request header and call request specific ->parse_request()
 445 * callback (if defined) to parse the rest of the message.
 446 *
 447 * Return: 0 on success or negative error code
 448 */
 449static int ethnl_default_parse(struct ethnl_req_info *req_info,
 450			       const struct genl_info *info,
 451			       const struct ethnl_request_ops *request_ops,
 452			       bool require_dev)
 453{
 454	struct nlattr **tb = info->attrs;
 455	int ret;
 456
 457	ret = ethnl_parse_header_dev_get(req_info, tb[request_ops->hdr_attr],
 458					 genl_info_net(info), info->extack,
 459					 require_dev);
 460	if (ret < 0)
 461		return ret;
 462
 463	if (request_ops->parse_request) {
 464		ret = request_ops->parse_request(req_info, tb, info->extack);
 465		if (ret < 0)
 466			goto err_dev;
 467	}
 468
 469	return 0;
 470
 471err_dev:
 472	netdev_put(req_info->dev, &req_info->dev_tracker);
 473	req_info->dev = NULL;
 474	return ret;
 475}
 476
 477/**
 478 * ethnl_init_reply_data() - Initialize reply data for GET request
 479 * @reply_data: pointer to embedded struct ethnl_reply_data
 480 * @ops:        instance of struct ethnl_request_ops describing the layout
 481 * @dev:        network device to initialize the reply for
 482 *
 483 * Fills the reply data part with zeros and sets the dev member. Must be called
 484 * before calling the ->fill_reply() callback (for each iteration when handling
 485 * dump requests).
 486 */
 487static void ethnl_init_reply_data(struct ethnl_reply_data *reply_data,
 488				  const struct ethnl_request_ops *ops,
 489				  struct net_device *dev)
 490{
 491	memset(reply_data, 0, ops->reply_data_size);
 492	reply_data->dev = dev;
 493}
 494
 495/* default ->doit() handler for GET type requests */
 496static int ethnl_default_doit(struct sk_buff *skb, struct genl_info *info)
 497{
 498	struct ethnl_reply_data *reply_data = NULL;
 499	struct ethnl_req_info *req_info = NULL;
 500	const u8 cmd = info->genlhdr->cmd;
 501	const struct ethnl_request_ops *ops;
 502	int hdr_len, reply_len;
 503	struct sk_buff *rskb;
 504	void *reply_payload;
 505	int ret;
 506
 507	ops = ethnl_default_requests[cmd];
 508	if (WARN_ONCE(!ops, "cmd %u has no ethnl_request_ops\n", cmd))
 509		return -EOPNOTSUPP;
 510	if (GENL_REQ_ATTR_CHECK(info, ops->hdr_attr))
 511		return -EINVAL;
 512
 513	req_info = kzalloc(ops->req_info_size, GFP_KERNEL);
 514	if (!req_info)
 515		return -ENOMEM;
 516	reply_data = kmalloc(ops->reply_data_size, GFP_KERNEL);
 517	if (!reply_data) {
 518		kfree(req_info);
 519		return -ENOMEM;
 520	}
 521
 522	ret = ethnl_default_parse(req_info, info, ops, !ops->allow_nodev_do);
 523	if (ret < 0)
 524		goto err_free;
 525	ethnl_init_reply_data(reply_data, ops, req_info->dev);
 526
 527	rtnl_lock();
 528	if (req_info->dev)
 529		netdev_lock_ops(req_info->dev);
 530	ret = ops->prepare_data(req_info, reply_data, info);
 531	if (req_info->dev)
 532		netdev_unlock_ops(req_info->dev);
 533	rtnl_unlock();
 534	if (ret < 0)
 535		goto err_dev;
 536	ret = ops->reply_size(req_info, reply_data);
 537	if (ret < 0)
 538		goto err_cleanup;
 539	reply_len = ret;
 540	ret = -ENOMEM;
 541	rskb = ethnl_reply_init(reply_len + ethnl_reply_header_size(),
 542				req_info->dev, ops->reply_cmd,
 543				ops->hdr_attr, info, &reply_payload);
 544	if (!rskb)
 545		goto err_cleanup;
 546	hdr_len = rskb->len;
 547	ret = ops->fill_reply(rskb, req_info, reply_data);
 548	if (ret < 0)
 549		goto err_msg;
 550	WARN_ONCE(rskb->len - hdr_len > reply_len,
 551		  "ethnl cmd %d: calculated reply length %d, but consumed %d\n",
 552		  cmd, reply_len, rskb->len - hdr_len);
 553	if (ops->cleanup_data)
 554		ops->cleanup_data(reply_data);
 555
 556	genlmsg_end(rskb, reply_payload);
 557	netdev_put(req_info->dev, &req_info->dev_tracker);
 558	kfree(reply_data);
 559	kfree(req_info);
 560	return genlmsg_reply(rskb, info);
 561
 562err_msg:
 563	WARN_ONCE(ret == -EMSGSIZE, "calculated message payload length (%d) not sufficient\n", reply_len);
 564	nlmsg_free(rskb);
 565err_cleanup:
 566	if (ops->cleanup_data)
 567		ops->cleanup_data(reply_data);
 568err_dev:
 569	netdev_put(req_info->dev, &req_info->dev_tracker);
 570err_free:
 571	kfree(reply_data);
 572	kfree(req_info);
 573	return ret;
 574}
 575
 576static int ethnl_default_dump_one(struct sk_buff *skb, struct net_device *dev,
 577				  const struct ethnl_dump_ctx *ctx,
 578				  const struct genl_info *info)
 579{
 580	void *ehdr;
 581	int ret;
 582
 583	ehdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
 584			   &ethtool_genl_family, NLM_F_MULTI,
 585			   ctx->ops->reply_cmd);
 586	if (!ehdr)
 587		return -EMSGSIZE;
 588
 589	ethnl_init_reply_data(ctx->reply_data, ctx->ops, dev);
 590	rtnl_lock();
 591	netdev_lock_ops(dev);
 592	ret = ctx->ops->prepare_data(ctx->req_info, ctx->reply_data, info);
 593	netdev_unlock_ops(dev);
 594	rtnl_unlock();
 595	if (ret < 0)
 596		goto out_cancel;
 597	ret = ethnl_fill_reply_header(skb, dev, ctx->ops->hdr_attr);
 598	if (ret < 0)
 599		goto out;
 600	ret = ctx->ops->fill_reply(skb, ctx->req_info, ctx->reply_data);
 601
 602out:
 603	if (ctx->ops->cleanup_data)
 604		ctx->ops->cleanup_data(ctx->reply_data);
 605out_cancel:
 606	ctx->reply_data->dev = NULL;
 607	if (ret < 0)
 608		genlmsg_cancel(skb, ehdr);
 609	else
 610		genlmsg_end(skb, ehdr);
 611	return ret;
 612}
 613
 614/* Default ->dumpit() handler for GET requests. */
 615static int ethnl_default_dumpit(struct sk_buff *skb,
 616				struct netlink_callback *cb)
 617{
 618	struct ethnl_dump_ctx *ctx = ethnl_dump_context(cb);
 619	struct net *net = sock_net(skb->sk);
 620	netdevice_tracker dev_tracker;
 621	struct net_device *dev;
 622	int ret = 0;
 623
 624	rcu_read_lock();
 625	for_each_netdev_dump(net, dev, ctx->pos_ifindex) {
 626		netdev_hold(dev, &dev_tracker, GFP_ATOMIC);
 627		rcu_read_unlock();
 628
 629		ret = ethnl_default_dump_one(skb, dev, ctx, genl_info_dump(cb));
 630
 631		rcu_read_lock();
 632		netdev_put(dev, &dev_tracker);
 633
 634		if (ret < 0 && ret != -EOPNOTSUPP) {
 635			if (likely(skb->len))
 636				ret = skb->len;
 637			break;
 638		}
 639		ret = 0;
 640	}
 641	rcu_read_unlock();
 642
 643	return ret;
 644}
 645
 646/* generic ->start() handler for GET requests */
 647static int ethnl_default_start(struct netlink_callback *cb)
 648{
 649	const struct genl_dumpit_info *info = genl_dumpit_info(cb);
 650	struct ethnl_dump_ctx *ctx = ethnl_dump_context(cb);
 651	struct ethnl_reply_data *reply_data;
 652	const struct ethnl_request_ops *ops;
 653	struct ethnl_req_info *req_info;
 654	struct genlmsghdr *ghdr;
 655	int ret;
 656
 657	BUILD_BUG_ON(sizeof(*ctx) > sizeof(cb->ctx));
 658
 659	ghdr = nlmsg_data(cb->nlh);
 660	ops = ethnl_default_requests[ghdr->cmd];
 661	if (WARN_ONCE(!ops, "cmd %u has no ethnl_request_ops\n", ghdr->cmd))
 662		return -EOPNOTSUPP;
 663	req_info = kzalloc(ops->req_info_size, GFP_KERNEL);
 664	if (!req_info)
 665		return -ENOMEM;
 666	reply_data = kmalloc(ops->reply_data_size, GFP_KERNEL);
 667	if (!reply_data) {
 668		ret = -ENOMEM;
 669		goto free_req_info;
 670	}
 671
 672	ret = ethnl_default_parse(req_info, &info->info, ops, false);
 673	if (ret < 0)
 674		goto free_reply_data;
 675	if (req_info->dev) {
 676		/* We ignore device specification in dump requests but as the
 677		 * same parser as for non-dump (doit) requests is used, it
 678		 * would take reference to the device if it finds one
 679		 */
 680		netdev_put(req_info->dev, &req_info->dev_tracker);
 681		req_info->dev = NULL;
 682	}
 683
 684	ctx->ops = ops;
 685	ctx->req_info = req_info;
 686	ctx->reply_data = reply_data;
 687	ctx->pos_ifindex = 0;
 688
 689	return 0;
 690
 691free_reply_data:
 692	kfree(reply_data);
 693free_req_info:
 694	kfree(req_info);
 695
 696	return ret;
 697}
 698
 699/* per-PHY ->start() handler for GET requests */
 700static int ethnl_perphy_start(struct netlink_callback *cb)
 701{
 702	struct ethnl_perphy_dump_ctx *phy_ctx = ethnl_perphy_dump_context(cb);
 703	const struct genl_dumpit_info *info = genl_dumpit_info(cb);
 704	struct ethnl_dump_ctx *ctx = &phy_ctx->ethnl_ctx;
 705	struct ethnl_reply_data *reply_data;
 706	const struct ethnl_request_ops *ops;
 707	struct ethnl_req_info *req_info;
 708	struct genlmsghdr *ghdr;
 709	int ret;
 710
 711	BUILD_BUG_ON(sizeof(*ctx) > sizeof(cb->ctx));
 712
 713	ghdr = nlmsg_data(cb->nlh);
 714	ops = ethnl_default_requests[ghdr->cmd];
 715	if (WARN_ONCE(!ops, "cmd %u has no ethnl_request_ops\n", ghdr->cmd))
 716		return -EOPNOTSUPP;
 717	req_info = kzalloc(ops->req_info_size, GFP_KERNEL);
 718	if (!req_info)
 719		return -ENOMEM;
 720	reply_data = kmalloc(ops->reply_data_size, GFP_KERNEL);
 721	if (!reply_data) {
 722		ret = -ENOMEM;
 723		goto free_req_info;
 724	}
 725
 726	/* Unlike per-dev dump, don't ignore dev. The dump handler
 727	 * will notice it and dump PHYs from given dev. We only keep track of
 728	 * the dev's ifindex, .dumpit() will grab and release the netdev itself.
 729	 */
 730	ret = ethnl_default_parse(req_info, &info->info, ops, false);
 731	if (ret < 0)
 732		goto free_reply_data;
 733	if (req_info->dev) {
 734		phy_ctx->ifindex = req_info->dev->ifindex;
 735		netdev_put(req_info->dev, &req_info->dev_tracker);
 736		req_info->dev = NULL;
 737	}
 738
 739	ctx->ops = ops;
 740	ctx->req_info = req_info;
 741	ctx->reply_data = reply_data;
 742	ctx->pos_ifindex = 0;
 743
 744	return 0;
 745
 746free_reply_data:
 747	kfree(reply_data);
 748free_req_info:
 749	kfree(req_info);
 750
 751	return ret;
 752}
 753
 754static int ethnl_perphy_dump_one_dev(struct sk_buff *skb,
 755				     struct ethnl_perphy_dump_ctx *ctx,
 756				     const struct genl_info *info)
 757{
 758	struct ethnl_dump_ctx *ethnl_ctx = &ctx->ethnl_ctx;
 759	struct net_device *dev = ethnl_ctx->req_info->dev;
 760	struct phy_device_node *pdn;
 761	int ret;
 762
 763	if (!dev->link_topo)
 764		return 0;
 765
 766	xa_for_each_start(&dev->link_topo->phys, ctx->pos_phyindex, pdn,
 767			  ctx->pos_phyindex) {
 768		ethnl_ctx->req_info->phy_index = ctx->pos_phyindex;
 769
 770		/* We can re-use the original dump_one as ->prepare_data in
 771		 * commands use ethnl_req_get_phydev(), which gets the PHY from
 772		 * the req_info->phy_index
 773		 */
 774		ret = ethnl_default_dump_one(skb, dev, ethnl_ctx, info);
 775		if (ret)
 776			return ret;
 777	}
 778
 779	ctx->pos_phyindex = 0;
 780
 781	return 0;
 782}
 783
 784static int ethnl_perphy_dump_all_dev(struct sk_buff *skb,
 785				     struct ethnl_perphy_dump_ctx *ctx,
 786				     const struct genl_info *info)
 787{
 788	struct ethnl_dump_ctx *ethnl_ctx = &ctx->ethnl_ctx;
 789	struct net *net = sock_net(skb->sk);
 790	netdevice_tracker dev_tracker;
 791	struct net_device *dev;
 792	int ret = 0;
 793
 794	rcu_read_lock();
 795	for_each_netdev_dump(net, dev, ethnl_ctx->pos_ifindex) {
 796		netdev_hold(dev, &dev_tracker, GFP_ATOMIC);
 797		rcu_read_unlock();
 798
 799		/* per-PHY commands use ethnl_req_get_phydev(), which needs the
 800		 * net_device in the req_info
 801		 */
 802		ethnl_ctx->req_info->dev = dev;
 803		ret = ethnl_perphy_dump_one_dev(skb, ctx, info);
 804
 805		rcu_read_lock();
 806		netdev_put(dev, &dev_tracker);
 807		ethnl_ctx->req_info->dev = NULL;
 808
 809		if (ret < 0 && ret != -EOPNOTSUPP) {
 810			if (likely(skb->len))
 811				ret = skb->len;
 812			break;
 813		}
 814		ret = 0;
 815	}
 816	rcu_read_unlock();
 817
 818	return ret;
 819}
 820
 821/* per-PHY ->dumpit() handler for GET requests. */
 822static int ethnl_perphy_dumpit(struct sk_buff *skb,
 823			       struct netlink_callback *cb)
 824{
 825	struct ethnl_perphy_dump_ctx *ctx = ethnl_perphy_dump_context(cb);
 826	const struct genl_dumpit_info *info = genl_dumpit_info(cb);
 827	struct ethnl_dump_ctx *ethnl_ctx = &ctx->ethnl_ctx;
 828	int ret = 0;
 829
 830	if (ctx->ifindex) {
 831		netdevice_tracker dev_tracker;
 832		struct net_device *dev;
 833
 834		dev = netdev_get_by_index(genl_info_net(&info->info),
 835					  ctx->ifindex, &dev_tracker,
 836					  GFP_KERNEL);
 837		if (!dev)
 838			return -ENODEV;
 839
 840		ethnl_ctx->req_info->dev = dev;
 841		ret = ethnl_perphy_dump_one_dev(skb, ctx, genl_info_dump(cb));
 842
 843		if (ret < 0 && ret != -EOPNOTSUPP && likely(skb->len))
 844			ret = skb->len;
 845
 846		netdev_put(dev, &dev_tracker);
 847	} else {
 848		ret = ethnl_perphy_dump_all_dev(skb, ctx, genl_info_dump(cb));
 849	}
 850
 851	return ret;
 852}
 853
 854/* per-PHY ->done() handler for GET requests */
 855static int ethnl_perphy_done(struct netlink_callback *cb)
 856{
 857	struct ethnl_perphy_dump_ctx *ctx = ethnl_perphy_dump_context(cb);
 858	struct ethnl_dump_ctx *ethnl_ctx = &ctx->ethnl_ctx;
 859
 860	kfree(ethnl_ctx->reply_data);
 861	kfree(ethnl_ctx->req_info);
 862
 863	return 0;
 864}
 865
 866/* default ->done() handler for GET requests */
 867static int ethnl_default_done(struct netlink_callback *cb)
 868{
 869	struct ethnl_dump_ctx *ctx = ethnl_dump_context(cb);
 870
 871	kfree(ctx->reply_data);
 872	kfree(ctx->req_info);
 873
 874	return 0;
 875}
 876
 877static int ethnl_default_set_doit(struct sk_buff *skb, struct genl_info *info)
 878{
 879	const struct ethnl_request_ops *ops;
 880	const u8 cmd = info->genlhdr->cmd;
 881	struct ethnl_req_info *req_info;
 882	struct net_device *dev;
 883	int ret;
 884
 885	ops = ethnl_default_requests[cmd];
 886	if (WARN_ONCE(!ops, "cmd %u has no ethnl_request_ops\n", cmd))
 887		return -EOPNOTSUPP;
 888	if (GENL_REQ_ATTR_CHECK(info, ops->hdr_attr))
 889		return -EINVAL;
 890
 891	req_info = kzalloc(ops->req_info_size, GFP_KERNEL);
 892	if (!req_info)
 893		return -ENOMEM;
 894
 895	ret = ethnl_default_parse(req_info, info,  ops, true);
 896	if (ret < 0)
 897		goto out_free_req;
 898
 899	if (ops->set_validate) {
 900		ret = ops->set_validate(req_info, info);
 901		/* 0 means nothing to do */
 902		if (ret <= 0)
 903			goto out_dev;
 904	}
 905
 906	dev = req_info->dev;
 907
 908	rtnl_lock();
 909	netdev_lock_ops(dev);
 910	dev->cfg_pending = kmemdup(dev->cfg, sizeof(*dev->cfg),
 911				   GFP_KERNEL_ACCOUNT);
 912	if (!dev->cfg_pending) {
 913		ret = -ENOMEM;
 914		goto out_tie_cfg;
 915	}
 916
 917	ret = ethnl_ops_begin(dev);
 918	if (ret < 0)
 919		goto out_free_cfg;
 920
 921	ret = ops->set(req_info, info);
 922	if (ret < 0)
 923		goto out_ops;
 924
 925	swap(dev->cfg, dev->cfg_pending);
 926	if (!ret)
 927		goto out_ops;
 928	ethnl_notify(dev, ops->set_ntf_cmd, req_info);
 929
 930	ret = 0;
 931out_ops:
 932	ethnl_ops_complete(dev);
 933out_free_cfg:
 934	kfree(dev->cfg_pending);
 935out_tie_cfg:
 936	dev->cfg_pending = dev->cfg;
 937	netdev_unlock_ops(dev);
 938	rtnl_unlock();
 939out_dev:
 940	ethnl_parse_header_dev_put(req_info);
 941out_free_req:
 942	kfree(req_info);
 943	return ret;
 944}
 945
 946static const struct ethnl_request_ops *
 947ethnl_default_notify_ops[ETHTOOL_MSG_KERNEL_MAX + 1] = {
 948	[ETHTOOL_MSG_LINKINFO_NTF]	= &ethnl_linkinfo_request_ops,
 949	[ETHTOOL_MSG_LINKMODES_NTF]	= &ethnl_linkmodes_request_ops,
 950	[ETHTOOL_MSG_DEBUG_NTF]		= &ethnl_debug_request_ops,
 951	[ETHTOOL_MSG_WOL_NTF]		= &ethnl_wol_request_ops,
 952	[ETHTOOL_MSG_FEATURES_NTF]	= &ethnl_features_request_ops,
 953	[ETHTOOL_MSG_PRIVFLAGS_NTF]	= &ethnl_privflags_request_ops,
 954	[ETHTOOL_MSG_RINGS_NTF]		= &ethnl_rings_request_ops,
 955	[ETHTOOL_MSG_CHANNELS_NTF]	= &ethnl_channels_request_ops,
 956	[ETHTOOL_MSG_COALESCE_NTF]	= &ethnl_coalesce_request_ops,
 957	[ETHTOOL_MSG_PAUSE_NTF]		= &ethnl_pause_request_ops,
 958	[ETHTOOL_MSG_EEE_NTF]		= &ethnl_eee_request_ops,
 959	[ETHTOOL_MSG_FEC_NTF]		= &ethnl_fec_request_ops,
 960	[ETHTOOL_MSG_MODULE_NTF]	= &ethnl_module_request_ops,
 961	[ETHTOOL_MSG_PLCA_NTF]		= &ethnl_plca_cfg_request_ops,
 962	[ETHTOOL_MSG_MM_NTF]		= &ethnl_mm_request_ops,
 963	[ETHTOOL_MSG_RSS_NTF]		= &ethnl_rss_request_ops,
 964	[ETHTOOL_MSG_RSS_CREATE_NTF]	= &ethnl_rss_request_ops,
 965};
 966
 967/* default notification handler */
 968static void ethnl_default_notify(struct net_device *dev, unsigned int cmd,
 969				 const struct ethnl_req_info *orig_req_info)
 970{
 971	struct ethnl_reply_data *reply_data;
 972	const struct ethnl_request_ops *ops;
 973	struct ethnl_req_info *req_info;
 974	struct genl_info info;
 975	struct sk_buff *skb;
 976	void *reply_payload;
 977	int reply_len;
 978	int ret;
 979
 980	genl_info_init_ntf(&info, &ethtool_genl_family, cmd);
 981
 982	if (WARN_ONCE(cmd > ETHTOOL_MSG_KERNEL_MAX ||
 983		      !ethnl_default_notify_ops[cmd],
 984		      "unexpected notification type %u\n", cmd))
 985		return;
 986	ops = ethnl_default_notify_ops[cmd];
 987	req_info = kzalloc(ops->req_info_size, GFP_KERNEL);
 988	if (!req_info)
 989		return;
 990	reply_data = kmalloc(ops->reply_data_size, GFP_KERNEL);
 991	if (!reply_data) {
 992		kfree(req_info);
 993		return;
 994	}
 995
 996	req_info->dev = dev;
 997	req_info->flags |= ETHTOOL_FLAG_COMPACT_BITSETS;
 998	if (orig_req_info) {
 999		req_info->phy_index = orig_req_info->phy_index;
1000		memcpy(&req_info[1], &orig_req_info[1],
1001		       ops->req_info_size - sizeof(*req_info));
1002	}
1003
1004	netdev_ops_assert_locked(dev);
1005
1006	ethnl_init_reply_data(reply_data, ops, dev);
1007	ret = ops->prepare_data(req_info, reply_data, &info);
1008	if (ret < 0)
1009		goto err_rep;
1010	ret = ops->reply_size(req_info, reply_data);
1011	if (ret < 0)
1012		goto err_cleanup;
1013	reply_len = ret + ethnl_reply_header_size();
1014	skb = genlmsg_new(reply_len, GFP_KERNEL);
1015	if (!skb)
1016		goto err_cleanup;
1017	reply_payload = ethnl_bcastmsg_put(skb, cmd);
1018	if (!reply_payload)
1019		goto err_skb;
1020	ret = ethnl_fill_reply_header(skb, dev, ops->hdr_attr);
1021	if (ret < 0)
1022		goto err_msg;
1023	ret = ops->fill_reply(skb, req_info, reply_data);
1024	if (ret < 0)
1025		goto err_msg;
1026	if (ops->cleanup_data)
1027		ops->cleanup_data(reply_data);
1028
1029	genlmsg_end(skb, reply_payload);
1030	kfree(reply_data);
1031	kfree(req_info);
1032	ethnl_multicast(skb, dev);
1033	return;
1034
1035err_msg:
1036	WARN_ONCE(ret == -EMSGSIZE,
1037		  "calculated message payload length (%d) not sufficient\n",
1038		  reply_len);
1039err_skb:
1040	nlmsg_free(skb);
1041err_cleanup:
1042	if (ops->cleanup_data)
1043		ops->cleanup_data(reply_data);
1044err_rep:
1045	kfree(reply_data);
1046	kfree(req_info);
1047	return;
1048}
1049
1050/* notifications */
1051
1052typedef void (*ethnl_notify_handler_t)(struct net_device *dev, unsigned int cmd,
1053				       const struct ethnl_req_info *req_info);
1054
1055static const ethnl_notify_handler_t ethnl_notify_handlers[] = {
1056	[ETHTOOL_MSG_LINKINFO_NTF]	= ethnl_default_notify,
1057	[ETHTOOL_MSG_LINKMODES_NTF]	= ethnl_default_notify,
1058	[ETHTOOL_MSG_DEBUG_NTF]		= ethnl_default_notify,
1059	[ETHTOOL_MSG_WOL_NTF]		= ethnl_default_notify,
1060	[ETHTOOL_MSG_FEATURES_NTF]	= ethnl_default_notify,
1061	[ETHTOOL_MSG_PRIVFLAGS_NTF]	= ethnl_default_notify,
1062	[ETHTOOL_MSG_RINGS_NTF]		= ethnl_default_notify,
1063	[ETHTOOL_MSG_CHANNELS_NTF]	= ethnl_default_notify,
1064	[ETHTOOL_MSG_COALESCE_NTF]	= ethnl_default_notify,
1065	[ETHTOOL_MSG_PAUSE_NTF]		= ethnl_default_notify,
1066	[ETHTOOL_MSG_EEE_NTF]		= ethnl_default_notify,
1067	[ETHTOOL_MSG_FEC_NTF]		= ethnl_default_notify,
1068	[ETHTOOL_MSG_MODULE_NTF]	= ethnl_default_notify,
1069	[ETHTOOL_MSG_PLCA_NTF]		= ethnl_default_notify,
1070	[ETHTOOL_MSG_MM_NTF]		= ethnl_default_notify,
1071	[ETHTOOL_MSG_RSS_NTF]		= ethnl_default_notify,
1072	[ETHTOOL_MSG_RSS_CREATE_NTF]	= ethnl_default_notify,
1073};
1074
1075void ethnl_notify(struct net_device *dev, unsigned int cmd,
1076		  const struct ethnl_req_info *req_info)
1077{
1078	if (unlikely(!ethnl_ok))
1079		return;
1080	ASSERT_RTNL();
1081
1082	if (likely(cmd < ARRAY_SIZE(ethnl_notify_handlers) &&
1083		   ethnl_notify_handlers[cmd]))
1084		ethnl_notify_handlers[cmd](dev, cmd, req_info);
1085	else
1086		WARN_ONCE(1, "notification %u not implemented (dev=%s)\n",
1087			  cmd, netdev_name(dev));
1088}
1089
1090void ethtool_notify(struct net_device *dev, unsigned int cmd)
1091{
1092	ethnl_notify(dev, cmd, NULL);
1093}
1094EXPORT_SYMBOL(ethtool_notify);
1095
1096static void ethnl_notify_features(struct netdev_notifier_info *info)
1097{
1098	struct net_device *dev = netdev_notifier_info_to_dev(info);
1099
1100	ethtool_notify(dev, ETHTOOL_MSG_FEATURES_NTF);
1101}
1102
1103static int ethnl_netdev_event(struct notifier_block *this, unsigned long event,
1104			      void *ptr)
1105{
1106	struct netdev_notifier_info *info = ptr;
1107	struct netlink_ext_ack *extack;
1108	struct net_device *dev;
1109
1110	dev = netdev_notifier_info_to_dev(info);
1111	extack = netdev_notifier_info_to_extack(info);
1112
1113	switch (event) {
1114	case NETDEV_FEAT_CHANGE:
1115		ethnl_notify_features(ptr);
1116		break;
1117	case NETDEV_PRE_UP:
1118		if (dev->ethtool->module_fw_flash_in_progress) {
1119			NL_SET_ERR_MSG(extack, "Can't set port up while flashing module firmware");
1120			return NOTIFY_BAD;
1121		}
1122	}
1123
1124	return NOTIFY_DONE;
1125}
1126
1127static struct notifier_block ethnl_netdev_notifier = {
1128	.notifier_call = ethnl_netdev_event,
1129};
1130
1131/* genetlink setup */
1132
1133static const struct genl_ops ethtool_genl_ops[] = {
1134	{
1135		.cmd	= ETHTOOL_MSG_STRSET_GET,
1136		.doit	= ethnl_default_doit,
1137		.start	= ethnl_default_start,
1138		.dumpit	= ethnl_default_dumpit,
1139		.done	= ethnl_default_done,
1140		.policy = ethnl_strset_get_policy,
1141		.maxattr = ARRAY_SIZE(ethnl_strset_get_policy) - 1,
1142	},
1143	{
1144		.cmd	= ETHTOOL_MSG_LINKINFO_GET,
1145		.doit	= ethnl_default_doit,
1146		.start	= ethnl_default_start,
1147		.dumpit	= ethnl_default_dumpit,
1148		.done	= ethnl_default_done,
1149		.policy = ethnl_linkinfo_get_policy,
1150		.maxattr = ARRAY_SIZE(ethnl_linkinfo_get_policy) - 1,
1151	},
1152	{
1153		.cmd	= ETHTOOL_MSG_LINKINFO_SET,
1154		.flags	= GENL_UNS_ADMIN_PERM,
1155		.doit	= ethnl_default_set_doit,
1156		.policy = ethnl_linkinfo_set_policy,
1157		.maxattr = ARRAY_SIZE(ethnl_linkinfo_set_policy) - 1,
1158	},
1159	{
1160		.cmd	= ETHTOOL_MSG_LINKMODES_GET,
1161		.doit	= ethnl_default_doit,
1162		.start	= ethnl_default_start,
1163		.dumpit	= ethnl_default_dumpit,
1164		.done	= ethnl_default_done,
1165		.policy = ethnl_linkmodes_get_policy,
1166		.maxattr = ARRAY_SIZE(ethnl_linkmodes_get_policy) - 1,
1167	},
1168	{
1169		.cmd	= ETHTOOL_MSG_LINKMODES_SET,
1170		.flags	= GENL_UNS_ADMIN_PERM,
1171		.doit	= ethnl_default_set_doit,
1172		.policy = ethnl_linkmodes_set_policy,
1173		.maxattr = ARRAY_SIZE(ethnl_linkmodes_set_policy) - 1,
1174	},
1175	{
1176		.cmd	= ETHTOOL_MSG_LINKSTATE_GET,
1177		.doit	= ethnl_default_doit,
1178		.start	= ethnl_default_start,
1179		.dumpit	= ethnl_default_dumpit,
1180		.done	= ethnl_default_done,
1181		.policy = ethnl_linkstate_get_policy,
1182		.maxattr = ARRAY_SIZE(ethnl_linkstate_get_policy) - 1,
1183	},
1184	{
1185		.cmd	= ETHTOOL_MSG_DEBUG_GET,
1186		.doit	= ethnl_default_doit,
1187		.start	= ethnl_default_start,
1188		.dumpit	= ethnl_default_dumpit,
1189		.done	= ethnl_default_done,
1190		.policy = ethnl_debug_get_policy,
1191		.maxattr = ARRAY_SIZE(ethnl_debug_get_policy) - 1,
1192	},
1193	{
1194		.cmd	= ETHTOOL_MSG_DEBUG_SET,
1195		.flags	= GENL_UNS_ADMIN_PERM,
1196		.doit	= ethnl_default_set_doit,
1197		.policy = ethnl_debug_set_policy,
1198		.maxattr = ARRAY_SIZE(ethnl_debug_set_policy) - 1,
1199	},
1200	{
1201		.cmd	= ETHTOOL_MSG_WOL_GET,
1202		.flags	= GENL_UNS_ADMIN_PERM,
1203		.doit	= ethnl_default_doit,
1204		.start	= ethnl_default_start,
1205		.dumpit	= ethnl_default_dumpit,
1206		.done	= ethnl_default_done,
1207		.policy = ethnl_wol_get_policy,
1208		.maxattr = ARRAY_SIZE(ethnl_wol_get_policy) - 1,
1209	},
1210	{
1211		.cmd	= ETHTOOL_MSG_WOL_SET,
1212		.flags	= GENL_UNS_ADMIN_PERM,
1213		.doit	= ethnl_default_set_doit,
1214		.policy = ethnl_wol_set_policy,
1215		.maxattr = ARRAY_SIZE(ethnl_wol_set_policy) - 1,
1216	},
1217	{
1218		.cmd	= ETHTOOL_MSG_FEATURES_GET,
1219		.doit	= ethnl_default_doit,
1220		.start	= ethnl_default_start,
1221		.dumpit	= ethnl_default_dumpit,
1222		.done	= ethnl_default_done,
1223		.policy = ethnl_features_get_policy,
1224		.maxattr = ARRAY_SIZE(ethnl_features_get_policy) - 1,
1225	},
1226	{
1227		.cmd	= ETHTOOL_MSG_FEATURES_SET,
1228		.flags	= GENL_UNS_ADMIN_PERM,
1229		.doit	= ethnl_set_features,
1230		.policy = ethnl_features_set_policy,
1231		.maxattr = ARRAY_SIZE(ethnl_features_set_policy) - 1,
1232	},
1233	{
1234		.cmd	= ETHTOOL_MSG_PRIVFLAGS_GET,
1235		.doit	= ethnl_default_doit,
1236		.start	= ethnl_default_start,
1237		.dumpit	= ethnl_default_dumpit,
1238		.done	= ethnl_default_done,
1239		.policy = ethnl_privflags_get_policy,
1240		.maxattr = ARRAY_SIZE(ethnl_privflags_get_policy) - 1,
1241	},
1242	{
1243		.cmd	= ETHTOOL_MSG_PRIVFLAGS_SET,
1244		.flags	= GENL_UNS_ADMIN_PERM,
1245		.doit	= ethnl_default_set_doit,
1246		.policy = ethnl_privflags_set_policy,
1247		.maxattr = ARRAY_SIZE(ethnl_privflags_set_policy) - 1,
1248	},
1249	{
1250		.cmd	= ETHTOOL_MSG_RINGS_GET,
1251		.doit	= ethnl_default_doit,
1252		.start	= ethnl_default_start,
1253		.dumpit	= ethnl_default_dumpit,
1254		.done	= ethnl_default_done,
1255		.policy = ethnl_rings_get_policy,
1256		.maxattr = ARRAY_SIZE(ethnl_rings_get_policy) - 1,
1257	},
1258	{
1259		.cmd	= ETHTOOL_MSG_RINGS_SET,
1260		.flags	= GENL_UNS_ADMIN_PERM,
1261		.doit	= ethnl_default_set_doit,
1262		.policy = ethnl_rings_set_policy,
1263		.maxattr = ARRAY_SIZE(ethnl_rings_set_policy) - 1,
1264	},
1265	{
1266		.cmd	= ETHTOOL_MSG_CHANNELS_GET,
1267		.doit	= ethnl_default_doit,
1268		.start	= ethnl_default_start,
1269		.dumpit	= ethnl_default_dumpit,
1270		.done	= ethnl_default_done,
1271		.policy = ethnl_channels_get_policy,
1272		.maxattr = ARRAY_SIZE(ethnl_channels_get_policy) - 1,
1273	},
1274	{
1275		.cmd	= ETHTOOL_MSG_CHANNELS_SET,
1276		.flags	= GENL_UNS_ADMIN_PERM,
1277		.doit	= ethnl_default_set_doit,
1278		.policy = ethnl_channels_set_policy,
1279		.maxattr = ARRAY_SIZE(ethnl_channels_set_policy) - 1,
1280	},
1281	{
1282		.cmd	= ETHTOOL_MSG_COALESCE_GET,
1283		.doit	= ethnl_default_doit,
1284		.start	= ethnl_default_start,
1285		.dumpit	= ethnl_default_dumpit,
1286		.done	= ethnl_default_done,
1287		.policy = ethnl_coalesce_get_policy,
1288		.maxattr = ARRAY_SIZE(ethnl_coalesce_get_policy) - 1,
1289	},
1290	{
1291		.cmd	= ETHTOOL_MSG_COALESCE_SET,
1292		.flags	= GENL_UNS_ADMIN_PERM,
1293		.doit	= ethnl_default_set_doit,
1294		.policy = ethnl_coalesce_set_policy,
1295		.maxattr = ARRAY_SIZE(ethnl_coalesce_set_policy) - 1,
1296	},
1297	{
1298		.cmd	= ETHTOOL_MSG_PAUSE_GET,
1299		.doit	= ethnl_default_doit,
1300		.start	= ethnl_default_start,
1301		.dumpit	= ethnl_default_dumpit,
1302		.done	= ethnl_default_done,
1303		.policy = ethnl_pause_get_policy,
1304		.maxattr = ARRAY_SIZE(ethnl_pause_get_policy) - 1,
1305	},
1306	{
1307		.cmd	= ETHTOOL_MSG_PAUSE_SET,
1308		.flags	= GENL_UNS_ADMIN_PERM,
1309		.doit	= ethnl_default_set_doit,
1310		.policy = ethnl_pause_set_policy,
1311		.maxattr = ARRAY_SIZE(ethnl_pause_set_policy) - 1,
1312	},
1313	{
1314		.cmd	= ETHTOOL_MSG_EEE_GET,
1315		.doit	= ethnl_default_doit,
1316		.start	= ethnl_default_start,
1317		.dumpit	= ethnl_default_dumpit,
1318		.done	= ethnl_default_done,
1319		.policy = ethnl_eee_get_policy,
1320		.maxattr = ARRAY_SIZE(ethnl_eee_get_policy) - 1,
1321	},
1322	{
1323		.cmd	= ETHTOOL_MSG_EEE_SET,
1324		.flags	= GENL_UNS_ADMIN_PERM,
1325		.doit	= ethnl_default_set_doit,
1326		.policy = ethnl_eee_set_policy,
1327		.maxattr = ARRAY_SIZE(ethnl_eee_set_policy) - 1,
1328	},
1329	{
1330		.cmd	= ETHTOOL_MSG_TSINFO_GET,
1331		.doit	= ethnl_default_doit,
1332		.start	= ethnl_tsinfo_start,
1333		.dumpit	= ethnl_tsinfo_dumpit,
1334		.done	= ethnl_tsinfo_done,
1335		.policy = ethnl_tsinfo_get_policy,
1336		.maxattr = ARRAY_SIZE(ethnl_tsinfo_get_policy) - 1,
1337	},
1338	{
1339		.cmd	= ETHTOOL_MSG_CABLE_TEST_ACT,
1340		.flags	= GENL_UNS_ADMIN_PERM,
1341		.doit	= ethnl_act_cable_test,
1342		.policy = ethnl_cable_test_act_policy,
1343		.maxattr = ARRAY_SIZE(ethnl_cable_test_act_policy) - 1,
1344	},
1345	{
1346		.cmd	= ETHTOOL_MSG_CABLE_TEST_TDR_ACT,
1347		.flags	= GENL_UNS_ADMIN_PERM,
1348		.doit	= ethnl_act_cable_test_tdr,
1349		.policy = ethnl_cable_test_tdr_act_policy,
1350		.maxattr = ARRAY_SIZE(ethnl_cable_test_tdr_act_policy) - 1,
1351	},
1352	{
1353		.cmd	= ETHTOOL_MSG_TUNNEL_INFO_GET,
1354		.doit	= ethnl_tunnel_info_doit,
1355		.start	= ethnl_tunnel_info_start,
1356		.dumpit	= ethnl_tunnel_info_dumpit,
1357		.policy = ethnl_tunnel_info_get_policy,
1358		.maxattr = ARRAY_SIZE(ethnl_tunnel_info_get_policy) - 1,
1359	},
1360	{
1361		.cmd	= ETHTOOL_MSG_FEC_GET,
1362		.doit	= ethnl_default_doit,
1363		.start	= ethnl_default_start,
1364		.dumpit	= ethnl_default_dumpit,
1365		.done	= ethnl_default_done,
1366		.policy = ethnl_fec_get_policy,
1367		.maxattr = ARRAY_SIZE(ethnl_fec_get_policy) - 1,
1368	},
1369	{
1370		.cmd	= ETHTOOL_MSG_FEC_SET,
1371		.flags	= GENL_UNS_ADMIN_PERM,
1372		.doit	= ethnl_default_set_doit,
1373		.policy = ethnl_fec_set_policy,
1374		.maxattr = ARRAY_SIZE(ethnl_fec_set_policy) - 1,
1375	},
1376	{
1377		.cmd	= ETHTOOL_MSG_MODULE_EEPROM_GET,
1378		.flags  = GENL_UNS_ADMIN_PERM,
1379		.doit	= ethnl_default_doit,
1380		.start	= ethnl_default_start,
1381		.dumpit	= ethnl_default_dumpit,
1382		.done	= ethnl_default_done,
1383		.policy = ethnl_module_eeprom_get_policy,
1384		.maxattr = ARRAY_SIZE(ethnl_module_eeprom_get_policy) - 1,
1385	},
1386	{
1387		.cmd	= ETHTOOL_MSG_STATS_GET,
1388		.doit	= ethnl_default_doit,
1389		.start	= ethnl_default_start,
1390		.dumpit	= ethnl_default_dumpit,
1391		.done	= ethnl_default_done,
1392		.policy = ethnl_stats_get_policy,
1393		.maxattr = ARRAY_SIZE(ethnl_stats_get_policy) - 1,
1394	},
1395	{
1396		.cmd	= ETHTOOL_MSG_PHC_VCLOCKS_GET,
1397		.doit	= ethnl_default_doit,
1398		.start	= ethnl_default_start,
1399		.dumpit	= ethnl_default_dumpit,
1400		.done	= ethnl_default_done,
1401		.policy = ethnl_phc_vclocks_get_policy,
1402		.maxattr = ARRAY_SIZE(ethnl_phc_vclocks_get_policy) - 1,
1403	},
1404	{
1405		.cmd	= ETHTOOL_MSG_MODULE_GET,
1406		.doit	= ethnl_default_doit,
1407		.start	= ethnl_default_start,
1408		.dumpit	= ethnl_default_dumpit,
1409		.done	= ethnl_default_done,
1410		.policy = ethnl_module_get_policy,
1411		.maxattr = ARRAY_SIZE(ethnl_module_get_policy) - 1,
1412	},
1413	{
1414		.cmd	= ETHTOOL_MSG_MODULE_SET,
1415		.flags	= GENL_UNS_ADMIN_PERM,
1416		.doit	= ethnl_default_set_doit,
1417		.policy = ethnl_module_set_policy,
1418		.maxattr = ARRAY_SIZE(ethnl_module_set_policy) - 1,
1419	},
1420	{
1421		.cmd	= ETHTOOL_MSG_PSE_GET,
1422		.doit	= ethnl_default_doit,
1423		.start	= ethnl_perphy_start,
1424		.dumpit	= ethnl_perphy_dumpit,
1425		.done	= ethnl_perphy_done,
1426		.policy = ethnl_pse_get_policy,
1427		.maxattr = ARRAY_SIZE(ethnl_pse_get_policy) - 1,
1428	},
1429	{
1430		.cmd	= ETHTOOL_MSG_PSE_SET,
1431		.flags	= GENL_UNS_ADMIN_PERM,
1432		.doit	= ethnl_default_set_doit,
1433		.policy = ethnl_pse_set_policy,
1434		.maxattr = ARRAY_SIZE(ethnl_pse_set_policy) - 1,
1435	},
1436	{
1437		.cmd	= ETHTOOL_MSG_RSS_GET,
1438		.doit	= ethnl_default_doit,
1439		.start	= ethnl_rss_dump_start,
1440		.dumpit	= ethnl_rss_dumpit,
1441		.policy = ethnl_rss_get_policy,
1442		.maxattr = ARRAY_SIZE(ethnl_rss_get_policy) - 1,
1443	},
1444	{
1445		.cmd	= ETHTOOL_MSG_PLCA_GET_CFG,
1446		.doit	= ethnl_default_doit,
1447		.start	= ethnl_perphy_start,
1448		.dumpit	= ethnl_perphy_dumpit,
1449		.done	= ethnl_perphy_done,
1450		.policy = ethnl_plca_get_cfg_policy,
1451		.maxattr = ARRAY_SIZE(ethnl_plca_get_cfg_policy) - 1,
1452	},
1453	{
1454		.cmd	= ETHTOOL_MSG_PLCA_SET_CFG,
1455		.flags	= GENL_UNS_ADMIN_PERM,
1456		.doit	= ethnl_default_set_doit,
1457		.policy = ethnl_plca_set_cfg_policy,
1458		.maxattr = ARRAY_SIZE(ethnl_plca_set_cfg_policy) - 1,
1459	},
1460	{
1461		.cmd	= ETHTOOL_MSG_PLCA_GET_STATUS,
1462		.doit	= ethnl_default_doit,
1463		.start	= ethnl_perphy_start,
1464		.dumpit	= ethnl_perphy_dumpit,
1465		.done	= ethnl_perphy_done,
1466		.policy = ethnl_plca_get_status_policy,
1467		.maxattr = ARRAY_SIZE(ethnl_plca_get_status_policy) - 1,
1468	},
1469	{
1470		.cmd	= ETHTOOL_MSG_MM_GET,
1471		.doit	= ethnl_default_doit,
1472		.start	= ethnl_default_start,
1473		.dumpit	= ethnl_default_dumpit,
1474		.done	= ethnl_default_done,
1475		.policy = ethnl_mm_get_policy,
1476		.maxattr = ARRAY_SIZE(ethnl_mm_get_policy) - 1,
1477	},
1478	{
1479		.cmd	= ETHTOOL_MSG_MM_SET,
1480		.flags	= GENL_UNS_ADMIN_PERM,
1481		.doit	= ethnl_default_set_doit,
1482		.policy = ethnl_mm_set_policy,
1483		.maxattr = ARRAY_SIZE(ethnl_mm_set_policy) - 1,
1484	},
1485	{
1486		.cmd	= ETHTOOL_MSG_MODULE_FW_FLASH_ACT,
1487		.flags	= GENL_UNS_ADMIN_PERM,
1488		.doit	= ethnl_act_module_fw_flash,
1489		.policy	= ethnl_module_fw_flash_act_policy,
1490		.maxattr = ARRAY_SIZE(ethnl_module_fw_flash_act_policy) - 1,
1491	},
1492	{
1493		.cmd	= ETHTOOL_MSG_PHY_GET,
1494		.doit	= ethnl_default_doit,
1495		.start	= ethnl_perphy_start,
1496		.dumpit	= ethnl_perphy_dumpit,
1497		.done	= ethnl_perphy_done,
1498		.policy = ethnl_phy_get_policy,
1499		.maxattr = ARRAY_SIZE(ethnl_phy_get_policy) - 1,
1500	},
1501	{
1502		.cmd	= ETHTOOL_MSG_TSCONFIG_GET,
1503		.doit	= ethnl_default_doit,
1504		.start	= ethnl_default_start,
1505		.dumpit	= ethnl_default_dumpit,
1506		.done	= ethnl_default_done,
1507		.policy = ethnl_tsconfig_get_policy,
1508		.maxattr = ARRAY_SIZE(ethnl_tsconfig_get_policy) - 1,
1509	},
1510	{
1511		.cmd	= ETHTOOL_MSG_TSCONFIG_SET,
1512		.flags	= GENL_UNS_ADMIN_PERM,
1513		.doit	= ethnl_default_set_doit,
1514		.policy = ethnl_tsconfig_set_policy,
1515		.maxattr = ARRAY_SIZE(ethnl_tsconfig_set_policy) - 1,
1516	},
1517	{
1518		.cmd	= ETHTOOL_MSG_RSS_SET,
1519		.flags	= GENL_UNS_ADMIN_PERM,
1520		.doit	= ethnl_default_set_doit,
1521		.policy = ethnl_rss_set_policy,
1522		.maxattr = ARRAY_SIZE(ethnl_rss_set_policy) - 1,
1523	},
1524	{
1525		.cmd	= ETHTOOL_MSG_RSS_CREATE_ACT,
1526		.flags	= GENL_UNS_ADMIN_PERM,
1527		.doit	= ethnl_rss_create_doit,
1528		.policy	= ethnl_rss_create_policy,
1529		.maxattr = ARRAY_SIZE(ethnl_rss_create_policy) - 1,
1530	},
1531	{
1532		.cmd	= ETHTOOL_MSG_RSS_DELETE_ACT,
1533		.flags	= GENL_UNS_ADMIN_PERM,
1534		.doit	= ethnl_rss_delete_doit,
1535		.policy	= ethnl_rss_delete_policy,
1536		.maxattr = ARRAY_SIZE(ethnl_rss_delete_policy) - 1,
1537	},
1538	{
1539		.cmd	= ETHTOOL_MSG_MSE_GET,
1540		.doit	= ethnl_default_doit,
1541		.start	= ethnl_perphy_start,
1542		.dumpit	= ethnl_perphy_dumpit,
1543		.done	= ethnl_perphy_done,
1544		.policy = ethnl_mse_get_policy,
1545		.maxattr = ARRAY_SIZE(ethnl_mse_get_policy) - 1,
1546	},
1547};
1548
1549static const struct genl_multicast_group ethtool_nl_mcgrps[] = {
1550	[ETHNL_MCGRP_MONITOR] = { .name = ETHTOOL_MCGRP_MONITOR_NAME },
1551};
1552
1553static struct genl_family ethtool_genl_family __ro_after_init = {
1554	.name		= ETHTOOL_GENL_NAME,
1555	.version	= ETHTOOL_GENL_VERSION,
1556	.netnsok	= true,
1557	.parallel_ops	= true,
1558	.ops		= ethtool_genl_ops,
1559	.n_ops		= ARRAY_SIZE(ethtool_genl_ops),
1560	.resv_start_op	= ETHTOOL_MSG_MODULE_GET + 1,
1561	.mcgrps		= ethtool_nl_mcgrps,
1562	.n_mcgrps	= ARRAY_SIZE(ethtool_nl_mcgrps),
1563	.sock_priv_size		= sizeof(struct ethnl_sock_priv),
1564	.sock_priv_destroy	= ethnl_sock_priv_destroy,
1565};
1566
1567/* module setup */
1568
1569static int __init ethnl_init(void)
1570{
1571	int ret;
1572
1573	ret = genl_register_family(&ethtool_genl_family);
1574	if (WARN(ret < 0, "ethtool: genetlink family registration failed"))
1575		return ret;
1576	ethnl_ok = true;
1577
1578	ret = register_netdevice_notifier(&ethnl_netdev_notifier);
1579	WARN(ret < 0, "ethtool: net device notifier registration failed");
1580	return ret;
1581}
1582
1583subsys_initcall(ethnl_init);
~/ Read-only file preview.