linux/net/ethtool/netlink.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2
   3#include <net/sock.h>
   4#include <linux/ethtool_netlink.h>
   5#include "netlink.h"
   6
   7static struct genl_family ethtool_genl_family;
   8
   9static bool ethnl_ok __read_mostly;
  10static u32 ethnl_bcast_seq;
  11
  12static const struct nla_policy ethnl_header_policy[ETHTOOL_A_HEADER_MAX + 1] = {
  13        [ETHTOOL_A_HEADER_UNSPEC]       = { .type = NLA_REJECT },
  14        [ETHTOOL_A_HEADER_DEV_INDEX]    = { .type = NLA_U32 },
  15        [ETHTOOL_A_HEADER_DEV_NAME]     = { .type = NLA_NUL_STRING,
  16                                            .len = ALTIFNAMSIZ - 1 },
  17        [ETHTOOL_A_HEADER_FLAGS]        = { .type = NLA_U32 },
  18};
  19
  20/**
  21 * ethnl_parse_header_dev_get() - parse request header
  22 * @req_info:    structure to put results into
  23 * @header:      nest attribute with request header
  24 * @net:         request netns
  25 * @extack:      netlink extack for error reporting
  26 * @require_dev: fail if no device identified in header
  27 *
  28 * Parse request header in nested attribute @nest and puts results into
  29 * the structure pointed to by @req_info. Extack from @info is used for error
  30 * reporting. If req_info->dev is not null on return, reference to it has
  31 * been taken. If error is returned, *req_info is null initialized and no
  32 * reference is held.
  33 *
  34 * Return: 0 on success or negative error code
  35 */
  36int ethnl_parse_header_dev_get(struct ethnl_req_info *req_info,
  37                               const struct nlattr *header, struct net *net,
  38                               struct netlink_ext_ack *extack, bool require_dev)
  39{
  40        struct nlattr *tb[ETHTOOL_A_HEADER_MAX + 1];
  41        const struct nlattr *devname_attr;
  42        struct net_device *dev = NULL;
  43        u32 flags = 0;
  44        int ret;
  45
  46        if (!header) {
  47                NL_SET_ERR_MSG(extack, "request header missing");
  48                return -EINVAL;
  49        }
  50        ret = nla_parse_nested(tb, ETHTOOL_A_HEADER_MAX, header,
  51                               ethnl_header_policy, extack);
  52        if (ret < 0)
  53                return ret;
  54        if (tb[ETHTOOL_A_HEADER_FLAGS]) {
  55                flags = nla_get_u32(tb[ETHTOOL_A_HEADER_FLAGS]);
  56                if (flags & ~ETHTOOL_FLAG_ALL) {
  57                        NL_SET_ERR_MSG_ATTR(extack, tb[ETHTOOL_A_HEADER_FLAGS],
  58                                            "unrecognized request flags");
  59                        nl_set_extack_cookie_u32(extack, ETHTOOL_FLAG_ALL);
  60                        return -EOPNOTSUPP;
  61                }
  62        }
  63
  64        devname_attr = tb[ETHTOOL_A_HEADER_DEV_NAME];
  65        if (tb[ETHTOOL_A_HEADER_DEV_INDEX]) {
  66                u32 ifindex = nla_get_u32(tb[ETHTOOL_A_HEADER_DEV_INDEX]);
  67
  68                dev = dev_get_by_index(net, ifindex);
  69                if (!dev) {
  70                        NL_SET_ERR_MSG_ATTR(extack,
  71                                            tb[ETHTOOL_A_HEADER_DEV_INDEX],
  72                                            "no device matches ifindex");
  73                        return -ENODEV;
  74                }
  75                /* if both ifindex and ifname are passed, they must match */
  76                if (devname_attr &&
  77                    strncmp(dev->name, nla_data(devname_attr), IFNAMSIZ)) {
  78                        dev_put(dev);
  79                        NL_SET_ERR_MSG_ATTR(extack, header,
  80                                            "ifindex and name do not match");
  81                        return -ENODEV;
  82                }
  83        } else if (devname_attr) {
  84                dev = dev_get_by_name(net, nla_data(devname_attr));
  85                if (!dev) {
  86                        NL_SET_ERR_MSG_ATTR(extack, devname_attr,
  87                                            "no device matches name");
  88                        return -ENODEV;
  89                }
  90        } else if (require_dev) {
  91                NL_SET_ERR_MSG_ATTR(extack, header,
  92                                    "neither ifindex nor name specified");
  93                return -EINVAL;
  94        }
  95
  96        if (dev && !netif_device_present(dev)) {
  97                dev_put(dev);
  98                NL_SET_ERR_MSG(extack, "device not present");
  99                return -ENODEV;
 100        }
 101
 102        req_info->dev = dev;
 103        req_info->flags = flags;
 104        return 0;
 105}
 106
 107/**
 108 * ethnl_fill_reply_header() - Put common header into a reply message
 109 * @skb:      skb with the message
 110 * @dev:      network device to describe in header
 111 * @attrtype: attribute type to use for the nest
 112 *
 113 * Create a nested attribute with attributes describing given network device.
 114 *
 115 * Return: 0 on success, error value (-EMSGSIZE only) on error
 116 */
 117int ethnl_fill_reply_header(struct sk_buff *skb, struct net_device *dev,
 118                            u16 attrtype)
 119{
 120        struct nlattr *nest;
 121
 122        if (!dev)
 123                return 0;
 124        nest = nla_nest_start(skb, attrtype);
 125        if (!nest)
 126                return -EMSGSIZE;
 127
 128        if (nla_put_u32(skb, ETHTOOL_A_HEADER_DEV_INDEX, (u32)dev->ifindex) ||
 129            nla_put_string(skb, ETHTOOL_A_HEADER_DEV_NAME, dev->name))
 130                goto nla_put_failure;
 131        /* If more attributes are put into reply header, ethnl_header_size()
 132         * must be updated to account for them.
 133         */
 134
 135        nla_nest_end(skb, nest);
 136        return 0;
 137
 138nla_put_failure:
 139        nla_nest_cancel(skb, nest);
 140        return -EMSGSIZE;
 141}
 142
 143/**
 144 * ethnl_reply_init() - Create skb for a reply and fill device identification
 145 * @payload:      payload length (without netlink and genetlink header)
 146 * @dev:          device the reply is about (may be null)
 147 * @cmd:          ETHTOOL_MSG_* message type for reply
 148 * @hdr_attrtype: attribute type for common header
 149 * @info:         genetlink info of the received packet we respond to
 150 * @ehdrp:        place to store payload pointer returned by genlmsg_new()
 151 *
 152 * Return: pointer to allocated skb on success, NULL on error
 153 */
 154struct sk_buff *ethnl_reply_init(size_t payload, struct net_device *dev, u8 cmd,
 155                                 u16 hdr_attrtype, struct genl_info *info,
 156                                 void **ehdrp)
 157{
 158        struct sk_buff *skb;
 159
 160        skb = genlmsg_new(payload, GFP_KERNEL);
 161        if (!skb)
 162                goto err;
 163        *ehdrp = genlmsg_put_reply(skb, info, &ethtool_genl_family, 0, cmd);
 164        if (!*ehdrp)
 165                goto err_free;
 166
 167        if (dev) {
 168                int ret;
 169
 170                ret = ethnl_fill_reply_header(skb, dev, hdr_attrtype);
 171                if (ret < 0)
 172                        goto err_free;
 173        }
 174        return skb;
 175
 176err_free:
 177        nlmsg_free(skb);
 178err:
 179        if (info)
 180                GENL_SET_ERR_MSG(info, "failed to setup reply message");
 181        return NULL;
 182}
 183
 184void *ethnl_dump_put(struct sk_buff *skb, struct netlink_callback *cb, u8 cmd)
 185{
 186        return genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
 187                           &ethtool_genl_family, 0, cmd);
 188}
 189
 190void *ethnl_bcastmsg_put(struct sk_buff *skb, u8 cmd)
 191{
 192        return genlmsg_put(skb, 0, ++ethnl_bcast_seq, &ethtool_genl_family, 0,
 193                           cmd);
 194}
 195
 196int ethnl_multicast(struct sk_buff *skb, struct net_device *dev)
 197{
 198        return genlmsg_multicast_netns(&ethtool_genl_family, dev_net(dev), skb,
 199                                       0, ETHNL_MCGRP_MONITOR, GFP_KERNEL);
 200}
 201
 202/* GET request helpers */
 203
 204/**
 205 * struct ethnl_dump_ctx - context structure for generic dumpit() callback
 206 * @ops:        request ops of currently processed message type
 207 * @req_info:   parsed request header of processed request
 208 * @reply_data: data needed to compose the reply
 209 * @pos_hash:   saved iteration position - hashbucket
 210 * @pos_idx:    saved iteration position - index
 211 *
 212 * These parameters are kept in struct netlink_callback as context preserved
 213 * between iterations. They are initialized by ethnl_default_start() and used
 214 * in ethnl_default_dumpit() and ethnl_default_done().
 215 */
 216struct ethnl_dump_ctx {
 217        const struct ethnl_request_ops  *ops;
 218        struct ethnl_req_info           *req_info;
 219        struct ethnl_reply_data         *reply_data;
 220        int                             pos_hash;
 221        int                             pos_idx;
 222};
 223
 224static const struct ethnl_request_ops *
 225ethnl_default_requests[__ETHTOOL_MSG_USER_CNT] = {
 226        [ETHTOOL_MSG_STRSET_GET]        = &ethnl_strset_request_ops,
 227        [ETHTOOL_MSG_LINKINFO_GET]      = &ethnl_linkinfo_request_ops,
 228        [ETHTOOL_MSG_LINKMODES_GET]     = &ethnl_linkmodes_request_ops,
 229        [ETHTOOL_MSG_LINKSTATE_GET]     = &ethnl_linkstate_request_ops,
 230        [ETHTOOL_MSG_DEBUG_GET]         = &ethnl_debug_request_ops,
 231        [ETHTOOL_MSG_WOL_GET]           = &ethnl_wol_request_ops,
 232        [ETHTOOL_MSG_FEATURES_GET]      = &ethnl_features_request_ops,
 233        [ETHTOOL_MSG_PRIVFLAGS_GET]     = &ethnl_privflags_request_ops,
 234        [ETHTOOL_MSG_RINGS_GET]         = &ethnl_rings_request_ops,
 235        [ETHTOOL_MSG_CHANNELS_GET]      = &ethnl_channels_request_ops,
 236        [ETHTOOL_MSG_COALESCE_GET]      = &ethnl_coalesce_request_ops,
 237        [ETHTOOL_MSG_PAUSE_GET]         = &ethnl_pause_request_ops,
 238        [ETHTOOL_MSG_EEE_GET]           = &ethnl_eee_request_ops,
 239        [ETHTOOL_MSG_TSINFO_GET]        = &ethnl_tsinfo_request_ops,
 240};
 241
 242static struct ethnl_dump_ctx *ethnl_dump_context(struct netlink_callback *cb)
 243{
 244        return (struct ethnl_dump_ctx *)cb->ctx;
 245}
 246
 247/**
 248 * ethnl_default_parse() - Parse request message
 249 * @req_info:    pointer to structure to put data into
 250 * @nlhdr:       pointer to request message header
 251 * @net:         request netns
 252 * @request_ops: struct request_ops for request type
 253 * @extack:      netlink extack for error reporting
 254 * @require_dev: fail if no device identified in header
 255 *
 256 * Parse universal request header and call request specific ->parse_request()
 257 * callback (if defined) to parse the rest of the message.
 258 *
 259 * Return: 0 on success or negative error code
 260 */
 261static int ethnl_default_parse(struct ethnl_req_info *req_info,
 262                               const struct nlmsghdr *nlhdr, struct net *net,
 263                               const struct ethnl_request_ops *request_ops,
 264                               struct netlink_ext_ack *extack, bool require_dev)
 265{
 266        struct nlattr **tb;
 267        int ret;
 268
 269        tb = kmalloc_array(request_ops->max_attr + 1, sizeof(tb[0]),
 270                           GFP_KERNEL);
 271        if (!tb)
 272                return -ENOMEM;
 273
 274        ret = nlmsg_parse(nlhdr, GENL_HDRLEN, tb, request_ops->max_attr,
 275                          request_ops->request_policy, extack);
 276        if (ret < 0)
 277                goto out;
 278        ret = ethnl_parse_header_dev_get(req_info, tb[request_ops->hdr_attr],
 279                                         net, extack, require_dev);
 280        if (ret < 0)
 281                goto out;
 282
 283        if (request_ops->parse_request) {
 284                ret = request_ops->parse_request(req_info, tb, extack);
 285                if (ret < 0)
 286                        goto out;
 287        }
 288
 289        ret = 0;
 290out:
 291        kfree(tb);
 292        return ret;
 293}
 294
 295/**
 296 * ethnl_init_reply_data() - Initialize reply data for GET request
 297 * @reply_data: pointer to embedded struct ethnl_reply_data
 298 * @ops:        instance of struct ethnl_request_ops describing the layout
 299 * @dev:        network device to initialize the reply for
 300 *
 301 * Fills the reply data part with zeros and sets the dev member. Must be called
 302 * before calling the ->fill_reply() callback (for each iteration when handling
 303 * dump requests).
 304 */
 305static void ethnl_init_reply_data(struct ethnl_reply_data *reply_data,
 306                                  const struct ethnl_request_ops *ops,
 307                                  struct net_device *dev)
 308{
 309        memset(reply_data, 0, ops->reply_data_size);
 310        reply_data->dev = dev;
 311}
 312
 313/* default ->doit() handler for GET type requests */
 314static int ethnl_default_doit(struct sk_buff *skb, struct genl_info *info)
 315{
 316        struct ethnl_reply_data *reply_data = NULL;
 317        struct ethnl_req_info *req_info = NULL;
 318        const u8 cmd = info->genlhdr->cmd;
 319        const struct ethnl_request_ops *ops;
 320        struct sk_buff *rskb;
 321        void *reply_payload;
 322        int reply_len;
 323        int ret;
 324
 325        ops = ethnl_default_requests[cmd];
 326        if (WARN_ONCE(!ops, "cmd %u has no ethnl_request_ops\n", cmd))
 327                return -EOPNOTSUPP;
 328        req_info = kzalloc(ops->req_info_size, GFP_KERNEL);
 329        if (!req_info)
 330                return -ENOMEM;
 331        reply_data = kmalloc(ops->reply_data_size, GFP_KERNEL);
 332        if (!reply_data) {
 333                kfree(req_info);
 334                return -ENOMEM;
 335        }
 336
 337        ret = ethnl_default_parse(req_info, info->nlhdr, genl_info_net(info), ops,
 338                                  info->extack, !ops->allow_nodev_do);
 339        if (ret < 0)
 340                goto err_dev;
 341        ethnl_init_reply_data(reply_data, ops, req_info->dev);
 342
 343        rtnl_lock();
 344        ret = ops->prepare_data(req_info, reply_data, info);
 345        rtnl_unlock();
 346        if (ret < 0)
 347                goto err_cleanup;
 348        ret = ops->reply_size(req_info, reply_data);
 349        if (ret < 0)
 350                goto err_cleanup;
 351        reply_len = ret + ethnl_reply_header_size();
 352        ret = -ENOMEM;
 353        rskb = ethnl_reply_init(reply_len, req_info->dev, ops->reply_cmd,
 354                                ops->hdr_attr, info, &reply_payload);
 355        if (!rskb)
 356                goto err_cleanup;
 357        ret = ops->fill_reply(rskb, req_info, reply_data);
 358        if (ret < 0)
 359                goto err_msg;
 360        if (ops->cleanup_data)
 361                ops->cleanup_data(reply_data);
 362
 363        genlmsg_end(rskb, reply_payload);
 364        if (req_info->dev)
 365                dev_put(req_info->dev);
 366        kfree(reply_data);
 367        kfree(req_info);
 368        return genlmsg_reply(rskb, info);
 369
 370err_msg:
 371        WARN_ONCE(ret == -EMSGSIZE, "calculated message payload length (%d) not sufficient\n", reply_len);
 372        nlmsg_free(rskb);
 373err_cleanup:
 374        if (ops->cleanup_data)
 375                ops->cleanup_data(reply_data);
 376err_dev:
 377        if (req_info->dev)
 378                dev_put(req_info->dev);
 379        kfree(reply_data);
 380        kfree(req_info);
 381        return ret;
 382}
 383
 384static int ethnl_default_dump_one(struct sk_buff *skb, struct net_device *dev,
 385                                  const struct ethnl_dump_ctx *ctx,
 386                                  struct netlink_callback *cb)
 387{
 388        void *ehdr;
 389        int ret;
 390
 391        ehdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
 392                           &ethtool_genl_family, 0, ctx->ops->reply_cmd);
 393        if (!ehdr)
 394                return -EMSGSIZE;
 395
 396        ethnl_init_reply_data(ctx->reply_data, ctx->ops, dev);
 397        rtnl_lock();
 398        ret = ctx->ops->prepare_data(ctx->req_info, ctx->reply_data, NULL);
 399        rtnl_unlock();
 400        if (ret < 0)
 401                goto out;
 402        ret = ethnl_fill_reply_header(skb, dev, ctx->ops->hdr_attr);
 403        if (ret < 0)
 404                goto out;
 405        ret = ctx->ops->fill_reply(skb, ctx->req_info, ctx->reply_data);
 406
 407out:
 408        if (ctx->ops->cleanup_data)
 409                ctx->ops->cleanup_data(ctx->reply_data);
 410        ctx->reply_data->dev = NULL;
 411        if (ret < 0)
 412                genlmsg_cancel(skb, ehdr);
 413        else
 414                genlmsg_end(skb, ehdr);
 415        return ret;
 416}
 417
 418/* Default ->dumpit() handler for GET requests. Device iteration copied from
 419 * rtnl_dump_ifinfo(); we have to be more careful about device hashtable
 420 * persistence as we cannot guarantee to hold RTNL lock through the whole
 421 * function as rtnetnlink does.
 422 */
 423static int ethnl_default_dumpit(struct sk_buff *skb,
 424                                struct netlink_callback *cb)
 425{
 426        struct ethnl_dump_ctx *ctx = ethnl_dump_context(cb);
 427        struct net *net = sock_net(skb->sk);
 428        int s_idx = ctx->pos_idx;
 429        int h, idx = 0;
 430        int ret = 0;
 431
 432        rtnl_lock();
 433        for (h = ctx->pos_hash; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
 434                struct hlist_head *head;
 435                struct net_device *dev;
 436                unsigned int seq;
 437
 438                head = &net->dev_index_head[h];
 439
 440restart_chain:
 441                seq = net->dev_base_seq;
 442                cb->seq = seq;
 443                idx = 0;
 444                hlist_for_each_entry(dev, head, index_hlist) {
 445                        if (idx < s_idx)
 446                                goto cont;
 447                        dev_hold(dev);
 448                        rtnl_unlock();
 449
 450                        ret = ethnl_default_dump_one(skb, dev, ctx, cb);
 451                        dev_put(dev);
 452                        if (ret < 0) {
 453                                if (ret == -EOPNOTSUPP)
 454                                        goto lock_and_cont;
 455                                if (likely(skb->len))
 456                                        ret = skb->len;
 457                                goto out;
 458                        }
 459lock_and_cont:
 460                        rtnl_lock();
 461                        if (net->dev_base_seq != seq) {
 462                                s_idx = idx + 1;
 463                                goto restart_chain;
 464                        }
 465cont:
 466                        idx++;
 467                }
 468
 469        }
 470        rtnl_unlock();
 471
 472out:
 473        ctx->pos_hash = h;
 474        ctx->pos_idx = idx;
 475        nl_dump_check_consistent(cb, nlmsg_hdr(skb));
 476
 477        return ret;
 478}
 479
 480/* generic ->start() handler for GET requests */
 481static int ethnl_default_start(struct netlink_callback *cb)
 482{
 483        struct ethnl_dump_ctx *ctx = ethnl_dump_context(cb);
 484        struct ethnl_reply_data *reply_data;
 485        const struct ethnl_request_ops *ops;
 486        struct ethnl_req_info *req_info;
 487        struct genlmsghdr *ghdr;
 488        int ret;
 489
 490        BUILD_BUG_ON(sizeof(*ctx) > sizeof(cb->ctx));
 491
 492        ghdr = nlmsg_data(cb->nlh);
 493        ops = ethnl_default_requests[ghdr->cmd];
 494        if (WARN_ONCE(!ops, "cmd %u has no ethnl_request_ops\n", ghdr->cmd))
 495                return -EOPNOTSUPP;
 496        req_info = kzalloc(ops->req_info_size, GFP_KERNEL);
 497        if (!req_info)
 498                return -ENOMEM;
 499        reply_data = kmalloc(ops->reply_data_size, GFP_KERNEL);
 500        if (!reply_data) {
 501                ret = -ENOMEM;
 502                goto free_req_info;
 503        }
 504
 505        ret = ethnl_default_parse(req_info, cb->nlh, sock_net(cb->skb->sk), ops,
 506                                  cb->extack, false);
 507        if (req_info->dev) {
 508                /* We ignore device specification in dump requests but as the
 509                 * same parser as for non-dump (doit) requests is used, it
 510                 * would take reference to the device if it finds one
 511                 */
 512                dev_put(req_info->dev);
 513                req_info->dev = NULL;
 514        }
 515        if (ret < 0)
 516                goto free_reply_data;
 517
 518        ctx->ops = ops;
 519        ctx->req_info = req_info;
 520        ctx->reply_data = reply_data;
 521        ctx->pos_hash = 0;
 522        ctx->pos_idx = 0;
 523
 524        return 0;
 525
 526free_reply_data:
 527        kfree(reply_data);
 528free_req_info:
 529        kfree(req_info);
 530
 531        return ret;
 532}
 533
 534/* default ->done() handler for GET requests */
 535static int ethnl_default_done(struct netlink_callback *cb)
 536{
 537        struct ethnl_dump_ctx *ctx = ethnl_dump_context(cb);
 538
 539        kfree(ctx->reply_data);
 540        kfree(ctx->req_info);
 541
 542        return 0;
 543}
 544
 545static const struct ethnl_request_ops *
 546ethnl_default_notify_ops[ETHTOOL_MSG_KERNEL_MAX + 1] = {
 547        [ETHTOOL_MSG_LINKINFO_NTF]      = &ethnl_linkinfo_request_ops,
 548        [ETHTOOL_MSG_LINKMODES_NTF]     = &ethnl_linkmodes_request_ops,
 549        [ETHTOOL_MSG_DEBUG_NTF]         = &ethnl_debug_request_ops,
 550        [ETHTOOL_MSG_WOL_NTF]           = &ethnl_wol_request_ops,
 551        [ETHTOOL_MSG_FEATURES_NTF]      = &ethnl_features_request_ops,
 552        [ETHTOOL_MSG_PRIVFLAGS_NTF]     = &ethnl_privflags_request_ops,
 553        [ETHTOOL_MSG_RINGS_NTF]         = &ethnl_rings_request_ops,
 554        [ETHTOOL_MSG_CHANNELS_NTF]      = &ethnl_channels_request_ops,
 555        [ETHTOOL_MSG_COALESCE_NTF]      = &ethnl_coalesce_request_ops,
 556        [ETHTOOL_MSG_PAUSE_NTF]         = &ethnl_pause_request_ops,
 557        [ETHTOOL_MSG_EEE_NTF]           = &ethnl_eee_request_ops,
 558};
 559
 560/* default notification handler */
 561static void ethnl_default_notify(struct net_device *dev, unsigned int cmd,
 562                                 const void *data)
 563{
 564        struct ethnl_reply_data *reply_data;
 565        const struct ethnl_request_ops *ops;
 566        struct ethnl_req_info *req_info;
 567        struct sk_buff *skb;
 568        void *reply_payload;
 569        int reply_len;
 570        int ret;
 571
 572        if (WARN_ONCE(cmd > ETHTOOL_MSG_KERNEL_MAX ||
 573                      !ethnl_default_notify_ops[cmd],
 574                      "unexpected notification type %u\n", cmd))
 575                return;
 576        ops = ethnl_default_notify_ops[cmd];
 577        req_info = kzalloc(ops->req_info_size, GFP_KERNEL);
 578        if (!req_info)
 579                return;
 580        reply_data = kmalloc(ops->reply_data_size, GFP_KERNEL);
 581        if (!reply_data) {
 582                kfree(req_info);
 583                return;
 584        }
 585
 586        req_info->dev = dev;
 587        req_info->flags |= ETHTOOL_FLAG_COMPACT_BITSETS;
 588
 589        ethnl_init_reply_data(reply_data, ops, dev);
 590        ret = ops->prepare_data(req_info, reply_data, NULL);
 591        if (ret < 0)
 592                goto err_cleanup;
 593        ret = ops->reply_size(req_info, reply_data);
 594        if (ret < 0)
 595                goto err_cleanup;
 596        reply_len = ret + ethnl_reply_header_size();
 597        ret = -ENOMEM;
 598        skb = genlmsg_new(reply_len, GFP_KERNEL);
 599        if (!skb)
 600                goto err_cleanup;
 601        reply_payload = ethnl_bcastmsg_put(skb, cmd);
 602        if (!reply_payload)
 603                goto err_skb;
 604        ret = ethnl_fill_reply_header(skb, dev, ops->hdr_attr);
 605        if (ret < 0)
 606                goto err_msg;
 607        ret = ops->fill_reply(skb, req_info, reply_data);
 608        if (ret < 0)
 609                goto err_msg;
 610        if (ops->cleanup_data)
 611                ops->cleanup_data(reply_data);
 612
 613        genlmsg_end(skb, reply_payload);
 614        kfree(reply_data);
 615        kfree(req_info);
 616        ethnl_multicast(skb, dev);
 617        return;
 618
 619err_msg:
 620        WARN_ONCE(ret == -EMSGSIZE,
 621                  "calculated message payload length (%d) not sufficient\n",
 622                  reply_len);
 623err_skb:
 624        nlmsg_free(skb);
 625err_cleanup:
 626        if (ops->cleanup_data)
 627                ops->cleanup_data(reply_data);
 628        kfree(reply_data);
 629        kfree(req_info);
 630        return;
 631}
 632
 633/* notifications */
 634
 635typedef void (*ethnl_notify_handler_t)(struct net_device *dev, unsigned int cmd,
 636                                       const void *data);
 637
 638static const ethnl_notify_handler_t ethnl_notify_handlers[] = {
 639        [ETHTOOL_MSG_LINKINFO_NTF]      = ethnl_default_notify,
 640        [ETHTOOL_MSG_LINKMODES_NTF]     = ethnl_default_notify,
 641        [ETHTOOL_MSG_DEBUG_NTF]         = ethnl_default_notify,
 642        [ETHTOOL_MSG_WOL_NTF]           = ethnl_default_notify,
 643        [ETHTOOL_MSG_FEATURES_NTF]      = ethnl_default_notify,
 644        [ETHTOOL_MSG_PRIVFLAGS_NTF]     = ethnl_default_notify,
 645        [ETHTOOL_MSG_RINGS_NTF]         = ethnl_default_notify,
 646        [ETHTOOL_MSG_CHANNELS_NTF]      = ethnl_default_notify,
 647        [ETHTOOL_MSG_COALESCE_NTF]      = ethnl_default_notify,
 648        [ETHTOOL_MSG_PAUSE_NTF]         = ethnl_default_notify,
 649        [ETHTOOL_MSG_EEE_NTF]           = ethnl_default_notify,
 650};
 651
 652void ethtool_notify(struct net_device *dev, unsigned int cmd, const void *data)
 653{
 654        if (unlikely(!ethnl_ok))
 655                return;
 656        ASSERT_RTNL();
 657
 658        if (likely(cmd < ARRAY_SIZE(ethnl_notify_handlers) &&
 659                   ethnl_notify_handlers[cmd]))
 660                ethnl_notify_handlers[cmd](dev, cmd, data);
 661        else
 662                WARN_ONCE(1, "notification %u not implemented (dev=%s)\n",
 663                          cmd, netdev_name(dev));
 664}
 665EXPORT_SYMBOL(ethtool_notify);
 666
 667static void ethnl_notify_features(struct netdev_notifier_info *info)
 668{
 669        struct net_device *dev = netdev_notifier_info_to_dev(info);
 670
 671        ethtool_notify(dev, ETHTOOL_MSG_FEATURES_NTF, NULL);
 672}
 673
 674static int ethnl_netdev_event(struct notifier_block *this, unsigned long event,
 675                              void *ptr)
 676{
 677        switch (event) {
 678        case NETDEV_FEAT_CHANGE:
 679                ethnl_notify_features(ptr);
 680                break;
 681        }
 682
 683        return NOTIFY_DONE;
 684}
 685
 686static struct notifier_block ethnl_netdev_notifier = {
 687        .notifier_call = ethnl_netdev_event,
 688};
 689
 690/* genetlink setup */
 691
 692static const struct genl_ops ethtool_genl_ops[] = {
 693        {
 694                .cmd    = ETHTOOL_MSG_STRSET_GET,
 695                .doit   = ethnl_default_doit,
 696                .start  = ethnl_default_start,
 697                .dumpit = ethnl_default_dumpit,
 698                .done   = ethnl_default_done,
 699        },
 700        {
 701                .cmd    = ETHTOOL_MSG_LINKINFO_GET,
 702                .doit   = ethnl_default_doit,
 703                .start  = ethnl_default_start,
 704                .dumpit = ethnl_default_dumpit,
 705                .done   = ethnl_default_done,
 706        },
 707        {
 708                .cmd    = ETHTOOL_MSG_LINKINFO_SET,
 709                .flags  = GENL_UNS_ADMIN_PERM,
 710                .doit   = ethnl_set_linkinfo,
 711        },
 712        {
 713                .cmd    = ETHTOOL_MSG_LINKMODES_GET,
 714                .doit   = ethnl_default_doit,
 715                .start  = ethnl_default_start,
 716                .dumpit = ethnl_default_dumpit,
 717                .done   = ethnl_default_done,
 718        },
 719        {
 720                .cmd    = ETHTOOL_MSG_LINKMODES_SET,
 721                .flags  = GENL_UNS_ADMIN_PERM,
 722                .doit   = ethnl_set_linkmodes,
 723        },
 724        {
 725                .cmd    = ETHTOOL_MSG_LINKSTATE_GET,
 726                .doit   = ethnl_default_doit,
 727                .start  = ethnl_default_start,
 728                .dumpit = ethnl_default_dumpit,
 729                .done   = ethnl_default_done,
 730        },
 731        {
 732                .cmd    = ETHTOOL_MSG_DEBUG_GET,
 733                .doit   = ethnl_default_doit,
 734                .start  = ethnl_default_start,
 735                .dumpit = ethnl_default_dumpit,
 736                .done   = ethnl_default_done,
 737        },
 738        {
 739                .cmd    = ETHTOOL_MSG_DEBUG_SET,
 740                .flags  = GENL_UNS_ADMIN_PERM,
 741                .doit   = ethnl_set_debug,
 742        },
 743        {
 744                .cmd    = ETHTOOL_MSG_WOL_GET,
 745                .flags  = GENL_UNS_ADMIN_PERM,
 746                .doit   = ethnl_default_doit,
 747                .start  = ethnl_default_start,
 748                .dumpit = ethnl_default_dumpit,
 749                .done   = ethnl_default_done,
 750        },
 751        {
 752                .cmd    = ETHTOOL_MSG_WOL_SET,
 753                .flags  = GENL_UNS_ADMIN_PERM,
 754                .doit   = ethnl_set_wol,
 755        },
 756        {
 757                .cmd    = ETHTOOL_MSG_FEATURES_GET,
 758                .doit   = ethnl_default_doit,
 759                .start  = ethnl_default_start,
 760                .dumpit = ethnl_default_dumpit,
 761                .done   = ethnl_default_done,
 762        },
 763        {
 764                .cmd    = ETHTOOL_MSG_FEATURES_SET,
 765                .flags  = GENL_UNS_ADMIN_PERM,
 766                .doit   = ethnl_set_features,
 767        },
 768        {
 769                .cmd    = ETHTOOL_MSG_PRIVFLAGS_GET,
 770                .doit   = ethnl_default_doit,
 771                .start  = ethnl_default_start,
 772                .dumpit = ethnl_default_dumpit,
 773                .done   = ethnl_default_done,
 774        },
 775        {
 776                .cmd    = ETHTOOL_MSG_PRIVFLAGS_SET,
 777                .flags  = GENL_UNS_ADMIN_PERM,
 778                .doit   = ethnl_set_privflags,
 779        },
 780        {
 781                .cmd    = ETHTOOL_MSG_RINGS_GET,
 782                .doit   = ethnl_default_doit,
 783                .start  = ethnl_default_start,
 784                .dumpit = ethnl_default_dumpit,
 785                .done   = ethnl_default_done,
 786        },
 787        {
 788                .cmd    = ETHTOOL_MSG_RINGS_SET,
 789                .flags  = GENL_UNS_ADMIN_PERM,
 790                .doit   = ethnl_set_rings,
 791        },
 792        {
 793                .cmd    = ETHTOOL_MSG_CHANNELS_GET,
 794                .doit   = ethnl_default_doit,
 795                .start  = ethnl_default_start,
 796                .dumpit = ethnl_default_dumpit,
 797                .done   = ethnl_default_done,
 798        },
 799        {
 800                .cmd    = ETHTOOL_MSG_CHANNELS_SET,
 801                .flags  = GENL_UNS_ADMIN_PERM,
 802                .doit   = ethnl_set_channels,
 803        },
 804        {
 805                .cmd    = ETHTOOL_MSG_COALESCE_GET,
 806                .doit   = ethnl_default_doit,
 807                .start  = ethnl_default_start,
 808                .dumpit = ethnl_default_dumpit,
 809                .done   = ethnl_default_done,
 810        },
 811        {
 812                .cmd    = ETHTOOL_MSG_COALESCE_SET,
 813                .flags  = GENL_UNS_ADMIN_PERM,
 814                .doit   = ethnl_set_coalesce,
 815        },
 816        {
 817                .cmd    = ETHTOOL_MSG_PAUSE_GET,
 818                .doit   = ethnl_default_doit,
 819                .start  = ethnl_default_start,
 820                .dumpit = ethnl_default_dumpit,
 821                .done   = ethnl_default_done,
 822        },
 823        {
 824                .cmd    = ETHTOOL_MSG_PAUSE_SET,
 825                .flags  = GENL_UNS_ADMIN_PERM,
 826                .doit   = ethnl_set_pause,
 827        },
 828        {
 829                .cmd    = ETHTOOL_MSG_EEE_GET,
 830                .doit   = ethnl_default_doit,
 831                .start  = ethnl_default_start,
 832                .dumpit = ethnl_default_dumpit,
 833                .done   = ethnl_default_done,
 834        },
 835        {
 836                .cmd    = ETHTOOL_MSG_EEE_SET,
 837                .flags  = GENL_UNS_ADMIN_PERM,
 838                .doit   = ethnl_set_eee,
 839        },
 840        {
 841                .cmd    = ETHTOOL_MSG_TSINFO_GET,
 842                .doit   = ethnl_default_doit,
 843                .start  = ethnl_default_start,
 844                .dumpit = ethnl_default_dumpit,
 845                .done   = ethnl_default_done,
 846        },
 847        {
 848                .cmd    = ETHTOOL_MSG_CABLE_TEST_ACT,
 849                .flags  = GENL_UNS_ADMIN_PERM,
 850                .doit   = ethnl_act_cable_test,
 851        },
 852        {
 853                .cmd    = ETHTOOL_MSG_CABLE_TEST_TDR_ACT,
 854                .flags  = GENL_UNS_ADMIN_PERM,
 855                .doit   = ethnl_act_cable_test_tdr,
 856        },
 857        {
 858                .cmd    = ETHTOOL_MSG_TUNNEL_INFO_GET,
 859                .doit   = ethnl_tunnel_info_doit,
 860                .start  = ethnl_tunnel_info_start,
 861                .dumpit = ethnl_tunnel_info_dumpit,
 862        },
 863};
 864
 865static const struct genl_multicast_group ethtool_nl_mcgrps[] = {
 866        [ETHNL_MCGRP_MONITOR] = { .name = ETHTOOL_MCGRP_MONITOR_NAME },
 867};
 868
 869static struct genl_family ethtool_genl_family __ro_after_init = {
 870        .name           = ETHTOOL_GENL_NAME,
 871        .version        = ETHTOOL_GENL_VERSION,
 872        .netnsok        = true,
 873        .parallel_ops   = true,
 874        .ops            = ethtool_genl_ops,
 875        .n_ops          = ARRAY_SIZE(ethtool_genl_ops),
 876        .mcgrps         = ethtool_nl_mcgrps,
 877        .n_mcgrps       = ARRAY_SIZE(ethtool_nl_mcgrps),
 878};
 879
 880/* module setup */
 881
 882static int __init ethnl_init(void)
 883{
 884        int ret;
 885
 886        ret = genl_register_family(&ethtool_genl_family);
 887        if (WARN(ret < 0, "ethtool: genetlink family registration failed"))
 888                return ret;
 889        ethnl_ok = true;
 890
 891        ret = register_netdevice_notifier(&ethnl_netdev_notifier);
 892        WARN(ret < 0, "ethtool: net device notifier registration failed");
 893        return ret;
 894}
 895
 896subsys_initcall(ethnl_init);
 897