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