Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 
0003 #include <net/sock.h>
0004 #include <linux/ethtool_netlink.h>
0005 #include <linux/pm_runtime.h>
0006 #include "netlink.h"
0007 
0008 static struct genl_family ethtool_genl_family;
0009 
0010 static bool ethnl_ok __read_mostly;
0011 static u32 ethnl_bcast_seq;
0012 
0013 #define ETHTOOL_FLAGS_BASIC (ETHTOOL_FLAG_COMPACT_BITSETS | \
0014                  ETHTOOL_FLAG_OMIT_REPLY)
0015 #define ETHTOOL_FLAGS_STATS (ETHTOOL_FLAGS_BASIC | ETHTOOL_FLAG_STATS)
0016 
0017 const struct nla_policy ethnl_header_policy[] = {
0018     [ETHTOOL_A_HEADER_DEV_INDEX]    = { .type = NLA_U32 },
0019     [ETHTOOL_A_HEADER_DEV_NAME] = { .type = NLA_NUL_STRING,
0020                         .len = ALTIFNAMSIZ - 1 },
0021     [ETHTOOL_A_HEADER_FLAGS]    = NLA_POLICY_MASK(NLA_U32,
0022                               ETHTOOL_FLAGS_BASIC),
0023 };
0024 
0025 const struct nla_policy ethnl_header_policy_stats[] = {
0026     [ETHTOOL_A_HEADER_DEV_INDEX]    = { .type = NLA_U32 },
0027     [ETHTOOL_A_HEADER_DEV_NAME] = { .type = NLA_NUL_STRING,
0028                         .len = ALTIFNAMSIZ - 1 },
0029     [ETHTOOL_A_HEADER_FLAGS]    = NLA_POLICY_MASK(NLA_U32,
0030                               ETHTOOL_FLAGS_STATS),
0031 };
0032 
0033 int ethnl_ops_begin(struct net_device *dev)
0034 {
0035     int ret;
0036 
0037     if (!dev)
0038         return -ENODEV;
0039 
0040     if (dev->dev.parent)
0041         pm_runtime_get_sync(dev->dev.parent);
0042 
0043     if (!netif_device_present(dev) ||
0044         dev->reg_state == NETREG_UNREGISTERING) {
0045         ret = -ENODEV;
0046         goto err;
0047     }
0048 
0049     if (dev->ethtool_ops->begin) {
0050         ret = dev->ethtool_ops->begin(dev);
0051         if (ret)
0052             goto err;
0053     }
0054 
0055     return 0;
0056 err:
0057     if (dev->dev.parent)
0058         pm_runtime_put(dev->dev.parent);
0059 
0060     return ret;
0061 }
0062 
0063 void ethnl_ops_complete(struct net_device *dev)
0064 {
0065     if (dev->ethtool_ops->complete)
0066         dev->ethtool_ops->complete(dev);
0067 
0068     if (dev->dev.parent)
0069         pm_runtime_put(dev->dev.parent);
0070 }
0071 
0072 /**
0073  * ethnl_parse_header_dev_get() - parse request header
0074  * @req_info:    structure to put results into
0075  * @header:      nest attribute with request header
0076  * @net:         request netns
0077  * @extack:      netlink extack for error reporting
0078  * @require_dev: fail if no device identified in header
0079  *
0080  * Parse request header in nested attribute @nest and puts results into
0081  * the structure pointed to by @req_info. Extack from @info is used for error
0082  * reporting. If req_info->dev is not null on return, reference to it has
0083  * been taken. If error is returned, *req_info is null initialized and no
0084  * reference is held.
0085  *
0086  * Return: 0 on success or negative error code
0087  */
0088 int ethnl_parse_header_dev_get(struct ethnl_req_info *req_info,
0089                    const struct nlattr *header, struct net *net,
0090                    struct netlink_ext_ack *extack, bool require_dev)
0091 {
0092     struct nlattr *tb[ARRAY_SIZE(ethnl_header_policy)];
0093     const struct nlattr *devname_attr;
0094     struct net_device *dev = NULL;
0095     u32 flags = 0;
0096     int ret;
0097 
0098     if (!header) {
0099         NL_SET_ERR_MSG(extack, "request header missing");
0100         return -EINVAL;
0101     }
0102     /* No validation here, command policy should have a nested policy set
0103      * for the header, therefore validation should have already been done.
0104      */
0105     ret = nla_parse_nested(tb, ARRAY_SIZE(ethnl_header_policy) - 1, header,
0106                    NULL, extack);
0107     if (ret < 0)
0108         return ret;
0109     if (tb[ETHTOOL_A_HEADER_FLAGS])
0110         flags = nla_get_u32(tb[ETHTOOL_A_HEADER_FLAGS]);
0111 
0112     devname_attr = tb[ETHTOOL_A_HEADER_DEV_NAME];
0113     if (tb[ETHTOOL_A_HEADER_DEV_INDEX]) {
0114         u32 ifindex = nla_get_u32(tb[ETHTOOL_A_HEADER_DEV_INDEX]);
0115 
0116         dev = dev_get_by_index(net, ifindex);
0117         if (!dev) {
0118             NL_SET_ERR_MSG_ATTR(extack,
0119                         tb[ETHTOOL_A_HEADER_DEV_INDEX],
0120                         "no device matches ifindex");
0121             return -ENODEV;
0122         }
0123         /* if both ifindex and ifname are passed, they must match */
0124         if (devname_attr &&
0125             strncmp(dev->name, nla_data(devname_attr), IFNAMSIZ)) {
0126             dev_put(dev);
0127             NL_SET_ERR_MSG_ATTR(extack, header,
0128                         "ifindex and name do not match");
0129             return -ENODEV;
0130         }
0131     } else if (devname_attr) {
0132         dev = dev_get_by_name(net, nla_data(devname_attr));
0133         if (!dev) {
0134             NL_SET_ERR_MSG_ATTR(extack, devname_attr,
0135                         "no device matches name");
0136             return -ENODEV;
0137         }
0138     } else if (require_dev) {
0139         NL_SET_ERR_MSG_ATTR(extack, header,
0140                     "neither ifindex nor name specified");
0141         return -EINVAL;
0142     }
0143 
0144     req_info->dev = dev;
0145     if (dev)
0146         netdev_tracker_alloc(dev, &req_info->dev_tracker, GFP_KERNEL);
0147     req_info->flags = flags;
0148     return 0;
0149 }
0150 
0151 /**
0152  * ethnl_fill_reply_header() - Put common header into a reply message
0153  * @skb:      skb with the message
0154  * @dev:      network device to describe in header
0155  * @attrtype: attribute type to use for the nest
0156  *
0157  * Create a nested attribute with attributes describing given network device.
0158  *
0159  * Return: 0 on success, error value (-EMSGSIZE only) on error
0160  */
0161 int ethnl_fill_reply_header(struct sk_buff *skb, struct net_device *dev,
0162                 u16 attrtype)
0163 {
0164     struct nlattr *nest;
0165 
0166     if (!dev)
0167         return 0;
0168     nest = nla_nest_start(skb, attrtype);
0169     if (!nest)
0170         return -EMSGSIZE;
0171 
0172     if (nla_put_u32(skb, ETHTOOL_A_HEADER_DEV_INDEX, (u32)dev->ifindex) ||
0173         nla_put_string(skb, ETHTOOL_A_HEADER_DEV_NAME, dev->name))
0174         goto nla_put_failure;
0175     /* If more attributes are put into reply header, ethnl_header_size()
0176      * must be updated to account for them.
0177      */
0178 
0179     nla_nest_end(skb, nest);
0180     return 0;
0181 
0182 nla_put_failure:
0183     nla_nest_cancel(skb, nest);
0184     return -EMSGSIZE;
0185 }
0186 
0187 /**
0188  * ethnl_reply_init() - Create skb for a reply and fill device identification
0189  * @payload:      payload length (without netlink and genetlink header)
0190  * @dev:          device the reply is about (may be null)
0191  * @cmd:          ETHTOOL_MSG_* message type for reply
0192  * @hdr_attrtype: attribute type for common header
0193  * @info:         genetlink info of the received packet we respond to
0194  * @ehdrp:        place to store payload pointer returned by genlmsg_new()
0195  *
0196  * Return: pointer to allocated skb on success, NULL on error
0197  */
0198 struct sk_buff *ethnl_reply_init(size_t payload, struct net_device *dev, u8 cmd,
0199                  u16 hdr_attrtype, struct genl_info *info,
0200                  void **ehdrp)
0201 {
0202     struct sk_buff *skb;
0203 
0204     skb = genlmsg_new(payload, GFP_KERNEL);
0205     if (!skb)
0206         goto err;
0207     *ehdrp = genlmsg_put_reply(skb, info, &ethtool_genl_family, 0, cmd);
0208     if (!*ehdrp)
0209         goto err_free;
0210 
0211     if (dev) {
0212         int ret;
0213 
0214         ret = ethnl_fill_reply_header(skb, dev, hdr_attrtype);
0215         if (ret < 0)
0216             goto err_free;
0217     }
0218     return skb;
0219 
0220 err_free:
0221     nlmsg_free(skb);
0222 err:
0223     if (info)
0224         GENL_SET_ERR_MSG(info, "failed to setup reply message");
0225     return NULL;
0226 }
0227 
0228 void *ethnl_dump_put(struct sk_buff *skb, struct netlink_callback *cb, u8 cmd)
0229 {
0230     return genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
0231                &ethtool_genl_family, 0, cmd);
0232 }
0233 
0234 void *ethnl_bcastmsg_put(struct sk_buff *skb, u8 cmd)
0235 {
0236     return genlmsg_put(skb, 0, ++ethnl_bcast_seq, &ethtool_genl_family, 0,
0237                cmd);
0238 }
0239 
0240 int ethnl_multicast(struct sk_buff *skb, struct net_device *dev)
0241 {
0242     return genlmsg_multicast_netns(&ethtool_genl_family, dev_net(dev), skb,
0243                        0, ETHNL_MCGRP_MONITOR, GFP_KERNEL);
0244 }
0245 
0246 /* GET request helpers */
0247 
0248 /**
0249  * struct ethnl_dump_ctx - context structure for generic dumpit() callback
0250  * @ops:        request ops of currently processed message type
0251  * @req_info:   parsed request header of processed request
0252  * @reply_data: data needed to compose the reply
0253  * @pos_hash:   saved iteration position - hashbucket
0254  * @pos_idx:    saved iteration position - index
0255  *
0256  * These parameters are kept in struct netlink_callback as context preserved
0257  * between iterations. They are initialized by ethnl_default_start() and used
0258  * in ethnl_default_dumpit() and ethnl_default_done().
0259  */
0260 struct ethnl_dump_ctx {
0261     const struct ethnl_request_ops  *ops;
0262     struct ethnl_req_info       *req_info;
0263     struct ethnl_reply_data     *reply_data;
0264     int             pos_hash;
0265     int             pos_idx;
0266 };
0267 
0268 static const struct ethnl_request_ops *
0269 ethnl_default_requests[__ETHTOOL_MSG_USER_CNT] = {
0270     [ETHTOOL_MSG_STRSET_GET]    = &ethnl_strset_request_ops,
0271     [ETHTOOL_MSG_LINKINFO_GET]  = &ethnl_linkinfo_request_ops,
0272     [ETHTOOL_MSG_LINKMODES_GET] = &ethnl_linkmodes_request_ops,
0273     [ETHTOOL_MSG_LINKSTATE_GET] = &ethnl_linkstate_request_ops,
0274     [ETHTOOL_MSG_DEBUG_GET]     = &ethnl_debug_request_ops,
0275     [ETHTOOL_MSG_WOL_GET]       = &ethnl_wol_request_ops,
0276     [ETHTOOL_MSG_FEATURES_GET]  = &ethnl_features_request_ops,
0277     [ETHTOOL_MSG_PRIVFLAGS_GET] = &ethnl_privflags_request_ops,
0278     [ETHTOOL_MSG_RINGS_GET]     = &ethnl_rings_request_ops,
0279     [ETHTOOL_MSG_CHANNELS_GET]  = &ethnl_channels_request_ops,
0280     [ETHTOOL_MSG_COALESCE_GET]  = &ethnl_coalesce_request_ops,
0281     [ETHTOOL_MSG_PAUSE_GET]     = &ethnl_pause_request_ops,
0282     [ETHTOOL_MSG_EEE_GET]       = &ethnl_eee_request_ops,
0283     [ETHTOOL_MSG_FEC_GET]       = &ethnl_fec_request_ops,
0284     [ETHTOOL_MSG_TSINFO_GET]    = &ethnl_tsinfo_request_ops,
0285     [ETHTOOL_MSG_MODULE_EEPROM_GET] = &ethnl_module_eeprom_request_ops,
0286     [ETHTOOL_MSG_STATS_GET]     = &ethnl_stats_request_ops,
0287     [ETHTOOL_MSG_PHC_VCLOCKS_GET]   = &ethnl_phc_vclocks_request_ops,
0288     [ETHTOOL_MSG_MODULE_GET]    = &ethnl_module_request_ops,
0289 };
0290 
0291 static struct ethnl_dump_ctx *ethnl_dump_context(struct netlink_callback *cb)
0292 {
0293     return (struct ethnl_dump_ctx *)cb->ctx;
0294 }
0295 
0296 /**
0297  * ethnl_default_parse() - Parse request message
0298  * @req_info:    pointer to structure to put data into
0299  * @tb:      parsed attributes
0300  * @net:         request netns
0301  * @request_ops: struct request_ops for request type
0302  * @extack:      netlink extack for error reporting
0303  * @require_dev: fail if no device identified in header
0304  *
0305  * Parse universal request header and call request specific ->parse_request()
0306  * callback (if defined) to parse the rest of the message.
0307  *
0308  * Return: 0 on success or negative error code
0309  */
0310 static int ethnl_default_parse(struct ethnl_req_info *req_info,
0311                    struct nlattr **tb, struct net *net,
0312                    const struct ethnl_request_ops *request_ops,
0313                    struct netlink_ext_ack *extack, bool require_dev)
0314 {
0315     int ret;
0316 
0317     ret = ethnl_parse_header_dev_get(req_info, tb[request_ops->hdr_attr],
0318                      net, extack, require_dev);
0319     if (ret < 0)
0320         return ret;
0321 
0322     if (request_ops->parse_request) {
0323         ret = request_ops->parse_request(req_info, tb, extack);
0324         if (ret < 0)
0325             return ret;
0326     }
0327 
0328     return 0;
0329 }
0330 
0331 /**
0332  * ethnl_init_reply_data() - Initialize reply data for GET request
0333  * @reply_data: pointer to embedded struct ethnl_reply_data
0334  * @ops:        instance of struct ethnl_request_ops describing the layout
0335  * @dev:        network device to initialize the reply for
0336  *
0337  * Fills the reply data part with zeros and sets the dev member. Must be called
0338  * before calling the ->fill_reply() callback (for each iteration when handling
0339  * dump requests).
0340  */
0341 static void ethnl_init_reply_data(struct ethnl_reply_data *reply_data,
0342                   const struct ethnl_request_ops *ops,
0343                   struct net_device *dev)
0344 {
0345     memset(reply_data, 0, ops->reply_data_size);
0346     reply_data->dev = dev;
0347 }
0348 
0349 /* default ->doit() handler for GET type requests */
0350 static int ethnl_default_doit(struct sk_buff *skb, struct genl_info *info)
0351 {
0352     struct ethnl_reply_data *reply_data = NULL;
0353     struct ethnl_req_info *req_info = NULL;
0354     const u8 cmd = info->genlhdr->cmd;
0355     const struct ethnl_request_ops *ops;
0356     int hdr_len, reply_len;
0357     struct sk_buff *rskb;
0358     void *reply_payload;
0359     int ret;
0360 
0361     ops = ethnl_default_requests[cmd];
0362     if (WARN_ONCE(!ops, "cmd %u has no ethnl_request_ops\n", cmd))
0363         return -EOPNOTSUPP;
0364     req_info = kzalloc(ops->req_info_size, GFP_KERNEL);
0365     if (!req_info)
0366         return -ENOMEM;
0367     reply_data = kmalloc(ops->reply_data_size, GFP_KERNEL);
0368     if (!reply_data) {
0369         kfree(req_info);
0370         return -ENOMEM;
0371     }
0372 
0373     ret = ethnl_default_parse(req_info, info->attrs, genl_info_net(info),
0374                   ops, info->extack, !ops->allow_nodev_do);
0375     if (ret < 0)
0376         goto err_dev;
0377     ethnl_init_reply_data(reply_data, ops, req_info->dev);
0378 
0379     rtnl_lock();
0380     ret = ops->prepare_data(req_info, reply_data, info);
0381     rtnl_unlock();
0382     if (ret < 0)
0383         goto err_cleanup;
0384     ret = ops->reply_size(req_info, reply_data);
0385     if (ret < 0)
0386         goto err_cleanup;
0387     reply_len = ret;
0388     ret = -ENOMEM;
0389     rskb = ethnl_reply_init(reply_len + ethnl_reply_header_size(),
0390                 req_info->dev, ops->reply_cmd,
0391                 ops->hdr_attr, info, &reply_payload);
0392     if (!rskb)
0393         goto err_cleanup;
0394     hdr_len = rskb->len;
0395     ret = ops->fill_reply(rskb, req_info, reply_data);
0396     if (ret < 0)
0397         goto err_msg;
0398     WARN_ONCE(rskb->len - hdr_len > reply_len,
0399           "ethnl cmd %d: calculated reply length %d, but consumed %d\n",
0400           cmd, reply_len, rskb->len - hdr_len);
0401     if (ops->cleanup_data)
0402         ops->cleanup_data(reply_data);
0403 
0404     genlmsg_end(rskb, reply_payload);
0405     netdev_put(req_info->dev, &req_info->dev_tracker);
0406     kfree(reply_data);
0407     kfree(req_info);
0408     return genlmsg_reply(rskb, info);
0409 
0410 err_msg:
0411     WARN_ONCE(ret == -EMSGSIZE, "calculated message payload length (%d) not sufficient\n", reply_len);
0412     nlmsg_free(rskb);
0413 err_cleanup:
0414     if (ops->cleanup_data)
0415         ops->cleanup_data(reply_data);
0416 err_dev:
0417     netdev_put(req_info->dev, &req_info->dev_tracker);
0418     kfree(reply_data);
0419     kfree(req_info);
0420     return ret;
0421 }
0422 
0423 static int ethnl_default_dump_one(struct sk_buff *skb, struct net_device *dev,
0424                   const struct ethnl_dump_ctx *ctx,
0425                   struct netlink_callback *cb)
0426 {
0427     void *ehdr;
0428     int ret;
0429 
0430     ehdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
0431                &ethtool_genl_family, NLM_F_MULTI,
0432                ctx->ops->reply_cmd);
0433     if (!ehdr)
0434         return -EMSGSIZE;
0435 
0436     ethnl_init_reply_data(ctx->reply_data, ctx->ops, dev);
0437     rtnl_lock();
0438     ret = ctx->ops->prepare_data(ctx->req_info, ctx->reply_data, NULL);
0439     rtnl_unlock();
0440     if (ret < 0)
0441         goto out;
0442     ret = ethnl_fill_reply_header(skb, dev, ctx->ops->hdr_attr);
0443     if (ret < 0)
0444         goto out;
0445     ret = ctx->ops->fill_reply(skb, ctx->req_info, ctx->reply_data);
0446 
0447 out:
0448     if (ctx->ops->cleanup_data)
0449         ctx->ops->cleanup_data(ctx->reply_data);
0450     ctx->reply_data->dev = NULL;
0451     if (ret < 0)
0452         genlmsg_cancel(skb, ehdr);
0453     else
0454         genlmsg_end(skb, ehdr);
0455     return ret;
0456 }
0457 
0458 /* Default ->dumpit() handler for GET requests. Device iteration copied from
0459  * rtnl_dump_ifinfo(); we have to be more careful about device hashtable
0460  * persistence as we cannot guarantee to hold RTNL lock through the whole
0461  * function as rtnetnlink does.
0462  */
0463 static int ethnl_default_dumpit(struct sk_buff *skb,
0464                 struct netlink_callback *cb)
0465 {
0466     struct ethnl_dump_ctx *ctx = ethnl_dump_context(cb);
0467     struct net *net = sock_net(skb->sk);
0468     int s_idx = ctx->pos_idx;
0469     int h, idx = 0;
0470     int ret = 0;
0471 
0472     rtnl_lock();
0473     for (h = ctx->pos_hash; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
0474         struct hlist_head *head;
0475         struct net_device *dev;
0476         unsigned int seq;
0477 
0478         head = &net->dev_index_head[h];
0479 
0480 restart_chain:
0481         seq = net->dev_base_seq;
0482         cb->seq = seq;
0483         idx = 0;
0484         hlist_for_each_entry(dev, head, index_hlist) {
0485             if (idx < s_idx)
0486                 goto cont;
0487             dev_hold(dev);
0488             rtnl_unlock();
0489 
0490             ret = ethnl_default_dump_one(skb, dev, ctx, cb);
0491             dev_put(dev);
0492             if (ret < 0) {
0493                 if (ret == -EOPNOTSUPP)
0494                     goto lock_and_cont;
0495                 if (likely(skb->len))
0496                     ret = skb->len;
0497                 goto out;
0498             }
0499 lock_and_cont:
0500             rtnl_lock();
0501             if (net->dev_base_seq != seq) {
0502                 s_idx = idx + 1;
0503                 goto restart_chain;
0504             }
0505 cont:
0506             idx++;
0507         }
0508 
0509     }
0510     rtnl_unlock();
0511 
0512 out:
0513     ctx->pos_hash = h;
0514     ctx->pos_idx = idx;
0515     nl_dump_check_consistent(cb, nlmsg_hdr(skb));
0516 
0517     return ret;
0518 }
0519 
0520 /* generic ->start() handler for GET requests */
0521 static int ethnl_default_start(struct netlink_callback *cb)
0522 {
0523     const struct genl_dumpit_info *info = genl_dumpit_info(cb);
0524     struct ethnl_dump_ctx *ctx = ethnl_dump_context(cb);
0525     struct ethnl_reply_data *reply_data;
0526     const struct ethnl_request_ops *ops;
0527     struct ethnl_req_info *req_info;
0528     struct genlmsghdr *ghdr;
0529     int ret;
0530 
0531     BUILD_BUG_ON(sizeof(*ctx) > sizeof(cb->ctx));
0532 
0533     ghdr = nlmsg_data(cb->nlh);
0534     ops = ethnl_default_requests[ghdr->cmd];
0535     if (WARN_ONCE(!ops, "cmd %u has no ethnl_request_ops\n", ghdr->cmd))
0536         return -EOPNOTSUPP;
0537     req_info = kzalloc(ops->req_info_size, GFP_KERNEL);
0538     if (!req_info)
0539         return -ENOMEM;
0540     reply_data = kmalloc(ops->reply_data_size, GFP_KERNEL);
0541     if (!reply_data) {
0542         ret = -ENOMEM;
0543         goto free_req_info;
0544     }
0545 
0546     ret = ethnl_default_parse(req_info, info->attrs, sock_net(cb->skb->sk),
0547                   ops, cb->extack, false);
0548     if (req_info->dev) {
0549         /* We ignore device specification in dump requests but as the
0550          * same parser as for non-dump (doit) requests is used, it
0551          * would take reference to the device if it finds one
0552          */
0553         netdev_put(req_info->dev, &req_info->dev_tracker);
0554         req_info->dev = NULL;
0555     }
0556     if (ret < 0)
0557         goto free_reply_data;
0558 
0559     ctx->ops = ops;
0560     ctx->req_info = req_info;
0561     ctx->reply_data = reply_data;
0562     ctx->pos_hash = 0;
0563     ctx->pos_idx = 0;
0564 
0565     return 0;
0566 
0567 free_reply_data:
0568     kfree(reply_data);
0569 free_req_info:
0570     kfree(req_info);
0571 
0572     return ret;
0573 }
0574 
0575 /* default ->done() handler for GET requests */
0576 static int ethnl_default_done(struct netlink_callback *cb)
0577 {
0578     struct ethnl_dump_ctx *ctx = ethnl_dump_context(cb);
0579 
0580     kfree(ctx->reply_data);
0581     kfree(ctx->req_info);
0582 
0583     return 0;
0584 }
0585 
0586 static const struct ethnl_request_ops *
0587 ethnl_default_notify_ops[ETHTOOL_MSG_KERNEL_MAX + 1] = {
0588     [ETHTOOL_MSG_LINKINFO_NTF]  = &ethnl_linkinfo_request_ops,
0589     [ETHTOOL_MSG_LINKMODES_NTF] = &ethnl_linkmodes_request_ops,
0590     [ETHTOOL_MSG_DEBUG_NTF]     = &ethnl_debug_request_ops,
0591     [ETHTOOL_MSG_WOL_NTF]       = &ethnl_wol_request_ops,
0592     [ETHTOOL_MSG_FEATURES_NTF]  = &ethnl_features_request_ops,
0593     [ETHTOOL_MSG_PRIVFLAGS_NTF] = &ethnl_privflags_request_ops,
0594     [ETHTOOL_MSG_RINGS_NTF]     = &ethnl_rings_request_ops,
0595     [ETHTOOL_MSG_CHANNELS_NTF]  = &ethnl_channels_request_ops,
0596     [ETHTOOL_MSG_COALESCE_NTF]  = &ethnl_coalesce_request_ops,
0597     [ETHTOOL_MSG_PAUSE_NTF]     = &ethnl_pause_request_ops,
0598     [ETHTOOL_MSG_EEE_NTF]       = &ethnl_eee_request_ops,
0599     [ETHTOOL_MSG_FEC_NTF]       = &ethnl_fec_request_ops,
0600     [ETHTOOL_MSG_MODULE_NTF]    = &ethnl_module_request_ops,
0601 };
0602 
0603 /* default notification handler */
0604 static void ethnl_default_notify(struct net_device *dev, unsigned int cmd,
0605                  const void *data)
0606 {
0607     struct ethnl_reply_data *reply_data;
0608     const struct ethnl_request_ops *ops;
0609     struct ethnl_req_info *req_info;
0610     struct sk_buff *skb;
0611     void *reply_payload;
0612     int reply_len;
0613     int ret;
0614 
0615     if (WARN_ONCE(cmd > ETHTOOL_MSG_KERNEL_MAX ||
0616               !ethnl_default_notify_ops[cmd],
0617               "unexpected notification type %u\n", cmd))
0618         return;
0619     ops = ethnl_default_notify_ops[cmd];
0620     req_info = kzalloc(ops->req_info_size, GFP_KERNEL);
0621     if (!req_info)
0622         return;
0623     reply_data = kmalloc(ops->reply_data_size, GFP_KERNEL);
0624     if (!reply_data) {
0625         kfree(req_info);
0626         return;
0627     }
0628 
0629     req_info->dev = dev;
0630     req_info->flags |= ETHTOOL_FLAG_COMPACT_BITSETS;
0631 
0632     ethnl_init_reply_data(reply_data, ops, dev);
0633     ret = ops->prepare_data(req_info, reply_data, NULL);
0634     if (ret < 0)
0635         goto err_cleanup;
0636     ret = ops->reply_size(req_info, reply_data);
0637     if (ret < 0)
0638         goto err_cleanup;
0639     reply_len = ret + ethnl_reply_header_size();
0640     skb = genlmsg_new(reply_len, GFP_KERNEL);
0641     if (!skb)
0642         goto err_cleanup;
0643     reply_payload = ethnl_bcastmsg_put(skb, cmd);
0644     if (!reply_payload)
0645         goto err_skb;
0646     ret = ethnl_fill_reply_header(skb, dev, ops->hdr_attr);
0647     if (ret < 0)
0648         goto err_msg;
0649     ret = ops->fill_reply(skb, req_info, reply_data);
0650     if (ret < 0)
0651         goto err_msg;
0652     if (ops->cleanup_data)
0653         ops->cleanup_data(reply_data);
0654 
0655     genlmsg_end(skb, reply_payload);
0656     kfree(reply_data);
0657     kfree(req_info);
0658     ethnl_multicast(skb, dev);
0659     return;
0660 
0661 err_msg:
0662     WARN_ONCE(ret == -EMSGSIZE,
0663           "calculated message payload length (%d) not sufficient\n",
0664           reply_len);
0665 err_skb:
0666     nlmsg_free(skb);
0667 err_cleanup:
0668     if (ops->cleanup_data)
0669         ops->cleanup_data(reply_data);
0670     kfree(reply_data);
0671     kfree(req_info);
0672     return;
0673 }
0674 
0675 /* notifications */
0676 
0677 typedef void (*ethnl_notify_handler_t)(struct net_device *dev, unsigned int cmd,
0678                        const void *data);
0679 
0680 static const ethnl_notify_handler_t ethnl_notify_handlers[] = {
0681     [ETHTOOL_MSG_LINKINFO_NTF]  = ethnl_default_notify,
0682     [ETHTOOL_MSG_LINKMODES_NTF] = ethnl_default_notify,
0683     [ETHTOOL_MSG_DEBUG_NTF]     = ethnl_default_notify,
0684     [ETHTOOL_MSG_WOL_NTF]       = ethnl_default_notify,
0685     [ETHTOOL_MSG_FEATURES_NTF]  = ethnl_default_notify,
0686     [ETHTOOL_MSG_PRIVFLAGS_NTF] = ethnl_default_notify,
0687     [ETHTOOL_MSG_RINGS_NTF]     = ethnl_default_notify,
0688     [ETHTOOL_MSG_CHANNELS_NTF]  = ethnl_default_notify,
0689     [ETHTOOL_MSG_COALESCE_NTF]  = ethnl_default_notify,
0690     [ETHTOOL_MSG_PAUSE_NTF]     = ethnl_default_notify,
0691     [ETHTOOL_MSG_EEE_NTF]       = ethnl_default_notify,
0692     [ETHTOOL_MSG_FEC_NTF]       = ethnl_default_notify,
0693     [ETHTOOL_MSG_MODULE_NTF]    = ethnl_default_notify,
0694 };
0695 
0696 void ethtool_notify(struct net_device *dev, unsigned int cmd, const void *data)
0697 {
0698     if (unlikely(!ethnl_ok))
0699         return;
0700     ASSERT_RTNL();
0701 
0702     if (likely(cmd < ARRAY_SIZE(ethnl_notify_handlers) &&
0703            ethnl_notify_handlers[cmd]))
0704         ethnl_notify_handlers[cmd](dev, cmd, data);
0705     else
0706         WARN_ONCE(1, "notification %u not implemented (dev=%s)\n",
0707               cmd, netdev_name(dev));
0708 }
0709 EXPORT_SYMBOL(ethtool_notify);
0710 
0711 static void ethnl_notify_features(struct netdev_notifier_info *info)
0712 {
0713     struct net_device *dev = netdev_notifier_info_to_dev(info);
0714 
0715     ethtool_notify(dev, ETHTOOL_MSG_FEATURES_NTF, NULL);
0716 }
0717 
0718 static int ethnl_netdev_event(struct notifier_block *this, unsigned long event,
0719                   void *ptr)
0720 {
0721     switch (event) {
0722     case NETDEV_FEAT_CHANGE:
0723         ethnl_notify_features(ptr);
0724         break;
0725     }
0726 
0727     return NOTIFY_DONE;
0728 }
0729 
0730 static struct notifier_block ethnl_netdev_notifier = {
0731     .notifier_call = ethnl_netdev_event,
0732 };
0733 
0734 /* genetlink setup */
0735 
0736 static const struct genl_ops ethtool_genl_ops[] = {
0737     {
0738         .cmd    = ETHTOOL_MSG_STRSET_GET,
0739         .doit   = ethnl_default_doit,
0740         .start  = ethnl_default_start,
0741         .dumpit = ethnl_default_dumpit,
0742         .done   = ethnl_default_done,
0743         .policy = ethnl_strset_get_policy,
0744         .maxattr = ARRAY_SIZE(ethnl_strset_get_policy) - 1,
0745     },
0746     {
0747         .cmd    = ETHTOOL_MSG_LINKINFO_GET,
0748         .doit   = ethnl_default_doit,
0749         .start  = ethnl_default_start,
0750         .dumpit = ethnl_default_dumpit,
0751         .done   = ethnl_default_done,
0752         .policy = ethnl_linkinfo_get_policy,
0753         .maxattr = ARRAY_SIZE(ethnl_linkinfo_get_policy) - 1,
0754     },
0755     {
0756         .cmd    = ETHTOOL_MSG_LINKINFO_SET,
0757         .flags  = GENL_UNS_ADMIN_PERM,
0758         .doit   = ethnl_set_linkinfo,
0759         .policy = ethnl_linkinfo_set_policy,
0760         .maxattr = ARRAY_SIZE(ethnl_linkinfo_set_policy) - 1,
0761     },
0762     {
0763         .cmd    = ETHTOOL_MSG_LINKMODES_GET,
0764         .doit   = ethnl_default_doit,
0765         .start  = ethnl_default_start,
0766         .dumpit = ethnl_default_dumpit,
0767         .done   = ethnl_default_done,
0768         .policy = ethnl_linkmodes_get_policy,
0769         .maxattr = ARRAY_SIZE(ethnl_linkmodes_get_policy) - 1,
0770     },
0771     {
0772         .cmd    = ETHTOOL_MSG_LINKMODES_SET,
0773         .flags  = GENL_UNS_ADMIN_PERM,
0774         .doit   = ethnl_set_linkmodes,
0775         .policy = ethnl_linkmodes_set_policy,
0776         .maxattr = ARRAY_SIZE(ethnl_linkmodes_set_policy) - 1,
0777     },
0778     {
0779         .cmd    = ETHTOOL_MSG_LINKSTATE_GET,
0780         .doit   = ethnl_default_doit,
0781         .start  = ethnl_default_start,
0782         .dumpit = ethnl_default_dumpit,
0783         .done   = ethnl_default_done,
0784         .policy = ethnl_linkstate_get_policy,
0785         .maxattr = ARRAY_SIZE(ethnl_linkstate_get_policy) - 1,
0786     },
0787     {
0788         .cmd    = ETHTOOL_MSG_DEBUG_GET,
0789         .doit   = ethnl_default_doit,
0790         .start  = ethnl_default_start,
0791         .dumpit = ethnl_default_dumpit,
0792         .done   = ethnl_default_done,
0793         .policy = ethnl_debug_get_policy,
0794         .maxattr = ARRAY_SIZE(ethnl_debug_get_policy) - 1,
0795     },
0796     {
0797         .cmd    = ETHTOOL_MSG_DEBUG_SET,
0798         .flags  = GENL_UNS_ADMIN_PERM,
0799         .doit   = ethnl_set_debug,
0800         .policy = ethnl_debug_set_policy,
0801         .maxattr = ARRAY_SIZE(ethnl_debug_set_policy) - 1,
0802     },
0803     {
0804         .cmd    = ETHTOOL_MSG_WOL_GET,
0805         .flags  = GENL_UNS_ADMIN_PERM,
0806         .doit   = ethnl_default_doit,
0807         .start  = ethnl_default_start,
0808         .dumpit = ethnl_default_dumpit,
0809         .done   = ethnl_default_done,
0810         .policy = ethnl_wol_get_policy,
0811         .maxattr = ARRAY_SIZE(ethnl_wol_get_policy) - 1,
0812     },
0813     {
0814         .cmd    = ETHTOOL_MSG_WOL_SET,
0815         .flags  = GENL_UNS_ADMIN_PERM,
0816         .doit   = ethnl_set_wol,
0817         .policy = ethnl_wol_set_policy,
0818         .maxattr = ARRAY_SIZE(ethnl_wol_set_policy) - 1,
0819     },
0820     {
0821         .cmd    = ETHTOOL_MSG_FEATURES_GET,
0822         .doit   = ethnl_default_doit,
0823         .start  = ethnl_default_start,
0824         .dumpit = ethnl_default_dumpit,
0825         .done   = ethnl_default_done,
0826         .policy = ethnl_features_get_policy,
0827         .maxattr = ARRAY_SIZE(ethnl_features_get_policy) - 1,
0828     },
0829     {
0830         .cmd    = ETHTOOL_MSG_FEATURES_SET,
0831         .flags  = GENL_UNS_ADMIN_PERM,
0832         .doit   = ethnl_set_features,
0833         .policy = ethnl_features_set_policy,
0834         .maxattr = ARRAY_SIZE(ethnl_features_set_policy) - 1,
0835     },
0836     {
0837         .cmd    = ETHTOOL_MSG_PRIVFLAGS_GET,
0838         .doit   = ethnl_default_doit,
0839         .start  = ethnl_default_start,
0840         .dumpit = ethnl_default_dumpit,
0841         .done   = ethnl_default_done,
0842         .policy = ethnl_privflags_get_policy,
0843         .maxattr = ARRAY_SIZE(ethnl_privflags_get_policy) - 1,
0844     },
0845     {
0846         .cmd    = ETHTOOL_MSG_PRIVFLAGS_SET,
0847         .flags  = GENL_UNS_ADMIN_PERM,
0848         .doit   = ethnl_set_privflags,
0849         .policy = ethnl_privflags_set_policy,
0850         .maxattr = ARRAY_SIZE(ethnl_privflags_set_policy) - 1,
0851     },
0852     {
0853         .cmd    = ETHTOOL_MSG_RINGS_GET,
0854         .doit   = ethnl_default_doit,
0855         .start  = ethnl_default_start,
0856         .dumpit = ethnl_default_dumpit,
0857         .done   = ethnl_default_done,
0858         .policy = ethnl_rings_get_policy,
0859         .maxattr = ARRAY_SIZE(ethnl_rings_get_policy) - 1,
0860     },
0861     {
0862         .cmd    = ETHTOOL_MSG_RINGS_SET,
0863         .flags  = GENL_UNS_ADMIN_PERM,
0864         .doit   = ethnl_set_rings,
0865         .policy = ethnl_rings_set_policy,
0866         .maxattr = ARRAY_SIZE(ethnl_rings_set_policy) - 1,
0867     },
0868     {
0869         .cmd    = ETHTOOL_MSG_CHANNELS_GET,
0870         .doit   = ethnl_default_doit,
0871         .start  = ethnl_default_start,
0872         .dumpit = ethnl_default_dumpit,
0873         .done   = ethnl_default_done,
0874         .policy = ethnl_channels_get_policy,
0875         .maxattr = ARRAY_SIZE(ethnl_channels_get_policy) - 1,
0876     },
0877     {
0878         .cmd    = ETHTOOL_MSG_CHANNELS_SET,
0879         .flags  = GENL_UNS_ADMIN_PERM,
0880         .doit   = ethnl_set_channels,
0881         .policy = ethnl_channels_set_policy,
0882         .maxattr = ARRAY_SIZE(ethnl_channels_set_policy) - 1,
0883     },
0884     {
0885         .cmd    = ETHTOOL_MSG_COALESCE_GET,
0886         .doit   = ethnl_default_doit,
0887         .start  = ethnl_default_start,
0888         .dumpit = ethnl_default_dumpit,
0889         .done   = ethnl_default_done,
0890         .policy = ethnl_coalesce_get_policy,
0891         .maxattr = ARRAY_SIZE(ethnl_coalesce_get_policy) - 1,
0892     },
0893     {
0894         .cmd    = ETHTOOL_MSG_COALESCE_SET,
0895         .flags  = GENL_UNS_ADMIN_PERM,
0896         .doit   = ethnl_set_coalesce,
0897         .policy = ethnl_coalesce_set_policy,
0898         .maxattr = ARRAY_SIZE(ethnl_coalesce_set_policy) - 1,
0899     },
0900     {
0901         .cmd    = ETHTOOL_MSG_PAUSE_GET,
0902         .doit   = ethnl_default_doit,
0903         .start  = ethnl_default_start,
0904         .dumpit = ethnl_default_dumpit,
0905         .done   = ethnl_default_done,
0906         .policy = ethnl_pause_get_policy,
0907         .maxattr = ARRAY_SIZE(ethnl_pause_get_policy) - 1,
0908     },
0909     {
0910         .cmd    = ETHTOOL_MSG_PAUSE_SET,
0911         .flags  = GENL_UNS_ADMIN_PERM,
0912         .doit   = ethnl_set_pause,
0913         .policy = ethnl_pause_set_policy,
0914         .maxattr = ARRAY_SIZE(ethnl_pause_set_policy) - 1,
0915     },
0916     {
0917         .cmd    = ETHTOOL_MSG_EEE_GET,
0918         .doit   = ethnl_default_doit,
0919         .start  = ethnl_default_start,
0920         .dumpit = ethnl_default_dumpit,
0921         .done   = ethnl_default_done,
0922         .policy = ethnl_eee_get_policy,
0923         .maxattr = ARRAY_SIZE(ethnl_eee_get_policy) - 1,
0924     },
0925     {
0926         .cmd    = ETHTOOL_MSG_EEE_SET,
0927         .flags  = GENL_UNS_ADMIN_PERM,
0928         .doit   = ethnl_set_eee,
0929         .policy = ethnl_eee_set_policy,
0930         .maxattr = ARRAY_SIZE(ethnl_eee_set_policy) - 1,
0931     },
0932     {
0933         .cmd    = ETHTOOL_MSG_TSINFO_GET,
0934         .doit   = ethnl_default_doit,
0935         .start  = ethnl_default_start,
0936         .dumpit = ethnl_default_dumpit,
0937         .done   = ethnl_default_done,
0938         .policy = ethnl_tsinfo_get_policy,
0939         .maxattr = ARRAY_SIZE(ethnl_tsinfo_get_policy) - 1,
0940     },
0941     {
0942         .cmd    = ETHTOOL_MSG_CABLE_TEST_ACT,
0943         .flags  = GENL_UNS_ADMIN_PERM,
0944         .doit   = ethnl_act_cable_test,
0945         .policy = ethnl_cable_test_act_policy,
0946         .maxattr = ARRAY_SIZE(ethnl_cable_test_act_policy) - 1,
0947     },
0948     {
0949         .cmd    = ETHTOOL_MSG_CABLE_TEST_TDR_ACT,
0950         .flags  = GENL_UNS_ADMIN_PERM,
0951         .doit   = ethnl_act_cable_test_tdr,
0952         .policy = ethnl_cable_test_tdr_act_policy,
0953         .maxattr = ARRAY_SIZE(ethnl_cable_test_tdr_act_policy) - 1,
0954     },
0955     {
0956         .cmd    = ETHTOOL_MSG_TUNNEL_INFO_GET,
0957         .doit   = ethnl_tunnel_info_doit,
0958         .start  = ethnl_tunnel_info_start,
0959         .dumpit = ethnl_tunnel_info_dumpit,
0960         .policy = ethnl_tunnel_info_get_policy,
0961         .maxattr = ARRAY_SIZE(ethnl_tunnel_info_get_policy) - 1,
0962     },
0963     {
0964         .cmd    = ETHTOOL_MSG_FEC_GET,
0965         .doit   = ethnl_default_doit,
0966         .start  = ethnl_default_start,
0967         .dumpit = ethnl_default_dumpit,
0968         .done   = ethnl_default_done,
0969         .policy = ethnl_fec_get_policy,
0970         .maxattr = ARRAY_SIZE(ethnl_fec_get_policy) - 1,
0971     },
0972     {
0973         .cmd    = ETHTOOL_MSG_FEC_SET,
0974         .flags  = GENL_UNS_ADMIN_PERM,
0975         .doit   = ethnl_set_fec,
0976         .policy = ethnl_fec_set_policy,
0977         .maxattr = ARRAY_SIZE(ethnl_fec_set_policy) - 1,
0978     },
0979     {
0980         .cmd    = ETHTOOL_MSG_MODULE_EEPROM_GET,
0981         .flags  = GENL_UNS_ADMIN_PERM,
0982         .doit   = ethnl_default_doit,
0983         .start  = ethnl_default_start,
0984         .dumpit = ethnl_default_dumpit,
0985         .done   = ethnl_default_done,
0986         .policy = ethnl_module_eeprom_get_policy,
0987         .maxattr = ARRAY_SIZE(ethnl_module_eeprom_get_policy) - 1,
0988     },
0989     {
0990         .cmd    = ETHTOOL_MSG_STATS_GET,
0991         .doit   = ethnl_default_doit,
0992         .start  = ethnl_default_start,
0993         .dumpit = ethnl_default_dumpit,
0994         .done   = ethnl_default_done,
0995         .policy = ethnl_stats_get_policy,
0996         .maxattr = ARRAY_SIZE(ethnl_stats_get_policy) - 1,
0997     },
0998     {
0999         .cmd    = ETHTOOL_MSG_PHC_VCLOCKS_GET,
1000         .doit   = ethnl_default_doit,
1001         .start  = ethnl_default_start,
1002         .dumpit = ethnl_default_dumpit,
1003         .done   = ethnl_default_done,
1004         .policy = ethnl_phc_vclocks_get_policy,
1005         .maxattr = ARRAY_SIZE(ethnl_phc_vclocks_get_policy) - 1,
1006     },
1007     {
1008         .cmd    = ETHTOOL_MSG_MODULE_GET,
1009         .doit   = ethnl_default_doit,
1010         .start  = ethnl_default_start,
1011         .dumpit = ethnl_default_dumpit,
1012         .done   = ethnl_default_done,
1013         .policy = ethnl_module_get_policy,
1014         .maxattr = ARRAY_SIZE(ethnl_module_get_policy) - 1,
1015     },
1016     {
1017         .cmd    = ETHTOOL_MSG_MODULE_SET,
1018         .flags  = GENL_UNS_ADMIN_PERM,
1019         .doit   = ethnl_set_module,
1020         .policy = ethnl_module_set_policy,
1021         .maxattr = ARRAY_SIZE(ethnl_module_set_policy) - 1,
1022     },
1023 };
1024 
1025 static const struct genl_multicast_group ethtool_nl_mcgrps[] = {
1026     [ETHNL_MCGRP_MONITOR] = { .name = ETHTOOL_MCGRP_MONITOR_NAME },
1027 };
1028 
1029 static struct genl_family ethtool_genl_family __ro_after_init = {
1030     .name       = ETHTOOL_GENL_NAME,
1031     .version    = ETHTOOL_GENL_VERSION,
1032     .netnsok    = true,
1033     .parallel_ops   = true,
1034     .ops        = ethtool_genl_ops,
1035     .n_ops      = ARRAY_SIZE(ethtool_genl_ops),
1036     .mcgrps     = ethtool_nl_mcgrps,
1037     .n_mcgrps   = ARRAY_SIZE(ethtool_nl_mcgrps),
1038 };
1039 
1040 /* module setup */
1041 
1042 static int __init ethnl_init(void)
1043 {
1044     int ret;
1045 
1046     ret = genl_register_family(&ethtool_genl_family);
1047     if (WARN(ret < 0, "ethtool: genetlink family registration failed"))
1048         return ret;
1049     ethnl_ok = true;
1050 
1051     ret = register_netdevice_notifier(&ethnl_netdev_notifier);
1052     WARN(ret < 0, "ethtool: net device notifier registration failed");
1053     return ret;
1054 }
1055 
1056 subsys_initcall(ethnl_init);