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