linux/net/dcb/dcbnl.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2008, Intel Corporation.
   3 *
   4 * This program is free software; you can redistribute it and/or modify it
   5 * under the terms and conditions of the GNU General Public License,
   6 * version 2, as published by the Free Software Foundation.
   7 *
   8 * This program is distributed in the hope it will be useful, but WITHOUT
   9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  10 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  11 * more details.
  12 *
  13 * You should have received a copy of the GNU General Public License along with
  14 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
  15 * Place - Suite 330, Boston, MA 02111-1307 USA.
  16 *
  17 * Author: Lucy Liu <lucy.liu@intel.com>
  18 */
  19
  20#include <linux/netdevice.h>
  21#include <linux/netlink.h>
  22#include <net/netlink.h>
  23#include <net/rtnetlink.h>
  24#include <linux/dcbnl.h>
  25#include <linux/rtnetlink.h>
  26#include <net/sock.h>
  27
  28/**
  29 * Data Center Bridging (DCB) is a collection of Ethernet enhancements
  30 * intended to allow network traffic with differing requirements
  31 * (highly reliable, no drops vs. best effort vs. low latency) to operate
  32 * and co-exist on Ethernet.  Current DCB features are:
  33 *
  34 * Enhanced Transmission Selection (aka Priority Grouping [PG]) - provides a
  35 *   framework for assigning bandwidth guarantees to traffic classes.
  36 *
  37 * Priority-based Flow Control (PFC) - provides a flow control mechanism which
  38 *   can work independently for each 802.1p priority.
  39 *
  40 * Congestion Notification - provides a mechanism for end-to-end congestion
  41 *   control for protocols which do not have built-in congestion management.
  42 *
  43 * More information about the emerging standards for these Ethernet features
  44 * can be found at: http://www.ieee802.org/1/pages/dcbridges.html
  45 *
  46 * This file implements an rtnetlink interface to allow configuration of DCB
  47 * features for capable devices.
  48 */
  49
  50MODULE_AUTHOR("Lucy Liu, <lucy.liu@intel.com>");
  51MODULE_DESCRIPTION("Data Center Bridging netlink interface");
  52MODULE_LICENSE("GPL");
  53
  54/**************** DCB attribute policies *************************************/
  55
  56/* DCB netlink attributes policy */
  57static struct nla_policy dcbnl_rtnl_policy[DCB_ATTR_MAX + 1] = {
  58        [DCB_ATTR_IFNAME]      = {.type = NLA_NUL_STRING, .len = IFNAMSIZ - 1},
  59        [DCB_ATTR_STATE]       = {.type = NLA_U8},
  60        [DCB_ATTR_PFC_CFG]     = {.type = NLA_NESTED},
  61        [DCB_ATTR_PG_CFG]      = {.type = NLA_NESTED},
  62        [DCB_ATTR_SET_ALL]     = {.type = NLA_U8},
  63        [DCB_ATTR_PERM_HWADDR] = {.type = NLA_FLAG},
  64        [DCB_ATTR_CAP]         = {.type = NLA_NESTED},
  65        [DCB_ATTR_PFC_STATE]   = {.type = NLA_U8},
  66        [DCB_ATTR_BCN]         = {.type = NLA_NESTED},
  67};
  68
  69/* DCB priority flow control to User Priority nested attributes */
  70static struct nla_policy dcbnl_pfc_up_nest[DCB_PFC_UP_ATTR_MAX + 1] = {
  71        [DCB_PFC_UP_ATTR_0]   = {.type = NLA_U8},
  72        [DCB_PFC_UP_ATTR_1]   = {.type = NLA_U8},
  73        [DCB_PFC_UP_ATTR_2]   = {.type = NLA_U8},
  74        [DCB_PFC_UP_ATTR_3]   = {.type = NLA_U8},
  75        [DCB_PFC_UP_ATTR_4]   = {.type = NLA_U8},
  76        [DCB_PFC_UP_ATTR_5]   = {.type = NLA_U8},
  77        [DCB_PFC_UP_ATTR_6]   = {.type = NLA_U8},
  78        [DCB_PFC_UP_ATTR_7]   = {.type = NLA_U8},
  79        [DCB_PFC_UP_ATTR_ALL] = {.type = NLA_FLAG},
  80};
  81
  82/* DCB priority grouping nested attributes */
  83static struct nla_policy dcbnl_pg_nest[DCB_PG_ATTR_MAX + 1] = {
  84        [DCB_PG_ATTR_TC_0]      = {.type = NLA_NESTED},
  85        [DCB_PG_ATTR_TC_1]      = {.type = NLA_NESTED},
  86        [DCB_PG_ATTR_TC_2]      = {.type = NLA_NESTED},
  87        [DCB_PG_ATTR_TC_3]      = {.type = NLA_NESTED},
  88        [DCB_PG_ATTR_TC_4]      = {.type = NLA_NESTED},
  89        [DCB_PG_ATTR_TC_5]      = {.type = NLA_NESTED},
  90        [DCB_PG_ATTR_TC_6]      = {.type = NLA_NESTED},
  91        [DCB_PG_ATTR_TC_7]      = {.type = NLA_NESTED},
  92        [DCB_PG_ATTR_TC_ALL]    = {.type = NLA_NESTED},
  93        [DCB_PG_ATTR_BW_ID_0]   = {.type = NLA_U8},
  94        [DCB_PG_ATTR_BW_ID_1]   = {.type = NLA_U8},
  95        [DCB_PG_ATTR_BW_ID_2]   = {.type = NLA_U8},
  96        [DCB_PG_ATTR_BW_ID_3]   = {.type = NLA_U8},
  97        [DCB_PG_ATTR_BW_ID_4]   = {.type = NLA_U8},
  98        [DCB_PG_ATTR_BW_ID_5]   = {.type = NLA_U8},
  99        [DCB_PG_ATTR_BW_ID_6]   = {.type = NLA_U8},
 100        [DCB_PG_ATTR_BW_ID_7]   = {.type = NLA_U8},
 101        [DCB_PG_ATTR_BW_ID_ALL] = {.type = NLA_FLAG},
 102};
 103
 104/* DCB traffic class nested attributes. */
 105static struct nla_policy dcbnl_tc_param_nest[DCB_TC_ATTR_PARAM_MAX + 1] = {
 106        [DCB_TC_ATTR_PARAM_PGID]            = {.type = NLA_U8},
 107        [DCB_TC_ATTR_PARAM_UP_MAPPING]      = {.type = NLA_U8},
 108        [DCB_TC_ATTR_PARAM_STRICT_PRIO]     = {.type = NLA_U8},
 109        [DCB_TC_ATTR_PARAM_BW_PCT]          = {.type = NLA_U8},
 110        [DCB_TC_ATTR_PARAM_ALL]             = {.type = NLA_FLAG},
 111};
 112
 113/* DCB capabilities nested attributes. */
 114static struct nla_policy dcbnl_cap_nest[DCB_CAP_ATTR_MAX + 1] = {
 115        [DCB_CAP_ATTR_ALL]     = {.type = NLA_FLAG},
 116        [DCB_CAP_ATTR_PG]      = {.type = NLA_U8},
 117        [DCB_CAP_ATTR_PFC]     = {.type = NLA_U8},
 118        [DCB_CAP_ATTR_UP2TC]   = {.type = NLA_U8},
 119        [DCB_CAP_ATTR_PG_TCS]  = {.type = NLA_U8},
 120        [DCB_CAP_ATTR_PFC_TCS] = {.type = NLA_U8},
 121        [DCB_CAP_ATTR_GSP]     = {.type = NLA_U8},
 122        [DCB_CAP_ATTR_BCN]     = {.type = NLA_U8},
 123};
 124
 125/* DCB capabilities nested attributes. */
 126static struct nla_policy dcbnl_numtcs_nest[DCB_NUMTCS_ATTR_MAX + 1] = {
 127        [DCB_NUMTCS_ATTR_ALL]     = {.type = NLA_FLAG},
 128        [DCB_NUMTCS_ATTR_PG]      = {.type = NLA_U8},
 129        [DCB_NUMTCS_ATTR_PFC]     = {.type = NLA_U8},
 130};
 131
 132/* DCB BCN nested attributes. */
 133static struct nla_policy dcbnl_bcn_nest[DCB_BCN_ATTR_MAX + 1] = {
 134        [DCB_BCN_ATTR_RP_0]         = {.type = NLA_U8},
 135        [DCB_BCN_ATTR_RP_1]         = {.type = NLA_U8},
 136        [DCB_BCN_ATTR_RP_2]         = {.type = NLA_U8},
 137        [DCB_BCN_ATTR_RP_3]         = {.type = NLA_U8},
 138        [DCB_BCN_ATTR_RP_4]         = {.type = NLA_U8},
 139        [DCB_BCN_ATTR_RP_5]         = {.type = NLA_U8},
 140        [DCB_BCN_ATTR_RP_6]         = {.type = NLA_U8},
 141        [DCB_BCN_ATTR_RP_7]         = {.type = NLA_U8},
 142        [DCB_BCN_ATTR_RP_ALL]       = {.type = NLA_FLAG},
 143        [DCB_BCN_ATTR_BCNA_0]       = {.type = NLA_U32},
 144        [DCB_BCN_ATTR_BCNA_1]       = {.type = NLA_U32},
 145        [DCB_BCN_ATTR_ALPHA]        = {.type = NLA_U32},
 146        [DCB_BCN_ATTR_BETA]         = {.type = NLA_U32},
 147        [DCB_BCN_ATTR_GD]           = {.type = NLA_U32},
 148        [DCB_BCN_ATTR_GI]           = {.type = NLA_U32},
 149        [DCB_BCN_ATTR_TMAX]         = {.type = NLA_U32},
 150        [DCB_BCN_ATTR_TD]           = {.type = NLA_U32},
 151        [DCB_BCN_ATTR_RMIN]         = {.type = NLA_U32},
 152        [DCB_BCN_ATTR_W]            = {.type = NLA_U32},
 153        [DCB_BCN_ATTR_RD]           = {.type = NLA_U32},
 154        [DCB_BCN_ATTR_RU]           = {.type = NLA_U32},
 155        [DCB_BCN_ATTR_WRTT]         = {.type = NLA_U32},
 156        [DCB_BCN_ATTR_RI]           = {.type = NLA_U32},
 157        [DCB_BCN_ATTR_C]            = {.type = NLA_U32},
 158        [DCB_BCN_ATTR_ALL]          = {.type = NLA_FLAG},
 159};
 160
 161/* standard netlink reply call */
 162static int dcbnl_reply(u8 value, u8 event, u8 cmd, u8 attr, u32 pid,
 163                       u32 seq, u16 flags)
 164{
 165        struct sk_buff *dcbnl_skb;
 166        struct dcbmsg *dcb;
 167        struct nlmsghdr *nlh;
 168        int ret = -EINVAL;
 169
 170        dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
 171        if (!dcbnl_skb)
 172                return ret;
 173
 174        nlh = NLMSG_NEW(dcbnl_skb, pid, seq, event, sizeof(*dcb), flags);
 175
 176        dcb = NLMSG_DATA(nlh);
 177        dcb->dcb_family = AF_UNSPEC;
 178        dcb->cmd = cmd;
 179        dcb->dcb_pad = 0;
 180
 181        ret = nla_put_u8(dcbnl_skb, attr, value);
 182        if (ret)
 183                goto err;
 184
 185        /* end the message, assign the nlmsg_len. */
 186        nlmsg_end(dcbnl_skb, nlh);
 187        ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
 188        if (ret)
 189                goto err;
 190
 191        return 0;
 192nlmsg_failure:
 193err:
 194        kfree_skb(dcbnl_skb);
 195        return ret;
 196}
 197
 198static int dcbnl_getstate(struct net_device *netdev, struct nlattr **tb,
 199                          u32 pid, u32 seq, u16 flags)
 200{
 201        int ret = -EINVAL;
 202
 203        /* if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->getstate) */
 204        if (!netdev->dcbnl_ops->getstate)
 205                return ret;
 206
 207        ret = dcbnl_reply(netdev->dcbnl_ops->getstate(netdev), RTM_GETDCB,
 208                          DCB_CMD_GSTATE, DCB_ATTR_STATE, pid, seq, flags);
 209
 210        return ret;
 211}
 212
 213static int dcbnl_getpfccfg(struct net_device *netdev, struct nlattr **tb,
 214                           u32 pid, u32 seq, u16 flags)
 215{
 216        struct sk_buff *dcbnl_skb;
 217        struct nlmsghdr *nlh;
 218        struct dcbmsg *dcb;
 219        struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1], *nest;
 220        u8 value;
 221        int ret = -EINVAL;
 222        int i;
 223        int getall = 0;
 224
 225        if (!tb[DCB_ATTR_PFC_CFG] || !netdev->dcbnl_ops->getpfccfg)
 226                return ret;
 227
 228        ret = nla_parse_nested(data, DCB_PFC_UP_ATTR_MAX,
 229                               tb[DCB_ATTR_PFC_CFG],
 230                               dcbnl_pfc_up_nest);
 231        if (ret)
 232                goto err_out;
 233
 234        dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
 235        if (!dcbnl_skb)
 236                goto err_out;
 237
 238        nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
 239
 240        dcb = NLMSG_DATA(nlh);
 241        dcb->dcb_family = AF_UNSPEC;
 242        dcb->cmd = DCB_CMD_PFC_GCFG;
 243
 244        nest = nla_nest_start(dcbnl_skb, DCB_ATTR_PFC_CFG);
 245        if (!nest)
 246                goto err;
 247
 248        if (data[DCB_PFC_UP_ATTR_ALL])
 249                getall = 1;
 250
 251        for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) {
 252                if (!getall && !data[i])
 253                        continue;
 254
 255                netdev->dcbnl_ops->getpfccfg(netdev, i - DCB_PFC_UP_ATTR_0,
 256                                             &value);
 257                ret = nla_put_u8(dcbnl_skb, i, value);
 258
 259                if (ret) {
 260                        nla_nest_cancel(dcbnl_skb, nest);
 261                        goto err;
 262                }
 263        }
 264        nla_nest_end(dcbnl_skb, nest);
 265
 266        nlmsg_end(dcbnl_skb, nlh);
 267
 268        ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
 269        if (ret)
 270                goto err;
 271
 272        return 0;
 273nlmsg_failure:
 274err:
 275        kfree_skb(dcbnl_skb);
 276err_out:
 277        return -EINVAL;
 278}
 279
 280static int dcbnl_getperm_hwaddr(struct net_device *netdev, struct nlattr **tb,
 281                                u32 pid, u32 seq, u16 flags)
 282{
 283        struct sk_buff *dcbnl_skb;
 284        struct nlmsghdr *nlh;
 285        struct dcbmsg *dcb;
 286        u8 perm_addr[MAX_ADDR_LEN];
 287        int ret = -EINVAL;
 288
 289        if (!netdev->dcbnl_ops->getpermhwaddr)
 290                return ret;
 291
 292        dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
 293        if (!dcbnl_skb)
 294                goto err_out;
 295
 296        nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
 297
 298        dcb = NLMSG_DATA(nlh);
 299        dcb->dcb_family = AF_UNSPEC;
 300        dcb->cmd = DCB_CMD_GPERM_HWADDR;
 301
 302        netdev->dcbnl_ops->getpermhwaddr(netdev, perm_addr);
 303
 304        ret = nla_put(dcbnl_skb, DCB_ATTR_PERM_HWADDR, sizeof(perm_addr),
 305                      perm_addr);
 306
 307        nlmsg_end(dcbnl_skb, nlh);
 308
 309        ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
 310        if (ret)
 311                goto err;
 312
 313        return 0;
 314
 315nlmsg_failure:
 316err:
 317        kfree_skb(dcbnl_skb);
 318err_out:
 319        return -EINVAL;
 320}
 321
 322static int dcbnl_getcap(struct net_device *netdev, struct nlattr **tb,
 323                        u32 pid, u32 seq, u16 flags)
 324{
 325        struct sk_buff *dcbnl_skb;
 326        struct nlmsghdr *nlh;
 327        struct dcbmsg *dcb;
 328        struct nlattr *data[DCB_CAP_ATTR_MAX + 1], *nest;
 329        u8 value;
 330        int ret = -EINVAL;
 331        int i;
 332        int getall = 0;
 333
 334        if (!tb[DCB_ATTR_CAP] || !netdev->dcbnl_ops->getcap)
 335                return ret;
 336
 337        ret = nla_parse_nested(data, DCB_CAP_ATTR_MAX, tb[DCB_ATTR_CAP],
 338                               dcbnl_cap_nest);
 339        if (ret)
 340                goto err_out;
 341
 342        dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
 343        if (!dcbnl_skb)
 344                goto err_out;
 345
 346        nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
 347
 348        dcb = NLMSG_DATA(nlh);
 349        dcb->dcb_family = AF_UNSPEC;
 350        dcb->cmd = DCB_CMD_GCAP;
 351
 352        nest = nla_nest_start(dcbnl_skb, DCB_ATTR_CAP);
 353        if (!nest)
 354                goto err;
 355
 356        if (data[DCB_CAP_ATTR_ALL])
 357                getall = 1;
 358
 359        for (i = DCB_CAP_ATTR_ALL+1; i <= DCB_CAP_ATTR_MAX; i++) {
 360                if (!getall && !data[i])
 361                        continue;
 362
 363                if (!netdev->dcbnl_ops->getcap(netdev, i, &value)) {
 364                        ret = nla_put_u8(dcbnl_skb, i, value);
 365
 366                        if (ret) {
 367                                nla_nest_cancel(dcbnl_skb, nest);
 368                                goto err;
 369                        }
 370                }
 371        }
 372        nla_nest_end(dcbnl_skb, nest);
 373
 374        nlmsg_end(dcbnl_skb, nlh);
 375
 376        ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
 377        if (ret)
 378                goto err;
 379
 380        return 0;
 381nlmsg_failure:
 382err:
 383        kfree_skb(dcbnl_skb);
 384err_out:
 385        return -EINVAL;
 386}
 387
 388static int dcbnl_getnumtcs(struct net_device *netdev, struct nlattr **tb,
 389                           u32 pid, u32 seq, u16 flags)
 390{
 391        struct sk_buff *dcbnl_skb;
 392        struct nlmsghdr *nlh;
 393        struct dcbmsg *dcb;
 394        struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1], *nest;
 395        u8 value;
 396        int ret = -EINVAL;
 397        int i;
 398        int getall = 0;
 399
 400        if (!tb[DCB_ATTR_NUMTCS] || !netdev->dcbnl_ops->getnumtcs)
 401                return ret;
 402
 403        ret = nla_parse_nested(data, DCB_NUMTCS_ATTR_MAX, tb[DCB_ATTR_NUMTCS],
 404                               dcbnl_numtcs_nest);
 405        if (ret) {
 406                ret = -EINVAL;
 407                goto err_out;
 408        }
 409
 410        dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
 411        if (!dcbnl_skb) {
 412                ret = -EINVAL;
 413                goto err_out;
 414        }
 415
 416        nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
 417
 418        dcb = NLMSG_DATA(nlh);
 419        dcb->dcb_family = AF_UNSPEC;
 420        dcb->cmd = DCB_CMD_GNUMTCS;
 421
 422        nest = nla_nest_start(dcbnl_skb, DCB_ATTR_NUMTCS);
 423        if (!nest) {
 424                ret = -EINVAL;
 425                goto err;
 426        }
 427
 428        if (data[DCB_NUMTCS_ATTR_ALL])
 429                getall = 1;
 430
 431        for (i = DCB_NUMTCS_ATTR_ALL+1; i <= DCB_NUMTCS_ATTR_MAX; i++) {
 432                if (!getall && !data[i])
 433                        continue;
 434
 435                ret = netdev->dcbnl_ops->getnumtcs(netdev, i, &value);
 436                if (!ret) {
 437                        ret = nla_put_u8(dcbnl_skb, i, value);
 438
 439                        if (ret) {
 440                                nla_nest_cancel(dcbnl_skb, nest);
 441                                ret = -EINVAL;
 442                                goto err;
 443                        }
 444                } else {
 445                        goto err;
 446                }
 447        }
 448        nla_nest_end(dcbnl_skb, nest);
 449
 450        nlmsg_end(dcbnl_skb, nlh);
 451
 452        ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
 453        if (ret) {
 454                ret = -EINVAL;
 455                goto err;
 456        }
 457
 458        return 0;
 459nlmsg_failure:
 460err:
 461        kfree_skb(dcbnl_skb);
 462err_out:
 463        return ret;
 464}
 465
 466static int dcbnl_setnumtcs(struct net_device *netdev, struct nlattr **tb,
 467                           u32 pid, u32 seq, u16 flags)
 468{
 469        struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1];
 470        int ret = -EINVAL;
 471        u8 value;
 472        int i;
 473
 474        if (!tb[DCB_ATTR_NUMTCS] || !netdev->dcbnl_ops->setnumtcs)
 475                return ret;
 476
 477        ret = nla_parse_nested(data, DCB_NUMTCS_ATTR_MAX, tb[DCB_ATTR_NUMTCS],
 478                               dcbnl_numtcs_nest);
 479
 480        if (ret) {
 481                ret = -EINVAL;
 482                goto err;
 483        }
 484
 485        for (i = DCB_NUMTCS_ATTR_ALL+1; i <= DCB_NUMTCS_ATTR_MAX; i++) {
 486                if (data[i] == NULL)
 487                        continue;
 488
 489                value = nla_get_u8(data[i]);
 490
 491                ret = netdev->dcbnl_ops->setnumtcs(netdev, i, value);
 492
 493                if (ret)
 494                        goto operr;
 495        }
 496
 497operr:
 498        ret = dcbnl_reply(!!ret, RTM_SETDCB, DCB_CMD_SNUMTCS,
 499                          DCB_ATTR_NUMTCS, pid, seq, flags);
 500
 501err:
 502        return ret;
 503}
 504
 505static int dcbnl_getpfcstate(struct net_device *netdev, struct nlattr **tb,
 506                             u32 pid, u32 seq, u16 flags)
 507{
 508        int ret = -EINVAL;
 509
 510        if (!netdev->dcbnl_ops->getpfcstate)
 511                return ret;
 512
 513        ret = dcbnl_reply(netdev->dcbnl_ops->getpfcstate(netdev), RTM_GETDCB,
 514                          DCB_CMD_PFC_GSTATE, DCB_ATTR_PFC_STATE,
 515                          pid, seq, flags);
 516
 517        return ret;
 518}
 519
 520static int dcbnl_setpfcstate(struct net_device *netdev, struct nlattr **tb,
 521                             u32 pid, u32 seq, u16 flags)
 522{
 523        int ret = -EINVAL;
 524        u8 value;
 525
 526        if (!tb[DCB_ATTR_PFC_STATE] || !netdev->dcbnl_ops->setpfcstate)
 527                return ret;
 528
 529        value = nla_get_u8(tb[DCB_ATTR_PFC_STATE]);
 530
 531        netdev->dcbnl_ops->setpfcstate(netdev, value);
 532
 533        ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_PFC_SSTATE, DCB_ATTR_PFC_STATE,
 534                          pid, seq, flags);
 535
 536        return ret;
 537}
 538
 539static int __dcbnl_pg_getcfg(struct net_device *netdev, struct nlattr **tb,
 540                             u32 pid, u32 seq, u16 flags, int dir)
 541{
 542        struct sk_buff *dcbnl_skb;
 543        struct nlmsghdr *nlh;
 544        struct dcbmsg *dcb;
 545        struct nlattr *pg_nest, *param_nest, *data;
 546        struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1];
 547        struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1];
 548        u8 prio, pgid, tc_pct, up_map;
 549        int ret  = -EINVAL;
 550        int getall = 0;
 551        int i;
 552
 553        if (!tb[DCB_ATTR_PG_CFG] ||
 554            !netdev->dcbnl_ops->getpgtccfgtx ||
 555            !netdev->dcbnl_ops->getpgtccfgrx ||
 556            !netdev->dcbnl_ops->getpgbwgcfgtx ||
 557            !netdev->dcbnl_ops->getpgbwgcfgrx)
 558                return ret;
 559
 560        ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX,
 561                               tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest);
 562
 563        if (ret)
 564                goto err_out;
 565
 566        dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
 567        if (!dcbnl_skb)
 568                goto err_out;
 569
 570        nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
 571
 572        dcb = NLMSG_DATA(nlh);
 573        dcb->dcb_family = AF_UNSPEC;
 574        dcb->cmd = (dir) ? DCB_CMD_PGRX_GCFG : DCB_CMD_PGTX_GCFG;
 575
 576        pg_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_PG_CFG);
 577        if (!pg_nest)
 578                goto err;
 579
 580        if (pg_tb[DCB_PG_ATTR_TC_ALL])
 581                getall = 1;
 582
 583        for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) {
 584                if (!getall && !pg_tb[i])
 585                        continue;
 586
 587                if (pg_tb[DCB_PG_ATTR_TC_ALL])
 588                        data = pg_tb[DCB_PG_ATTR_TC_ALL];
 589                else
 590                        data = pg_tb[i];
 591                ret = nla_parse_nested(param_tb, DCB_TC_ATTR_PARAM_MAX,
 592                                       data, dcbnl_tc_param_nest);
 593                if (ret)
 594                        goto err_pg;
 595
 596                param_nest = nla_nest_start(dcbnl_skb, i);
 597                if (!param_nest)
 598                        goto err_pg;
 599
 600                pgid = DCB_ATTR_VALUE_UNDEFINED;
 601                prio = DCB_ATTR_VALUE_UNDEFINED;
 602                tc_pct = DCB_ATTR_VALUE_UNDEFINED;
 603                up_map = DCB_ATTR_VALUE_UNDEFINED;
 604
 605                if (dir) {
 606                        /* Rx */
 607                        netdev->dcbnl_ops->getpgtccfgrx(netdev,
 608                                                i - DCB_PG_ATTR_TC_0, &prio,
 609                                                &pgid, &tc_pct, &up_map);
 610                } else {
 611                        /* Tx */
 612                        netdev->dcbnl_ops->getpgtccfgtx(netdev,
 613                                                i - DCB_PG_ATTR_TC_0, &prio,
 614                                                &pgid, &tc_pct, &up_map);
 615                }
 616
 617                if (param_tb[DCB_TC_ATTR_PARAM_PGID] ||
 618                    param_tb[DCB_TC_ATTR_PARAM_ALL]) {
 619                        ret = nla_put_u8(dcbnl_skb,
 620                                         DCB_TC_ATTR_PARAM_PGID, pgid);
 621                        if (ret)
 622                                goto err_param;
 623                }
 624                if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING] ||
 625                    param_tb[DCB_TC_ATTR_PARAM_ALL]) {
 626                        ret = nla_put_u8(dcbnl_skb,
 627                                         DCB_TC_ATTR_PARAM_UP_MAPPING, up_map);
 628                        if (ret)
 629                                goto err_param;
 630                }
 631                if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO] ||
 632                    param_tb[DCB_TC_ATTR_PARAM_ALL]) {
 633                        ret = nla_put_u8(dcbnl_skb,
 634                                         DCB_TC_ATTR_PARAM_STRICT_PRIO, prio);
 635                        if (ret)
 636                                goto err_param;
 637                }
 638                if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT] ||
 639                    param_tb[DCB_TC_ATTR_PARAM_ALL]) {
 640                        ret = nla_put_u8(dcbnl_skb, DCB_TC_ATTR_PARAM_BW_PCT,
 641                                         tc_pct);
 642                        if (ret)
 643                                goto err_param;
 644                }
 645                nla_nest_end(dcbnl_skb, param_nest);
 646        }
 647
 648        if (pg_tb[DCB_PG_ATTR_BW_ID_ALL])
 649                getall = 1;
 650        else
 651                getall = 0;
 652
 653        for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) {
 654                if (!getall && !pg_tb[i])
 655                        continue;
 656
 657                tc_pct = DCB_ATTR_VALUE_UNDEFINED;
 658
 659                if (dir) {
 660                        /* Rx */
 661                        netdev->dcbnl_ops->getpgbwgcfgrx(netdev,
 662                                        i - DCB_PG_ATTR_BW_ID_0, &tc_pct);
 663                } else {
 664                        /* Tx */
 665                        netdev->dcbnl_ops->getpgbwgcfgtx(netdev,
 666                                        i - DCB_PG_ATTR_BW_ID_0, &tc_pct);
 667                }
 668                ret = nla_put_u8(dcbnl_skb, i, tc_pct);
 669
 670                if (ret)
 671                        goto err_pg;
 672        }
 673
 674        nla_nest_end(dcbnl_skb, pg_nest);
 675
 676        nlmsg_end(dcbnl_skb, nlh);
 677
 678        ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
 679        if (ret)
 680                goto err;
 681
 682        return 0;
 683
 684err_param:
 685        nla_nest_cancel(dcbnl_skb, param_nest);
 686err_pg:
 687        nla_nest_cancel(dcbnl_skb, pg_nest);
 688nlmsg_failure:
 689err:
 690        kfree_skb(dcbnl_skb);
 691err_out:
 692        ret  = -EINVAL;
 693        return ret;
 694}
 695
 696static int dcbnl_pgtx_getcfg(struct net_device *netdev, struct nlattr **tb,
 697                             u32 pid, u32 seq, u16 flags)
 698{
 699        return __dcbnl_pg_getcfg(netdev, tb, pid, seq, flags, 0);
 700}
 701
 702static int dcbnl_pgrx_getcfg(struct net_device *netdev, struct nlattr **tb,
 703                             u32 pid, u32 seq, u16 flags)
 704{
 705        return __dcbnl_pg_getcfg(netdev, tb, pid, seq, flags, 1);
 706}
 707
 708static int dcbnl_setstate(struct net_device *netdev, struct nlattr **tb,
 709                          u32 pid, u32 seq, u16 flags)
 710{
 711        int ret = -EINVAL;
 712        u8 value;
 713
 714        if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->setstate)
 715                return ret;
 716
 717        value = nla_get_u8(tb[DCB_ATTR_STATE]);
 718
 719        ret = dcbnl_reply(netdev->dcbnl_ops->setstate(netdev, value),
 720                          RTM_SETDCB, DCB_CMD_SSTATE, DCB_ATTR_STATE,
 721                          pid, seq, flags);
 722
 723        return ret;
 724}
 725
 726static int dcbnl_setpfccfg(struct net_device *netdev, struct nlattr **tb,
 727                           u32 pid, u32 seq, u16 flags)
 728{
 729        struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1];
 730        int i;
 731        int ret = -EINVAL;
 732        u8 value;
 733
 734        if (!tb[DCB_ATTR_PFC_CFG] || !netdev->dcbnl_ops->setpfccfg)
 735                return ret;
 736
 737        ret = nla_parse_nested(data, DCB_PFC_UP_ATTR_MAX,
 738                               tb[DCB_ATTR_PFC_CFG],
 739                               dcbnl_pfc_up_nest);
 740        if (ret)
 741                goto err;
 742
 743        for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) {
 744                if (data[i] == NULL)
 745                        continue;
 746                value = nla_get_u8(data[i]);
 747                netdev->dcbnl_ops->setpfccfg(netdev,
 748                        data[i]->nla_type - DCB_PFC_UP_ATTR_0, value);
 749        }
 750
 751        ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_PFC_SCFG, DCB_ATTR_PFC_CFG,
 752                          pid, seq, flags);
 753err:
 754        return ret;
 755}
 756
 757static int dcbnl_setall(struct net_device *netdev, struct nlattr **tb,
 758                        u32 pid, u32 seq, u16 flags)
 759{
 760        int ret = -EINVAL;
 761
 762        if (!tb[DCB_ATTR_SET_ALL] || !netdev->dcbnl_ops->setall)
 763                return ret;
 764
 765        ret = dcbnl_reply(netdev->dcbnl_ops->setall(netdev), RTM_SETDCB,
 766                          DCB_CMD_SET_ALL, DCB_ATTR_SET_ALL, pid, seq, flags);
 767
 768        return ret;
 769}
 770
 771static int __dcbnl_pg_setcfg(struct net_device *netdev, struct nlattr **tb,
 772                             u32 pid, u32 seq, u16 flags, int dir)
 773{
 774        struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1];
 775        struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1];
 776        int ret = -EINVAL;
 777        int i;
 778        u8 pgid;
 779        u8 up_map;
 780        u8 prio;
 781        u8 tc_pct;
 782
 783        if (!tb[DCB_ATTR_PG_CFG] ||
 784            !netdev->dcbnl_ops->setpgtccfgtx ||
 785            !netdev->dcbnl_ops->setpgtccfgrx ||
 786            !netdev->dcbnl_ops->setpgbwgcfgtx ||
 787            !netdev->dcbnl_ops->setpgbwgcfgrx)
 788                return ret;
 789
 790        ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX,
 791                               tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest);
 792        if (ret)
 793                goto err;
 794
 795        for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) {
 796                if (!pg_tb[i])
 797                        continue;
 798
 799                ret = nla_parse_nested(param_tb, DCB_TC_ATTR_PARAM_MAX,
 800                                       pg_tb[i], dcbnl_tc_param_nest);
 801                if (ret)
 802                        goto err;
 803
 804                pgid = DCB_ATTR_VALUE_UNDEFINED;
 805                prio = DCB_ATTR_VALUE_UNDEFINED;
 806                tc_pct = DCB_ATTR_VALUE_UNDEFINED;
 807                up_map = DCB_ATTR_VALUE_UNDEFINED;
 808
 809                if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO])
 810                        prio =
 811                            nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO]);
 812
 813                if (param_tb[DCB_TC_ATTR_PARAM_PGID])
 814                        pgid = nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_PGID]);
 815
 816                if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT])
 817                        tc_pct = nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_BW_PCT]);
 818
 819                if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING])
 820                        up_map =
 821                             nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING]);
 822
 823                /* dir: Tx = 0, Rx = 1 */
 824                if (dir) {
 825                        /* Rx */
 826                        netdev->dcbnl_ops->setpgtccfgrx(netdev,
 827                                i - DCB_PG_ATTR_TC_0,
 828                                prio, pgid, tc_pct, up_map);
 829                } else {
 830                        /* Tx */
 831                        netdev->dcbnl_ops->setpgtccfgtx(netdev,
 832                                i - DCB_PG_ATTR_TC_0,
 833                                prio, pgid, tc_pct, up_map);
 834                }
 835        }
 836
 837        for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) {
 838                if (!pg_tb[i])
 839                        continue;
 840
 841                tc_pct = nla_get_u8(pg_tb[i]);
 842
 843                /* dir: Tx = 0, Rx = 1 */
 844                if (dir) {
 845                        /* Rx */
 846                        netdev->dcbnl_ops->setpgbwgcfgrx(netdev,
 847                                         i - DCB_PG_ATTR_BW_ID_0, tc_pct);
 848                } else {
 849                        /* Tx */
 850                        netdev->dcbnl_ops->setpgbwgcfgtx(netdev,
 851                                         i - DCB_PG_ATTR_BW_ID_0, tc_pct);
 852                }
 853        }
 854
 855        ret = dcbnl_reply(0, RTM_SETDCB,
 856                          (dir ? DCB_CMD_PGRX_SCFG : DCB_CMD_PGTX_SCFG),
 857                          DCB_ATTR_PG_CFG, pid, seq, flags);
 858
 859err:
 860        return ret;
 861}
 862
 863static int dcbnl_pgtx_setcfg(struct net_device *netdev, struct nlattr **tb,
 864                             u32 pid, u32 seq, u16 flags)
 865{
 866        return __dcbnl_pg_setcfg(netdev, tb, pid, seq, flags, 0);
 867}
 868
 869static int dcbnl_pgrx_setcfg(struct net_device *netdev, struct nlattr **tb,
 870                             u32 pid, u32 seq, u16 flags)
 871{
 872        return __dcbnl_pg_setcfg(netdev, tb, pid, seq, flags, 1);
 873}
 874
 875static int dcbnl_bcn_getcfg(struct net_device *netdev, struct nlattr **tb,
 876                            u32 pid, u32 seq, u16 flags)
 877{
 878        struct sk_buff *dcbnl_skb;
 879        struct nlmsghdr *nlh;
 880        struct dcbmsg *dcb;
 881        struct nlattr *bcn_nest;
 882        struct nlattr *bcn_tb[DCB_BCN_ATTR_MAX + 1];
 883        u8 value_byte;
 884        u32 value_integer;
 885        int ret  = -EINVAL;
 886        bool getall = false;
 887        int i;
 888
 889        if (!tb[DCB_ATTR_BCN] || !netdev->dcbnl_ops->getbcnrp ||
 890            !netdev->dcbnl_ops->getbcncfg)
 891                return ret;
 892
 893        ret = nla_parse_nested(bcn_tb, DCB_BCN_ATTR_MAX,
 894                               tb[DCB_ATTR_BCN], dcbnl_bcn_nest);
 895
 896        if (ret)
 897                goto err_out;
 898
 899        dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
 900        if (!dcbnl_skb)
 901                goto err_out;
 902
 903        nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
 904
 905        dcb = NLMSG_DATA(nlh);
 906        dcb->dcb_family = AF_UNSPEC;
 907        dcb->cmd = DCB_CMD_BCN_GCFG;
 908
 909        bcn_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_BCN);
 910        if (!bcn_nest)
 911                goto err;
 912
 913        if (bcn_tb[DCB_BCN_ATTR_ALL])
 914                getall = true;
 915
 916        for (i = DCB_BCN_ATTR_RP_0; i <= DCB_BCN_ATTR_RP_7; i++) {
 917                if (!getall && !bcn_tb[i])
 918                        continue;
 919
 920                netdev->dcbnl_ops->getbcnrp(netdev, i - DCB_BCN_ATTR_RP_0,
 921                                            &value_byte);
 922                ret = nla_put_u8(dcbnl_skb, i, value_byte);
 923                if (ret)
 924                        goto err_bcn;
 925        }
 926
 927        for (i = DCB_BCN_ATTR_BCNA_0; i <= DCB_BCN_ATTR_RI; i++) {
 928                if (!getall && !bcn_tb[i])
 929                        continue;
 930
 931                netdev->dcbnl_ops->getbcncfg(netdev, i,
 932                                             &value_integer);
 933                ret = nla_put_u32(dcbnl_skb, i, value_integer);
 934                if (ret)
 935                        goto err_bcn;
 936        }
 937
 938        nla_nest_end(dcbnl_skb, bcn_nest);
 939
 940        nlmsg_end(dcbnl_skb, nlh);
 941
 942        ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
 943        if (ret)
 944                goto err;
 945
 946        return 0;
 947
 948err_bcn:
 949        nla_nest_cancel(dcbnl_skb, bcn_nest);
 950nlmsg_failure:
 951err:
 952        kfree_skb(dcbnl_skb);
 953err_out:
 954        ret  = -EINVAL;
 955        return ret;
 956}
 957
 958static int dcbnl_bcn_setcfg(struct net_device *netdev, struct nlattr **tb,
 959                            u32 pid, u32 seq, u16 flags)
 960{
 961        struct nlattr *data[DCB_BCN_ATTR_MAX + 1];
 962        int i;
 963        int ret = -EINVAL;
 964        u8 value_byte;
 965        u32 value_int;
 966
 967        if (!tb[DCB_ATTR_BCN] || !netdev->dcbnl_ops->setbcncfg
 968            || !netdev->dcbnl_ops->setbcnrp)
 969                return ret;
 970
 971        ret = nla_parse_nested(data, DCB_BCN_ATTR_MAX,
 972                               tb[DCB_ATTR_BCN],
 973                               dcbnl_pfc_up_nest);
 974        if (ret)
 975                goto err;
 976
 977        for (i = DCB_BCN_ATTR_RP_0; i <= DCB_BCN_ATTR_RP_7; i++) {
 978                if (data[i] == NULL)
 979                        continue;
 980                value_byte = nla_get_u8(data[i]);
 981                netdev->dcbnl_ops->setbcnrp(netdev,
 982                        data[i]->nla_type - DCB_BCN_ATTR_RP_0, value_byte);
 983        }
 984
 985        for (i = DCB_BCN_ATTR_BCNA_0; i <= DCB_BCN_ATTR_RI; i++) {
 986                if (data[i] == NULL)
 987                        continue;
 988                value_int = nla_get_u32(data[i]);
 989                netdev->dcbnl_ops->setbcncfg(netdev,
 990                                             i, value_int);
 991        }
 992
 993        ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_BCN_SCFG, DCB_ATTR_BCN,
 994                          pid, seq, flags);
 995err:
 996        return ret;
 997}
 998
 999static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
