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        [DCB_ATTR_APP]         = {.type = NLA_NESTED},
  68};
  69
  70/* DCB priority flow control to User Priority nested attributes */
  71static struct nla_policy dcbnl_pfc_up_nest[DCB_PFC_UP_ATTR_MAX + 1] = {
  72        [DCB_PFC_UP_ATTR_0]   = {.type = NLA_U8},
  73        [DCB_PFC_UP_ATTR_1]   = {.type = NLA_U8},
  74        [DCB_PFC_UP_ATTR_2]   = {.type = NLA_U8},
  75        [DCB_PFC_UP_ATTR_3]   = {.type = NLA_U8},
  76        [DCB_PFC_UP_ATTR_4]   = {.type = NLA_U8},
  77        [DCB_PFC_UP_ATTR_5]   = {.type = NLA_U8},
  78        [DCB_PFC_UP_ATTR_6]   = {.type = NLA_U8},
  79        [DCB_PFC_UP_ATTR_7]   = {.type = NLA_U8},
  80        [DCB_PFC_UP_ATTR_ALL] = {.type = NLA_FLAG},
  81};
  82
  83/* DCB priority grouping nested attributes */
  84static struct nla_policy dcbnl_pg_nest[DCB_PG_ATTR_MAX + 1] = {
  85        [DCB_PG_ATTR_TC_0]      = {.type = NLA_NESTED},
  86        [DCB_PG_ATTR_TC_1]      = {.type = NLA_NESTED},
  87        [DCB_PG_ATTR_TC_2]      = {.type = NLA_NESTED},
  88        [DCB_PG_ATTR_TC_3]      = {.type = NLA_NESTED},
  89        [DCB_PG_ATTR_TC_4]      = {.type = NLA_NESTED},
  90        [DCB_PG_ATTR_TC_5]      = {.type = NLA_NESTED},
  91        [DCB_PG_ATTR_TC_6]      = {.type = NLA_NESTED},
  92        [DCB_PG_ATTR_TC_7]      = {.type = NLA_NESTED},
  93        [DCB_PG_ATTR_TC_ALL]    = {.type = NLA_NESTED},
  94        [DCB_PG_ATTR_BW_ID_0]   = {.type = NLA_U8},
  95        [DCB_PG_ATTR_BW_ID_1]   = {.type = NLA_U8},
  96        [DCB_PG_ATTR_BW_ID_2]   = {.type = NLA_U8},
  97        [DCB_PG_ATTR_BW_ID_3]   = {.type = NLA_U8},
  98        [DCB_PG_ATTR_BW_ID_4]   = {.type = NLA_U8},
  99        [DCB_PG_ATTR_BW_ID_5]   = {.type = NLA_U8},
 100        [DCB_PG_ATTR_BW_ID_6]   = {.type = NLA_U8},
 101        [DCB_PG_ATTR_BW_ID_7]   = {.type = NLA_U8},
 102        [DCB_PG_ATTR_BW_ID_ALL] = {.type = NLA_FLAG},
 103};
 104
 105/* DCB traffic class nested attributes. */
 106static struct nla_policy dcbnl_tc_param_nest[DCB_TC_ATTR_PARAM_MAX + 1] = {
 107        [DCB_TC_ATTR_PARAM_PGID]            = {.type = NLA_U8},
 108        [DCB_TC_ATTR_PARAM_UP_MAPPING]      = {.type = NLA_U8},
 109        [DCB_TC_ATTR_PARAM_STRICT_PRIO]     = {.type = NLA_U8},
 110        [DCB_TC_ATTR_PARAM_BW_PCT]          = {.type = NLA_U8},
 111        [DCB_TC_ATTR_PARAM_ALL]             = {.type = NLA_FLAG},
 112};
 113
 114/* DCB capabilities nested attributes. */
 115static struct nla_policy dcbnl_cap_nest[DCB_CAP_ATTR_MAX + 1] = {
 116        [DCB_CAP_ATTR_ALL]     = {.type = NLA_FLAG},
 117        [DCB_CAP_ATTR_PG]      = {.type = NLA_U8},
 118        [DCB_CAP_ATTR_PFC]     = {.type = NLA_U8},
 119        [DCB_CAP_ATTR_UP2TC]   = {.type = NLA_U8},
 120        [DCB_CAP_ATTR_PG_TCS]  = {.type = NLA_U8},
 121        [DCB_CAP_ATTR_PFC_TCS] = {.type = NLA_U8},
 122        [DCB_CAP_ATTR_GSP]     = {.type = NLA_U8},
 123        [DCB_CAP_ATTR_BCN]     = {.type = NLA_U8},
 124};
 125
 126/* DCB capabilities nested attributes. */
 127static struct nla_policy dcbnl_numtcs_nest[DCB_NUMTCS_ATTR_MAX + 1] = {
 128        [DCB_NUMTCS_ATTR_ALL]     = {.type = NLA_FLAG},
 129        [DCB_NUMTCS_ATTR_PG]      = {.type = NLA_U8},
 130        [DCB_NUMTCS_ATTR_PFC]     = {.type = NLA_U8},
 131};
 132
 133/* DCB BCN nested attributes. */
 134static struct nla_policy dcbnl_bcn_nest[DCB_BCN_ATTR_MAX + 1] = {
 135        [DCB_BCN_ATTR_RP_0]         = {.type = NLA_U8},
 136        [DCB_BCN_ATTR_RP_1]         = {.type = NLA_U8},
 137        [DCB_BCN_ATTR_RP_2]         = {.type = NLA_U8},
 138        [DCB_BCN_ATTR_RP_3]         = {.type = NLA_U8},
 139        [DCB_BCN_ATTR_RP_4]         = {.type = NLA_U8},
 140        [DCB_BCN_ATTR_RP_5]         = {.type = NLA_U8},
 141        [DCB_BCN_ATTR_RP_6]         = {.type = NLA_U8},
 142        [DCB_BCN_ATTR_RP_7]         = {.type = NLA_U8},
 143        [DCB_BCN_ATTR_RP_ALL]       = {.type = NLA_FLAG},
 144        [DCB_BCN_ATTR_BCNA_0]       = {.type = NLA_U32},
 145        [DCB_BCN_ATTR_BCNA_1]       = {.type = NLA_U32},
 146        [DCB_BCN_ATTR_ALPHA]        = {.type = NLA_U32},
 147        [DCB_BCN_ATTR_BETA]         = {.type = NLA_U32},
 148        [DCB_BCN_ATTR_GD]           = {.type = NLA_U32},
 149        [DCB_BCN_ATTR_GI]           = {.type = NLA_U32},
 150        [DCB_BCN_ATTR_TMAX]         = {.type = NLA_U32},
 151        [DCB_BCN_ATTR_TD]           = {.type = NLA_U32},
 152        [DCB_BCN_ATTR_RMIN]         = {.type = NLA_U32},
 153        [DCB_BCN_ATTR_W]            = {.type = NLA_U32},
 154        [DCB_BCN_ATTR_RD]           = {.type = NLA_U32},
 155        [DCB_BCN_ATTR_RU]           = {.type = NLA_U32},
 156        [DCB_BCN_ATTR_WRTT]         = {.type = NLA_U32},
 157        [DCB_BCN_ATTR_RI]           = {.type = NLA_U32},
 158        [DCB_BCN_ATTR_C]            = {.type = NLA_U32},
 159        [DCB_BCN_ATTR_ALL]          = {.type = NLA_FLAG},
 160};
 161
 162/* DCB APP nested attributes. */
 163static struct nla_policy dcbnl_app_nest[DCB_APP_ATTR_MAX + 1] = {
 164        [DCB_APP_ATTR_IDTYPE]       = {.type = NLA_U8},
 165        [DCB_APP_ATTR_ID]           = {.type = NLA_U16},
 166        [DCB_APP_ATTR_PRIORITY]     = {.type = NLA_U8},
 167};
 168
 169/* standard netlink reply call */
 170static int dcbnl_reply(u8 value, u8 event, u8 cmd, u8 attr, u32 pid,
 171                       u32 seq, u16 flags)
 172{
 173        struct sk_buff *dcbnl_skb;
 174        struct dcbmsg *dcb;
 175        struct nlmsghdr *nlh;
 176        int ret = -EINVAL;
 177
 178        dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
 179        if (!dcbnl_skb)
 180                return ret;
 181
 182        nlh = NLMSG_NEW(dcbnl_skb, pid, seq, event, sizeof(*dcb), flags);
 183
 184        dcb = NLMSG_DATA(nlh);
 185        dcb->dcb_family = AF_UNSPEC;
 186        dcb->cmd = cmd;
 187        dcb->dcb_pad = 0;
 188
 189        ret = nla_put_u8(dcbnl_skb, attr, value);
 190        if (ret)
 191                goto err;
 192
 193        /* end the message, assign the nlmsg_len. */
 194        nlmsg_end(dcbnl_skb, nlh);
 195        ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
 196        if (ret)
 197                return -EINVAL;
 198
 199        return 0;
 200nlmsg_failure:
 201err:
 202        kfree_skb(dcbnl_skb);
 203        return ret;
 204}
 205
 206static int dcbnl_getstate(struct net_device *netdev, struct nlattr **tb,
 207                          u32 pid, u32 seq, u16 flags)
 208{
 209        int ret = -EINVAL;
 210
 211        /* if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->getstate) */
 212        if (!netdev->dcbnl_ops->getstate)
 213                return ret;
 214
 215        ret = dcbnl_reply(netdev->dcbnl_ops->getstate(netdev), RTM_GETDCB,
 216                          DCB_CMD_GSTATE, DCB_ATTR_STATE, pid, seq, flags);
 217
 218        return ret;
 219}
 220
 221static int dcbnl_getpfccfg(struct net_device *netdev, struct nlattr **tb,
 222                           u32 pid, u32 seq, u16 flags)
 223{
 224        struct sk_buff *dcbnl_skb;
 225        struct nlmsghdr *nlh;
 226        struct dcbmsg *dcb;
 227        struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1], *nest;
 228        u8 value;
 229        int ret = -EINVAL;
 230        int i;
 231        int getall = 0;
 232
 233        if (!tb[DCB_ATTR_PFC_CFG] || !netdev->dcbnl_ops->getpfccfg)
 234                return ret;
 235
 236        ret = nla_parse_nested(data, DCB_PFC_UP_ATTR_MAX,
 237                               tb[DCB_ATTR_PFC_CFG],
 238                               dcbnl_pfc_up_nest);
 239        if (ret)
 240                goto err_out;
 241
 242        dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
 243        if (!dcbnl_skb)
 244                goto err_out;
 245
 246        nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
 247
 248        dcb = NLMSG_DATA(nlh);
 249        dcb->dcb_family = AF_UNSPEC;
 250        dcb->cmd = DCB_CMD_PFC_GCFG;
 251
 252        nest = nla_nest_start(dcbnl_skb, DCB_ATTR_PFC_CFG);
 253        if (!nest)
 254                goto err;
 255
 256        if (data[DCB_PFC_UP_ATTR_ALL])
 257                getall = 1;
 258
 259        for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) {
 260                if (!getall && !data[i])
 261                        continue;
 262
 263                netdev->dcbnl_ops->getpfccfg(netdev, i - DCB_PFC_UP_ATTR_0,
 264                                             &value);
 265                ret = nla_put_u8(dcbnl_skb, i, value);
 266
 267                if (ret) {
 268                        nla_nest_cancel(dcbnl_skb, nest);
 269                        goto err;
 270                }
 271        }
 272        nla_nest_end(dcbnl_skb, nest);
 273
 274        nlmsg_end(dcbnl_skb, nlh);
 275
 276        ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
 277        if (ret)
 278                goto err_out;
 279
 280        return 0;
 281nlmsg_failure:
 282err:
 283        kfree_skb(dcbnl_skb);
 284err_out:
 285        return -EINVAL;
 286}
 287
 288static int dcbnl_getperm_hwaddr(struct net_device *netdev, struct nlattr **tb,
 289                                u32 pid, u32 seq, u16 flags)
 290{
 291        struct sk_buff *dcbnl_skb;
 292        struct nlmsghdr *nlh;
 293        struct dcbmsg *dcb;
 294        u8 perm_addr[MAX_ADDR_LEN];
 295        int ret = -EINVAL;
 296
 297        if (!netdev->dcbnl_ops->getpermhwaddr)
 298                return ret;
 299
 300        dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
 301        if (!dcbnl_skb)
 302                goto err_out;
 303
 304        nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
 305
 306        dcb = NLMSG_DATA(nlh);
 307        dcb->dcb_family = AF_UNSPEC;
 308        dcb->cmd = DCB_CMD_GPERM_HWADDR;
 309
 310        netdev->dcbnl_ops->getpermhwaddr(netdev, perm_addr);
 311
 312        ret = nla_put(dcbnl_skb, DCB_ATTR_PERM_HWADDR, sizeof(perm_addr),
 313                      perm_addr);
 314
 315        nlmsg_end(dcbnl_skb, nlh);
 316
 317        ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
 318        if (ret)
 319                goto err_out;
 320
 321        return 0;
 322
 323nlmsg_failure:
 324        kfree_skb(dcbnl_skb);
 325err_out:
 326        return -EINVAL;
 327}
 328
 329static int dcbnl_getcap(struct net_device *netdev, struct nlattr **tb,
 330                        u32 pid, u32 seq, u16 flags)
 331{
 332        struct sk_buff *dcbnl_skb;
 333        struct nlmsghdr *nlh;
 334        struct dcbmsg *dcb;
 335        struct nlattr *data[DCB_CAP_ATTR_MAX + 1], *nest;
 336        u8 value;
 337        int ret = -EINVAL;
 338        int i;
 339        int getall = 0;
 340
 341        if (!tb[DCB_ATTR_CAP] || !netdev->dcbnl_ops->getcap)
 342                return ret;
 343
 344        ret = nla_parse_nested(data, DCB_CAP_ATTR_MAX, tb[DCB_ATTR_CAP],
 345                               dcbnl_cap_nest);
 346        if (ret)
 347                goto err_out;
 348
 349        dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
 350        if (!dcbnl_skb)
 351                goto err_out;
 352
 353        nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
 354
 355        dcb = NLMSG_DATA(nlh);
 356        dcb->dcb_family = AF_UNSPEC;
 357        dcb->cmd = DCB_CMD_GCAP;
 358
 359        nest = nla_nest_start(dcbnl_skb, DCB_ATTR_CAP);
 360        if (!nest)
 361                goto err;
 362
 363        if (data[DCB_CAP_ATTR_ALL])
 364                getall = 1;
 365
 366        for (i = DCB_CAP_ATTR_ALL+1; i <= DCB_CAP_ATTR_MAX; i++) {
 367                if (!getall && !data[i])
 368                        continue;
 369
 370                if (!netdev->dcbnl_ops->getcap(netdev, i, &value)) {
 371                        ret = nla_put_u8(dcbnl_skb, i, value);
 372
 373                        if (ret) {
 374                                nla_nest_cancel(dcbnl_skb, nest);
 375                                goto err;
 376                        }
 377                }
 378        }
 379        nla_nest_end(dcbnl_skb, nest);
 380
 381        nlmsg_end(dcbnl_skb, nlh);
 382
 383        ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
 384        if (ret)
 385                goto err_out;
 386
 387        return 0;
 388nlmsg_failure:
 389err:
 390        kfree_skb(dcbnl_skb);
 391err_out:
 392        return -EINVAL;
 393}
 394
 395static int dcbnl_getnumtcs(struct net_device *netdev, struct nlattr **tb,
 396                           u32 pid, u32 seq, u16 flags)
 397{
 398        struct sk_buff *dcbnl_skb;
 399        struct nlmsghdr *nlh;
 400        struct dcbmsg *dcb;
 401        struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1], *nest;
 402        u8 value;
 403        int ret = -EINVAL;
 404        int i;
 405        int getall = 0;
 406
 407        if (!tb[DCB_ATTR_NUMTCS] || !netdev->dcbnl_ops->getnumtcs)
 408                return ret;
 409
 410        ret = nla_parse_nested(data, DCB_NUMTCS_ATTR_MAX, tb[DCB_ATTR_NUMTCS],
 411                               dcbnl_numtcs_nest);
 412        if (ret) {
 413                ret = -EINVAL;
 414                goto err_out;
 415        }
 416
 417        dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
 418        if (!dcbnl_skb) {
 419                ret = -EINVAL;
 420                goto err_out;
 421        }
 422
 423        nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
 424
 425        dcb = NLMSG_DATA(nlh);
 426        dcb->dcb_family = AF_UNSPEC;
 427        dcb->cmd = DCB_CMD_GNUMTCS;
 428
 429        nest = nla_nest_start(dcbnl_skb, DCB_ATTR_NUMTCS);
 430        if (!nest) {
 431                ret = -EINVAL;
 432                goto err;
 433        }
 434
 435        if (data[DCB_NUMTCS_ATTR_ALL])
 436                getall = 1;
 437
 438        for (i = DCB_NUMTCS_ATTR_ALL+1; i <= DCB_NUMTCS_ATTR_MAX; i++) {
 439                if (!getall && !data[i])
 440                        continue;
 441
 442                ret = netdev->dcbnl_ops->getnumtcs(netdev, i, &value);
 443                if (!ret) {
 444                        ret = nla_put_u8(dcbnl_skb, i, value);
 445
 446                        if (ret) {
 447                                nla_nest_cancel(dcbnl_skb, nest);
 448                                ret = -EINVAL;
 449                                goto err;
 450                        }
 451                } else {
 452                        goto err;
 453                }
 454        }
 455        nla_nest_end(dcbnl_skb, nest);
 456
 457        nlmsg_end(dcbnl_skb, nlh);
 458
 459        ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
 460        if (ret) {
 461                ret = -EINVAL;
 462                goto err_out;
 463        }
 464
 465        return 0;
 466nlmsg_failure:
 467err:
 468        kfree_skb(dcbnl_skb);
 469err_out:
 470        return ret;
 471}
 472
 473static int dcbnl_setnumtcs(struct net_device *netdev, struct nlattr **tb,
 474                           u32 pid, u32 seq, u16 flags)
 475{
 476        struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1];
 477        int ret = -EINVAL;
 478        u8 value;
 479        int i;
 480
 481        if (!tb[DCB_ATTR_NUMTCS] || !netdev->dcbnl_ops->setnumtcs)
 482                return ret;
 483
 484        ret = nla_parse_nested(data, DCB_NUMTCS_ATTR_MAX, tb[DCB_ATTR_NUMTCS],
 485                               dcbnl_numtcs_nest);
 486
 487        if (ret) {
 488                ret = -EINVAL;
 489                goto err;
 490        }
 491
 492        for (i = DCB_NUMTCS_ATTR_ALL+1; i <= DCB_NUMTCS_ATTR_MAX; i++) {
 493                if (data[i] == NULL)
 494                        continue;
 495
 496                value = nla_get_u8(data[i]);
 497
 498                ret = netdev->dcbnl_ops->setnumtcs(netdev, i, value);
 499
 500                if (ret)
 501                        goto operr;
 502        }
 503
 504operr:
 505        ret = dcbnl_reply(!!ret, RTM_SETDCB, DCB_CMD_SNUMTCS,
 506                          DCB_ATTR_NUMTCS, pid, seq, flags);
 507
 508err:
 509        return ret;
 510}
 511
 512static int dcbnl_getpfcstate(struct net_device *netdev, struct nlattr **tb,
 513                             u32 pid, u32 seq, u16 flags)
 514{
 515        int ret = -EINVAL;
 516
 517        if (!netdev->dcbnl_ops->getpfcstate)
 518                return ret;
 519
 520        ret = dcbnl_reply(netdev->dcbnl_ops->getpfcstate(netdev), RTM_GETDCB,
 521                          DCB_CMD_PFC_GSTATE, DCB_ATTR_PFC_STATE,
 522                          pid, seq, flags);
 523
 524        return ret;
 525}
 526
 527static int dcbnl_setpfcstate(struct net_device *netdev, struct nlattr **tb,
 528                             u32 pid, u32 seq, u16 flags)
 529{
 530        int ret = -EINVAL;
 531        u8 value;
 532
 533        if (!tb[DCB_ATTR_PFC_STATE] || !netdev->dcbnl_ops->setpfcstate)
 534                return ret;
 535
 536        value = nla_get_u8(tb[DCB_ATTR_PFC_STATE]);
 537
 538        netdev->dcbnl_ops->setpfcstate(netdev, value);
 539
 540        ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_PFC_SSTATE, DCB_ATTR_PFC_STATE,
 541                          pid, seq, flags);
 542
 543        return ret;
 544}
 545
 546static int dcbnl_getapp(struct net_device *netdev, struct nlattr **tb,
 547                        u32 pid, u32 seq, u16 flags)
 548{
 549        struct sk_buff *dcbnl_skb;
 550        struct nlmsghdr *nlh;
 551        struct dcbmsg *dcb;
 552        struct nlattr *app_nest;
 553        struct nlattr *app_tb[DCB_APP_ATTR_MAX + 1];
 554        u16 id;
 555        u8 up, idtype;
 556        int ret = -EINVAL;
 557
 558        if (!tb[DCB_ATTR_APP] || !netdev->dcbnl_ops->getapp)
 559                goto out;
 560
 561        ret = nla_parse_nested(app_tb, DCB_APP_ATTR_MAX, tb[DCB_ATTR_APP],
 562                               dcbnl_app_nest);
 563        if (ret)
 564                goto out;
 565
 566        ret = -EINVAL;
 567        /* all must be non-null */
 568        if ((!app_tb[DCB_APP_ATTR_IDTYPE]) ||
 569            (!app_tb[DCB_APP_ATTR_ID]))
 570                goto out;
 571
 572        /* either by eth type or by socket number */
 573        idtype = nla_get_u8(app_tb[DCB_APP_ATTR_IDTYPE]);
 574        if ((idtype != DCB_APP_IDTYPE_ETHTYPE) &&
 575            (idtype != DCB_APP_IDTYPE_PORTNUM))
 576                goto out;
 577
 578        id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]);
 579        up = netdev->dcbnl_ops->getapp(netdev, idtype, id);
 580
 581        /* send this back */
 582        dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
 583        if (!dcbnl_skb)
 584                goto out;
 585
 586        nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
 587        dcb = NLMSG_DATA(nlh);
 588        dcb->dcb_family = AF_UNSPEC;
 589        dcb->cmd = DCB_CMD_GAPP;
 590
 591        app_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_APP);
 592        ret = nla_put_u8(dcbnl_skb, DCB_APP_ATTR_IDTYPE, idtype);
 593        if (ret)
 594                goto out_cancel;
 595
 596        ret = nla_put_u16(dcbnl_skb, DCB_APP_ATTR_ID, id);
 597        if (ret)
 598                goto out_cancel;
 599
 600        ret = nla_put_u8(dcbnl_skb, DCB_APP_ATTR_PRIORITY, up);
 601        if (ret)
 602                goto out_cancel;
 603
 604        nla_nest_end(dcbnl_skb, app_nest);
 605        nlmsg_end(dcbnl_skb, nlh);
 606
 607        ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
 608        if (ret)
 609                goto nlmsg_failure;
 610
 611        goto out;
 612
 613out_cancel:
 614        nla_nest_cancel(dcbnl_skb, app_nest);
 615nlmsg_failure:
 616        kfree_skb(dcbnl_skb);
 617out:
 618        return ret;
 619}
 620
 621static int dcbnl_setapp(struct net_device *netdev, struct nlattr **tb,
 622                        u32 pid, u32 seq, u16 flags)
 623{
 624        int ret = -EINVAL;
 625        u16 id;
 626        u8 up, idtype;
 627        struct nlattr *app_tb[DCB_APP_ATTR_MAX + 1];
 628
 629        if (!tb[DCB_ATTR_APP] || !netdev->dcbnl_ops->setapp)
 630                goto out;
 631
 632        ret = nla_parse_nested(app_tb, DCB_APP_ATTR_MAX, tb[DCB_ATTR_APP],
 633                               dcbnl_app_nest);
 634        if (ret)
 635                goto out;
 636
 637        ret = -EINVAL;
 638        /* all must be non-null */
 639        if ((!app_tb[DCB_APP_ATTR_IDTYPE]) ||
 640            (!app_tb[DCB_APP_ATTR_ID]) ||
 641            (!app_tb[DCB_APP_ATTR_PRIORITY]))
 642                goto out;
 643
 644        /* either by eth type or by socket number */
 645        idtype = nla_get_u8(app_tb[DCB_APP_ATTR_IDTYPE]);
 646        if ((idtype != DCB_APP_IDTYPE_ETHTYPE) &&
 647            (idtype != DCB_APP_IDTYPE_PORTNUM))
 648                goto out;
 649
 650        id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]);
 651        up = nla_get_u8(app_tb[DCB_APP_ATTR_PRIORITY]);
 652
 653        ret = dcbnl_reply(netdev->dcbnl_ops->setapp(netdev, idtype, id, up),
 654                          RTM_SETDCB, DCB_CMD_SAPP, DCB_ATTR_APP,
 655                          pid, seq, flags);
 656out:
 657        return ret;
 658}
 659
 660static int __dcbnl_pg_getcfg(struct net_device *netdev, struct nlattr **tb,
 661                             u32 pid, u32 seq, u16 flags, int dir)
 662{
 663        struct sk_buff *dcbnl_skb;
 664        struct nlmsghdr *nlh;
 665        struct dcbmsg *dcb;
 666        struct nlattr *pg_nest, *param_nest, *data;
 667        struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1];
 668        struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1];
 669        u8 prio, pgid, tc_pct, up_map;
 670        int ret  = -EINVAL;
 671        int getall = 0;
 672        int i;
 673
 674        if (!tb[DCB_ATTR_PG_CFG] ||
 675            !netdev->dcbnl_ops->getpgtccfgtx ||
 676            !netdev->dcbnl_ops->getpgtccfgrx ||
 677            !netdev->dcbnl_ops->getpgbwgcfgtx ||
 678            !netdev->dcbnl_ops->getpgbwgcfgrx)
 679                return ret;
 680
 681        ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX,
 682                               tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest);
 683
 684        if (ret)
 685                goto err_out;
 686
 687        dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
 688        if (!dcbnl_skb)
 689                goto err_out;
 690
 691        nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
 692
 693        dcb = NLMSG_DATA(nlh);
 694        dcb->dcb_family = AF_UNSPEC;
 695        dcb->cmd = (dir) ? DCB_CMD_PGRX_GCFG : DCB_CMD_PGTX_GCFG;
 696
 697        pg_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_PG_CFG);
 698        if (!pg_nest)
 699                goto err;
 700
 701        if (pg_tb[DCB_PG_ATTR_TC_ALL])
 702                getall = 1;
 703
 704        for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) {
 705                if (!getall && !pg_tb[i])
 706                        continue;
 707
 708                if (pg_tb[DCB_PG_ATTR_TC_ALL])
 709                        data = pg_tb[DCB_PG_ATTR_TC_ALL];
 710                else
 711                        data = pg_tb[i];
 712                ret = nla_parse_nested(param_tb, DCB_TC_ATTR_PARAM_MAX,
 713                                       data, dcbnl_tc_param_nest);
 714                if (ret)
 715                        goto err_pg;
 716
 717                param_nest = nla_nest_start(dcbnl_skb, i);
 718                if (!param_nest)
 719                        goto err_pg;
 720
 721                pgid = DCB_ATTR_VALUE_UNDEFINED;
 722                prio = DCB_ATTR_VALUE_UNDEFINED;
 723                tc_pct = DCB_ATTR_VALUE_UNDEFINED;
 724                up_map = DCB_ATTR_VALUE_UNDEFINED;
 725
 726                if (dir) {
 727                        /* Rx */
 728                        netdev->dcbnl_ops->getpgtccfgrx(netdev,
 729                                                i - DCB_PG_ATTR_TC_0, &prio,
 730                                                &pgid, &tc_pct, &up_map);
 731                } else {
 732                        /* Tx */
 733                        netdev->dcbnl_ops->getpgtccfgtx(netdev,
 734                                                i - DCB_PG_ATTR_TC_0, &prio,
 735                                                &pgid, &tc_pct, &up_map);
 736                }
 737
 738                if (param_tb[DCB_TC_ATTR_PARAM_PGID] ||
 739                    param_tb[DCB_TC_ATTR_PARAM_ALL]) {
 740                        ret = nla_put_u8(dcbnl_skb,
 741                                         DCB_TC_ATTR_PARAM_PGID, pgid);
 742                        if (ret)
 743                                goto err_param;
 744                }
 745                if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING] ||
 746                    param_tb[DCB_TC_ATTR_PARAM_ALL]) {
 747                        ret = nla_put_u8(dcbnl_skb,
 748                                         DCB_TC_ATTR_PARAM_UP_MAPPING, up_map);
 749                        if (ret)
 750                                goto err_param;
 751                }
 752                if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO] ||
 753                    param_tb[DCB_TC_ATTR_PARAM_ALL]) {
 754                        ret = nla_put_u8(dcbnl_skb,
 755                                         DCB_TC_ATTR_PARAM_STRICT_PRIO, prio);
 756                        if (ret)
 757                                goto err_param;
 758                }
 759                if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT] ||
 760                    param_tb[DCB_TC_ATTR_PARAM_ALL]) {
 761                        ret = nla_put_u8(dcbnl_skb, DCB_TC_ATTR_PARAM_BW_PCT,
 762                                         tc_pct);
 763                        if (ret)
 764                                goto err_param;
 765                }
 766                nla_nest_end(dcbnl_skb, param_nest);
 767        }
 768
 769        if (pg_tb[DCB_PG_ATTR_BW_ID_ALL])
 770                getall = 1;
 771        else
 772                getall = 0;
 773
 774        for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) {
 775                if (!getall && !pg_tb[i])
 776                        continue;
 777
 778                tc_pct = DCB_ATTR_VALUE_UNDEFINED;
 779
 780                if (dir) {
 781                        /* Rx */
 782                        netdev->dcbnl_ops->getpgbwgcfgrx(netdev,
 783                                        i - DCB_PG_ATTR_BW_ID_0, &tc_pct);
 784                } else {
 785                        /* Tx */
 786                        netdev->dcbnl_ops->getpgbwgcfgtx(netdev,
 787                                        i - DCB_PG_ATTR_BW_ID_0, &tc_pct);
 788                }
 789                ret = nla_put_u8(dcbnl_skb, i, tc_pct);
 790
 791                if (ret)
 792                        goto err_pg;
 793        }
 794
 795        nla_nest_end(dcbnl_skb, pg_nest);
 796
 797        nlmsg_end(dcbnl_skb, nlh);
 798
 799        ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
 800        if (ret)
 801                goto err_out;
 802
 803        return 0;
 804
 805err_param:
 806        nla_nest_cancel(dcbnl_skb, param_nest);
 807err_pg:
 808        nla_nest_cancel(dcbnl_skb, pg_nest);
 809nlmsg_failure:
 810err:
 811        kfree_skb(dcbnl_skb);
 812err_out:
 813        ret  = -EINVAL;
 814        return ret;
 815}
 816
 817static int dcbnl_pgtx_getcfg(struct net_device *netdev, struct nlattr **tb,
 818                             u32 pid, u32 seq, u16 flags)
 819{
 820        return __dcbnl_pg_getcfg(netdev, tb, pid, seq, flags, 0);
 821}
 822
 823static int dcbnl_pgrx_getcfg(struct net_device *netdev, struct nlattr **tb,
 824                             u32 pid, u32 seq, u16 flags)
 825{
 826        return __dcbnl_pg_getcfg(netdev, tb, pid, seq, flags, 1);
 827}
 828
 829static int dcbnl_setstate(struct net_device *netdev, struct nlattr **tb,
 830                          u32 pid, u32 seq, u16 flags)
 831{
 832        int ret = -EINVAL;
 833        u8 value;
 834
 835        if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->setstate)
 836                return ret;
 837
 838        value = nla_get_u8(tb[DCB_ATTR_STATE]);
 839
 840        ret = dcbnl_reply(netdev->dcbnl_ops->setstate(netdev, value),
 841                          RTM_SETDCB, DCB_CMD_SSTATE, DCB_ATTR_STATE,
 842                          pid, seq, flags);
 843
 844        return ret;
 845}
 846
 847static int dcbnl_setpfccfg(struct net_device *netdev, struct nlattr **tb,
 848                           u32 pid, u32 seq, u16 flags)
 849{
 850        struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1];
 851        int i;
 852        int ret = -EINVAL;
 853        u8 value;
 854
 855        if (!tb[DCB_ATTR_PFC_CFG] || !netdev->dcbnl_ops->setpfccfg)
 856                return ret;
 857
 858        ret = nla_parse_nested(data, DCB_PFC_UP_ATTR_MAX,
 859                               tb[DCB_ATTR_PFC_CFG],
 860                               dcbnl_pfc_up_nest);
 861        if (ret)
 862                goto err;
 863
 864        for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) {
 865                if (data[i] == NULL)
 866                        continue;
 867                value = nla_get_u8(data[i]);
 868                netdev->dcbnl_ops->setpfccfg(netdev,
 869                        data[i]->nla_type - DCB_PFC_UP_ATTR_0, value);
 870        }
 871
 872        ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_PFC_SCFG, DCB_ATTR_PFC_CFG,
 873                          pid, seq, flags);
 874err:
 875        return ret;
 876}
 877
 878static int dcbnl_setall(struct net_device *netdev, struct nlattr **tb,
 879                        u32 pid, u32 seq, u16 flags)
 880{
 881        int ret = -EINVAL;
 882
 883        if (!tb[DCB_ATTR_SET_ALL] || !netdev->dcbnl_ops->setall)
 884                return ret;
 885
 886        ret = dcbnl_reply(netdev->dcbnl_ops->setall(netdev), RTM_SETDCB,
 887                          DCB_CMD_SET_ALL, DCB_ATTR_SET_ALL, pid, seq, flags);
 888
 889        return ret;
 890}
 891
 892static int __dcbnl_pg_setcfg(struct net_device *netdev, struct nlattr **tb,
 893                             u32 pid, u32 seq, u16 flags, int dir)
 894{
 895        struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1];
 896        struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1];
 897        int ret = -EINVAL;
 898        int i;
 899        u8 pgid;
 900        u8 up_map;
 901        u8 prio;
 902        u8 tc_pct;
 903
 904        if (!tb[DCB_ATTR_PG_CFG] ||
 905            !netdev->dcbnl_ops->setpgtccfgtx ||
 906            !netdev->dcbnl_ops->setpgtccfgrx ||
 907            !netdev->dcbnl_ops->setpgbwgcfgtx ||
 908            !netdev->dcbnl_ops->setpgbwgcfgrx)
 909                return ret;
 910
 911        ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX,
 912                               tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest);
 913        if (ret)
 914                goto err;
 915
 916        for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) {
 917                if (!pg_tb[i])
 918                        continue;
 919
 920                ret = nla_parse_nested(param_tb, DCB_TC_ATTR_PARAM_MAX,
 921                                       pg_tb[i], dcbnl_tc_param_nest);
 922                if (ret)
 923                        goto err;
 924
 925                pgid = DCB_ATTR_VALUE_UNDEFINED;
 926                prio = DCB_ATTR_VALUE_UNDEFINED;
 927                tc_pct = DCB_ATTR_VALUE_UNDEFINED;
 928                up_map = DCB_ATTR_VALUE_UNDEFINED;
 929
 930                if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO])
 931                        prio =
 932                            nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO]);
 933
 934                if (param_tb[DCB_TC_ATTR_PARAM_PGID])
 935                        pgid = nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_PGID]);
 936
 937                if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT])
 938                        tc_pct = nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_BW_PCT]);
 939
 940                if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING])
 941                        up_map =
 942                             nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING]);
 943
 944                /* dir: Tx = 0, Rx = 1 */
 945                if (dir) {
 946                        /* Rx */
 947                        netdev->dcbnl_ops->setpgtccfgrx(netdev,
 948                                i - DCB_PG_ATTR_TC_0,
 949                                prio, pgid, tc_pct, up_map);
 950                } else {
 951                        /* Tx */
 952                        netdev->dcbnl_ops->setpgtccfgtx(netdev,
 953                                i - DCB_PG_ATTR_TC_0,
 954                                prio, pgid, tc_pct, up_map);
 955                }
 956        }
 957
 958        for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) {
 959                if (!pg_tb[i])
 960                        continue;
 961
 962                tc_pct = nla_get_u8(pg_tb[i]);
 963
 964                /* dir: Tx = 0, Rx = 1 */
 965                if (dir) {
 966                        /* Rx */
 967                        netdev->dcbnl_ops->setpgbwgcfgrx(netdev,
 968                                         i - DCB_PG_ATTR_BW_ID_0, tc_pct);
 969                } else {
 970                        /* Tx */
 971                        netdev->dcbnl_ops->setpgbwgcfgtx(netdev,
 972                                         i - DCB_PG_ATTR_BW_ID_0, tc_pct);
 973                }
 974        }
 975
 976        ret = dcbnl_reply(0, RTM_SETDCB,
 977                          (dir ? DCB_CMD_PGRX_SCFG : DCB_CMD_PGTX_SCFG),
 978                          DCB_ATTR_PG_CFG, pid, seq, flags);
 979
 980err:
 981        return ret;
 982}
 983
 984static int dcbnl_pgtx_setcfg(struct net_device *netdev, struct nlattr **tb,
 985                             u32 pid, u32 seq, u16 flags)
 986{
 987        return __dcbnl_pg_setcfg(netdev, tb, pid, seq, flags, 0);
 988}
 989
 990static int dcbnl_pgrx_setcfg(struct net_device *netdev, struct nlattr **tb,
 991                             u32 pid, u32 seq, u16 flags)
 992{
 993        return __dcbnl_pg_setcfg(netdev, tb, pid, seq, flags, 1);
 994}
 995
 996static int dcbnl_bcn_getcfg(struct net_device *netdev, struct nlattr **tb,
 997                            u32 pid, u32 seq, u16 flags)
 998{
 999        struct sk_buff *dcbnl_skb;
1000        struct nlmsghdr *nlh;
1001        struct dcbmsg *dcb;
1002        struct nlattr *bcn_nest;
1003        struct nlattr *bcn_tb[DCB_BCN_ATTR_MAX + 1];
1004        u8 value_byte;
1005        u32 value_integer;
1006        int ret  = -EINVAL;
1007        bool getall = false;
1008        int i;
1009
1010        if (!tb[DCB_ATTR_BCN] || !netdev->dcbnl_ops->getbcnrp ||
1011            !netdev->dcbnl_ops->getbcncfg)
1012                return ret;
1013
1014        ret = nla_parse_nested(bcn_tb, DCB_BCN_ATTR_MAX,
1015                               tb[DCB_ATTR_BCN], dcbnl_bcn_nest);
1016
1017        if (ret)
1018                goto err_out;
1019
1020        dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1021        if (!dcbnl_skb)
1022                goto err_out;
1023
1024        nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
1025
1026        dcb = NLMSG_DATA(nlh);
1027        dcb->dcb_family = AF_UNSPEC;
1028        dcb->cmd = DCB_CMD_BCN_GCFG;
1029
1030        bcn_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_BCN);
1031        if (!bcn_nest)
1032                goto err;
1033
1034        if (bcn_tb[DCB_BCN_ATTR_ALL])
1035                getall = true;
1036
1037        for (i = DCB_BCN_ATTR_RP_0; i <= DCB_BCN_ATTR_RP_7; i++) {
1038                if (!getall && !bcn_tb[i])
1039                        continue;
1040
1041                netdev->dcbnl_ops->getbcnrp(netdev, i - DCB_BCN_ATTR_RP_0,
1042                                            &value_byte);
1043                ret = nla_put_u8(dcbnl_skb, i, value_byte);
1044                if (ret)
1045                        goto err_bcn;
1046        }
1047
1048        for (i = DCB_BCN_ATTR_BCNA_0; i <= DCB_BCN_ATTR_RI; i++) {
1049                if (!getall && !bcn_tb[i])
1050                        continue;
1051
1052                netdev->dcbnl_ops->getbcncfg(netdev, i,
1053                                             &value_integer);
1054                ret = nla_put_u32(dcbnl_skb, i, value_integer);
1055                if (ret)
1056                        goto err_bcn;
1057        }
1058
1059        nla_nest_end(dcbnl_skb, bcn_nest);
1060
1061        nlmsg_end(dcbnl_skb, nlh);
1062
1063        ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
1064        if (ret)
1065                goto err_out;
1066
1067        return 0;
1068
1069err_bcn:
1070        nla_nest_cancel(dcbnl_skb, bcn_nest);
1071nlmsg_failure:
1072err:
1073        kfree_skb(dcbnl_skb);
1074err_out:
1075        ret  = -EINVAL;
1076        return ret;
1077}
1078
1079static int dcbnl_bcn_setcfg(struct net_device *netdev, struct nlattr **tb,
1080                            u32 pid, u32 seq, u16 flags)
1081{
1082        struct nlattr *data[DCB_BCN_ATTR_MAX + 1];
1083        int i;
1084        int ret = -EINVAL;
1085        u8 value_byte;
1086        u32 value_int;
1087
1088        if (!tb[DCB_ATTR_BCN] || !netdev->dcbnl_ops->setbcncfg
1089            || !netdev->dcbnl_ops->setbcnrp)
1090                return ret;
1091
1092        ret = nla_parse_nested(data, DCB_BCN_ATTR_MAX,
1093                               tb[DCB_ATTR_BCN],
1094                               dcbnl_pfc_up_nest);
1095        if (ret)
1096                goto err;
1097
1098        for (i = DCB_BCN_ATTR_RP_0; i <= DCB_BCN_ATTR_RP_7; i++) {
1099                if (data[i] == NULL)
1100                        continue;
1101                value_byte = nla_get_u8(data[i]);
1102                netdev->dcbnl_ops->setbcnrp(netdev,
1103                        data[i]->nla_type - DCB_BCN_ATTR_RP_0, value_byte);
1104        }
1105
1106        for (i = DCB_BCN_ATTR_BCNA_0; i <= DCB_BCN_ATTR_RI; i++) {
1107                if (data[i] == NULL)
1108                        continue;
1109                value_int = nla_get_u32(data[i]);
1110                netdev->dcbnl_ops->setbcncfg(netdev,
1111                                             i, value_int);
1112        }
1113
1114        ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_BCN_SCFG, DCB_ATTR_BCN,
1115                          pid, seq, flags);
1116err:
1117        return ret;
1118}
1119
1120static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
1121{
1122        struct net *net = sock_net(skb->sk);
1123        struct net_device *netdev;
1124        struct dcbmsg  *dcb = (struct dcbmsg *)NLMSG_DATA(nlh);
1125        struct nlattr *tb[DCB_ATTR_MAX + 1];
1126        u32 pid = skb ? NETLINK_CB(skb).pid : 0;
1127        int ret = -EINVAL;
1128
1129        if (net != &init_net)
1130                return -EINVAL;
1131
1132        ret = nlmsg_parse(nlh, sizeof(*dcb), tb, DCB_ATTR_MAX,
1133                          dcbnl_rtnl_policy);
1134        if (ret < 0)
1135                return ret;
1136
1137        if (!tb[DCB_ATTR_IFNAME])
1138                return -EINVAL;
1139
1140        netdev = dev_get_by_name(&init_net, nla_data(tb[DCB_ATTR_IFNAME]));
1141        if (!netdev)
1142                return -EINVAL;
1143
1144        if (!netdev->dcbnl_ops)
1145                goto errout;
1146
1147        switch (dcb->cmd) {
1148        case DCB_CMD_GSTATE:
1149                ret = dcbnl_getstate(netdev, tb, pid, nlh->nlmsg_seq,
1150                                     nlh->nlmsg_flags);
1151                goto out;
1152        case DCB_CMD_PFC_GCFG:
1153                ret = dcbnl_getpfccfg(netdev, tb, pid, nlh->nlmsg_seq,
1154                                      nlh->nlmsg_flags);
1155                goto out;
1156        case DCB_CMD_GPERM_HWADDR:
1157                ret = dcbnl_getperm_hwaddr(netdev, tb, pid, nlh->nlmsg_seq,
1158                                           nlh->nlmsg_flags);
1159                goto out;
1160        case DCB_CMD_PGTX_GCFG:
1161                ret = dcbnl_pgtx_getcfg(netdev, tb, pid, nlh->nlmsg_seq,
1162                                        nlh->nlmsg_flags);
1163                goto out;
1164        case DCB_CMD_PGRX_GCFG:
1165                ret = dcbnl_pgrx_getcfg(netdev, tb, pid, nlh->nlmsg_seq,
1166                                        nlh->nlmsg_flags);
1167                goto out;
1168        case DCB_CMD_BCN_GCFG:
1169                ret = dcbnl_bcn_getcfg(netdev, tb, pid, nlh->nlmsg_seq,
1170                                       nlh->nlmsg_flags);
1171                goto out;
1172        case DCB_CMD_SSTATE:
1173                ret = dcbnl_setstate(netdev, tb, pid, nlh->nlmsg_seq,
1174                                     nlh->nlmsg_flags);
1175                goto out;
1176        case DCB_CMD_PFC_SCFG:
1177                ret = dcbnl_setpfccfg(netdev, tb, pid, nlh->nlmsg_seq,
1178                                      nlh->nlmsg_flags);
1179                goto out;
1180
1181        case DCB_CMD_SET_ALL:
1182                ret = dcbnl_setall(netdev, tb, pid, nlh->nlmsg_seq,
1183                                   nlh->nlmsg_flags);
1184                goto out;
1185        case DCB_CMD_PGTX_SCFG:
1186                ret = dcbnl_pgtx_setcfg(netdev, tb, pid, nlh->nlmsg_seq,
1187                                        nlh->nlmsg_flags);
1188                goto out;
1189        case DCB_CMD_PGRX_SCFG:
1190                ret = dcbnl_pgrx_setcfg(netdev, tb, pid, nlh->nlmsg_seq,
1191                                        nlh->nlmsg_flags);
1192                goto out;
1193        case DCB_CMD_GCAP:
1194                ret = dcbnl_getcap(netdev, tb, pid, nlh->nlmsg_seq,
1195                                   nlh->nlmsg_flags);
1196                goto out;
1197        case DCB_CMD_GNUMTCS:
1198                ret = dcbnl_getnumtcs(netdev, tb, pid, nlh->nlmsg_seq,
1199                                      nlh->nlmsg_flags);
1200                goto out;
1201        case DCB_CMD_SNUMTCS:
1202                ret = dcbnl_setnumtcs(netdev, tb, pid, nlh->nlmsg_seq,
1203                                      nlh->nlmsg_flags);
1204                goto out;
1205        case DCB_CMD_PFC_GSTATE:
1206                ret = dcbnl_getpfcstate(netdev, tb, pid, nlh->nlmsg_seq,
1207                                        nlh->nlmsg_flags);
1208                goto out;
1209        case DCB_CMD_PFC_SSTATE:
1210                ret = dcbnl_setpfcstate(netdev, tb, pid, nlh->nlmsg_seq,
1211                                        nlh->nlmsg_flags);
1212                goto out;
1213        case DCB_CMD_BCN_SCFG:
1214                ret = dcbnl_bcn_setcfg(netdev, tb, pid, nlh->nlmsg_seq,
1215                                       nlh->nlmsg_flags);
1216                goto out;
1217        case DCB_CMD_GAPP:
1218                ret = dcbnl_getapp(netdev, tb, pid, nlh->nlmsg_seq,
1219                                   nlh->nlmsg_flags);
1220                goto out;
1221        case DCB_CMD_SAPP:
1222                ret = dcbnl_setapp(netdev, tb, pid, nlh->nlmsg_seq,
1223                                   nlh->nlmsg_flags);
1224                goto out;
1225        default:
1226                goto errout;
1227        }
1228errout:
1229        ret = -EINVAL;
1230out:
1231        dev_put(netdev);
1232        return ret;
1233}
1234
1235static int __init dcbnl_init(void)
1236{
1237        rtnl_register(PF_UNSPEC, RTM_GETDCB, dcb_doit, NULL);
1238        rtnl_register(PF_UNSPEC, RTM_SETDCB, dcb_doit, NULL);
1239
1240        return 0;
1241}
1242module_init(dcbnl_init);
1243
1244static void __exit dcbnl_exit(void)
1245{
1246        rtnl_unregister(PF_UNSPEC, RTM_GETDCB);
1247        rtnl_unregister(PF_UNSPEC, RTM_SETDCB);
1248}
1249module_exit(dcbnl_exit);
1250
1251
1252