1000{
1001        struct net *net = sock_net(skb->sk);
1002        struct net_device *netdev;
1003        struct dcbmsg  *dcb = (struct dcbmsg *)NLMSG_DATA(nlh);
1004        struct nlattr *tb[DCB_ATTR_MAX + 1];
1005        u32 pid = skb ? NETLINK_CB(skb).pid : 0;
1006        int ret = -EINVAL;
1007
1008        if (net != &init_net)
1009                return -EINVAL;
1010
1011        ret = nlmsg_parse(nlh, sizeof(*dcb), tb, DCB_ATTR_MAX,
1012                          dcbnl_rtnl_policy);
1013        if (ret < 0)
1014                return ret;
1015
1016        if (!tb[DCB_ATTR_IFNAME])
1017                return -EINVAL;
1018
1019        netdev = dev_get_by_name(&init_net, nla_data(tb[DCB_ATTR_IFNAME]));
1020        if (!netdev)
1021                return -EINVAL;
1022
1023        if (!netdev->dcbnl_ops)
1024                goto errout;
1025
1026        switch (dcb->cmd) {
1027        case DCB_CMD_GSTATE:
1028                ret = dcbnl_getstate(netdev, tb, pid, nlh->nlmsg_seq,
1029                                     nlh->nlmsg_flags);
1030                goto out;
1031        case DCB_CMD_PFC_GCFG:
1032                ret = dcbnl_getpfccfg(netdev, tb, pid, nlh->nlmsg_seq,
1033                                      nlh->nlmsg_flags);
1034                goto out;
1035        case DCB_CMD_GPERM_HWADDR:
1036                ret = dcbnl_getperm_hwaddr(netdev, tb, pid, nlh->nlmsg_seq,
1037                                           nlh->nlmsg_flags);
1038                goto out;
1039        case DCB_CMD_PGTX_GCFG:
1040                ret = dcbnl_pgtx_getcfg(netdev, tb, pid, nlh->nlmsg_seq,
1041                                        nlh->nlmsg_flags);
1042                goto out;
1043        case DCB_CMD_PGRX_GCFG:
1044                ret = dcbnl_pgrx_getcfg(netdev, tb, pid, nlh->nlmsg_seq,
1045                                        nlh->nlmsg_flags);
1046                goto out;
1047        case DCB_CMD_BCN_GCFG:
1048                ret = dcbnl_bcn_getcfg(netdev, tb, pid, nlh->nlmsg_seq,
1049                                       nlh->nlmsg_flags);
1050                goto out;
1051        case DCB_CMD_SSTATE:
1052                ret = dcbnl_setstate(netdev, tb, pid, nlh->nlmsg_seq,
1053                                     nlh->nlmsg_flags);
1054                goto out;
1055        case DCB_CMD_PFC_SCFG:
1056                ret = dcbnl_setpfccfg(netdev, tb, pid, nlh->nlmsg_seq,
1057                                      nlh->nlmsg_flags);
1058                goto out;
1059
1060        case DCB_CMD_SET_ALL:
1061                ret = dcbnl_setall(netdev, tb, pid, nlh->nlmsg_seq,
1062                                   nlh->nlmsg_flags);
1063                goto out;
1064        case DCB_CMD_PGTX_SCFG:
1065                ret = dcbnl_pgtx_setcfg(netdev, tb, pid, nlh->nlmsg_seq,
1066                                        nlh->nlmsg_flags);
1067                goto out;
1068        case DCB_CMD_PGRX_SCFG:
1069                ret = dcbnl_pgrx_setcfg(netdev, tb, pid, nlh->nlmsg_seq,
1070                                        nlh->nlmsg_flags);
1071                goto out;
1072        case DCB_CMD_GCAP:
1073                ret = dcbnl_getcap(netdev, tb, pid, nlh->nlmsg_seq,
1074                                   nlh->nlmsg_flags);
1075                goto out;
1076        case DCB_CMD_GNUMTCS:
1077                ret = dcbnl_getnumtcs(netdev, tb, pid, nlh->nlmsg_seq,
1078                                      nlh->nlmsg_flags);
1079                goto out;
1080        case DCB_CMD_SNUMTCS:
1081                ret = dcbnl_setnumtcs(netdev, tb, pid, nlh->nlmsg_seq,
1082                                      nlh->nlmsg_flags);
1083                goto out;
1084        case DCB_CMD_PFC_GSTATE:
1085                ret = dcbnl_getpfcstate(netdev, tb, pid, nlh->nlmsg_seq,
1086                                        nlh->nlmsg_flags);
1087                goto out;
1088        case DCB_CMD_PFC_SSTATE:
1089                ret = dcbnl_setpfcstate(netdev, tb, pid, nlh->nlmsg_seq,
1090                                        nlh->nlmsg_flags);
1091                goto out;
1092        case DCB_CMD_BCN_SCFG:
1093                ret = dcbnl_bcn_setcfg(netdev, tb, pid, nlh->nlmsg_seq,
1094                                       nlh->nlmsg_flags);
1095                goto out;
1096        default:
1097                goto errout;
1098        }
1099errout:
1100        ret = -EINVAL;
1101out:
1102        dev_put(netdev);
1103        return ret;
1104}
1105
1106static int __init dcbnl_init(void)
1107{
1108        rtnl_register(PF_UNSPEC, RTM_GETDCB, dcb_doit, NULL);
1109        rtnl_register(PF_UNSPEC, RTM_SETDCB, dcb_doit, NULL);
1110
1111        return 0;
1112}
1113module_init(dcbnl_init);
1114
1115static void __exit dcbnl_exit(void)
1116{
1117        rtnl_unregister(PF_UNSPEC, RTM_GETDCB);
1118        rtnl_unregister(PF_UNSPEC, RTM_SETDCB);
1119}
1120module_exit(dcbnl_exit);
1121
1122
1123