linux/net/dcb/dcbnl.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2008-2011, 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 <linux/slab.h>
  23#include <net/netlink.h>
  24#include <net/rtnetlink.h>
  25#include <linux/dcbnl.h>
  26#include <net/dcbevent.h>
  27#include <linux/rtnetlink.h>
  28#include <linux/module.h>
  29#include <net/sock.h>
  30
  31/**
  32 * Data Center Bridging (DCB) is a collection of Ethernet enhancements
  33 * intended to allow network traffic with differing requirements
  34 * (highly reliable, no drops vs. best effort vs. low latency) to operate
  35 * and co-exist on Ethernet.  Current DCB features are:
  36 *
  37 * Enhanced Transmission Selection (aka Priority Grouping [PG]) - provides a
  38 *   framework for assigning bandwidth guarantees to traffic classes.
  39 *
  40 * Priority-based Flow Control (PFC) - provides a flow control mechanism which
  41 *   can work independently for each 802.1p priority.
  42 *
  43 * Congestion Notification - provides a mechanism for end-to-end congestion
  44 *   control for protocols which do not have built-in congestion management.
  45 *
  46 * More information about the emerging standards for these Ethernet features
  47 * can be found at: http://www.ieee802.org/1/pages/dcbridges.html
  48 *
  49 * This file implements an rtnetlink interface to allow configuration of DCB
  50 * features for capable devices.
  51 */
  52
  53MODULE_AUTHOR("Lucy Liu, <lucy.liu@intel.com>");
  54MODULE_DESCRIPTION("Data Center Bridging netlink interface");
  55MODULE_LICENSE("GPL");
  56
  57/**************** DCB attribute policies *************************************/
  58
  59/* DCB netlink attributes policy */
  60static const struct nla_policy dcbnl_rtnl_policy[DCB_ATTR_MAX + 1] = {
  61        [DCB_ATTR_IFNAME]      = {.type = NLA_NUL_STRING, .len = IFNAMSIZ - 1},
  62        [DCB_ATTR_STATE]       = {.type = NLA_U8},
  63        [DCB_ATTR_PFC_CFG]     = {.type = NLA_NESTED},
  64        [DCB_ATTR_PG_CFG]      = {.type = NLA_NESTED},
  65        [DCB_ATTR_SET_ALL]     = {.type = NLA_U8},
  66        [DCB_ATTR_PERM_HWADDR] = {.type = NLA_FLAG},
  67        [DCB_ATTR_CAP]         = {.type = NLA_NESTED},
  68        [DCB_ATTR_PFC_STATE]   = {.type = NLA_U8},
  69        [DCB_ATTR_BCN]         = {.type = NLA_NESTED},
  70        [DCB_ATTR_APP]         = {.type = NLA_NESTED},
  71        [DCB_ATTR_IEEE]        = {.type = NLA_NESTED},
  72        [DCB_ATTR_DCBX]        = {.type = NLA_U8},
  73        [DCB_ATTR_FEATCFG]     = {.type = NLA_NESTED},
  74};
  75
  76/* DCB priority flow control to User Priority nested attributes */
  77static const struct nla_policy dcbnl_pfc_up_nest[DCB_PFC_UP_ATTR_MAX + 1] = {
  78        [DCB_PFC_UP_ATTR_0]   = {.type = NLA_U8},
  79        [DCB_PFC_UP_ATTR_1]   = {.type = NLA_U8},
  80        [DCB_PFC_UP_ATTR_2]   = {.type = NLA_U8},
  81        [DCB_PFC_UP_ATTR_3]   = {.type = NLA_U8},
  82        [DCB_PFC_UP_ATTR_4]   = {.type = NLA_U8},
  83        [DCB_PFC_UP_ATTR_5]   = {.type = NLA_U8},
  84        [DCB_PFC_UP_ATTR_6]   = {.type = NLA_U8},
  85        [DCB_PFC_UP_ATTR_7]   = {.type = NLA_U8},
  86        [DCB_PFC_UP_ATTR_ALL] = {.type = NLA_FLAG},
  87};
  88
  89/* DCB priority grouping nested attributes */
  90static const struct nla_policy dcbnl_pg_nest[DCB_PG_ATTR_MAX + 1] = {
  91        [DCB_PG_ATTR_TC_0]      = {.type = NLA_NESTED},
  92        [DCB_PG_ATTR_TC_1]      = {.type = NLA_NESTED},
  93        [DCB_PG_ATTR_TC_2]      = {.type = NLA_NESTED},
  94        [DCB_PG_ATTR_TC_3]      = {.type = NLA_NESTED},
  95        [DCB_PG_ATTR_TC_4]      = {.type = NLA_NESTED},
  96        [DCB_PG_ATTR_TC_5]      = {.type = NLA_NESTED},
  97        [DCB_PG_ATTR_TC_6]      = {.type = NLA_NESTED},
  98        [DCB_PG_ATTR_TC_7]      = {.type = NLA_NESTED},
  99        [DCB_PG_ATTR_TC_ALL]    = {.type = NLA_NESTED},
 100        [DCB_PG_ATTR_BW_ID_0]   = {.type = NLA_U8},
 101        [DCB_PG_ATTR_BW_ID_1]   = {.type = NLA_U8},
 102        [DCB_PG_ATTR_BW_ID_2]   = {.type = NLA_U8},
 103        [DCB_PG_ATTR_BW_ID_3]   = {.type = NLA_U8},
 104        [DCB_PG_ATTR_BW_ID_4]   = {.type = NLA_U8},
 105        [DCB_PG_ATTR_BW_ID_5]   = {.type = NLA_U8},
 106        [DCB_PG_ATTR_BW_ID_6]   = {.type = NLA_U8},
 107        [DCB_PG_ATTR_BW_ID_7]   = {.type = NLA_U8},
 108        [DCB_PG_ATTR_BW_ID_ALL] = {.type = NLA_FLAG},
 109};
 110
 111/* DCB traffic class nested attributes. */
 112static const struct nla_policy dcbnl_tc_param_nest[DCB_TC_ATTR_PARAM_MAX + 1] = {
 113        [DCB_TC_ATTR_PARAM_PGID]            = {.type = NLA_U8},
 114        [DCB_TC_ATTR_PARAM_UP_MAPPING]      = {.type = NLA_U8},
 115        [DCB_TC_ATTR_PARAM_STRICT_PRIO]     = {.type = NLA_U8},
 116        [DCB_TC_ATTR_PARAM_BW_PCT]          = {.type = NLA_U8},
 117        [DCB_TC_ATTR_PARAM_ALL]             = {.type = NLA_FLAG},
 118};
 119
 120/* DCB capabilities nested attributes. */
 121static const struct nla_policy dcbnl_cap_nest[DCB_CAP_ATTR_MAX + 1] = {
 122        [DCB_CAP_ATTR_ALL]     = {.type = NLA_FLAG},
 123        [DCB_CAP_ATTR_PG]      = {.type = NLA_U8},
 124        [DCB_CAP_ATTR_PFC]     = {.type = NLA_U8},
 125        [DCB_CAP_ATTR_UP2TC]   = {.type = NLA_U8},
 126        [DCB_CAP_ATTR_PG_TCS]  = {.type = NLA_U8},
 127        [DCB_CAP_ATTR_PFC_TCS] = {.type = NLA_U8},
 128        [DCB_CAP_ATTR_GSP]     = {.type = NLA_U8},
 129        [DCB_CAP_ATTR_BCN]     = {.type = NLA_U8},
 130        [DCB_CAP_ATTR_DCBX]    = {.type = NLA_U8},
 131};
 132
 133/* DCB capabilities nested attributes. */
 134static const struct nla_policy dcbnl_numtcs_nest[DCB_NUMTCS_ATTR_MAX + 1] = {
 135        [DCB_NUMTCS_ATTR_ALL]     = {.type = NLA_FLAG},
 136        [DCB_NUMTCS_ATTR_PG]      = {.type = NLA_U8},
 137        [DCB_NUMTCS_ATTR_PFC]     = {.type = NLA_U8},
 138};
 139
 140/* DCB BCN nested attributes. */
 141static const struct nla_policy dcbnl_bcn_nest[DCB_BCN_ATTR_MAX + 1] = {
 142        [DCB_BCN_ATTR_RP_0]         = {.type = NLA_U8},
 143        [DCB_BCN_ATTR_RP_1]         = {.type = NLA_U8},
 144        [DCB_BCN_ATTR_RP_2]         = {.type = NLA_U8},
 145        [DCB_BCN_ATTR_RP_3]         = {.type = NLA_U8},
 146        [DCB_BCN_ATTR_RP_4]         = {.type = NLA_U8},
 147        [DCB_BCN_ATTR_RP_5]         = {.type = NLA_U8},
 148        [DCB_BCN_ATTR_RP_6]         = {.type = NLA_U8},
 149        [DCB_BCN_ATTR_RP_7]         = {.type = NLA_U8},
 150        [DCB_BCN_ATTR_RP_ALL]       = {.type = NLA_FLAG},
 151        [DCB_BCN_ATTR_BCNA_0]       = {.type = NLA_U32},
 152        [DCB_BCN_ATTR_BCNA_1]       = {.type = NLA_U32},
 153        [DCB_BCN_ATTR_ALPHA]        = {.type = NLA_U32},
 154        [DCB_BCN_ATTR_BETA]         = {.type = NLA_U32},
 155        [DCB_BCN_ATTR_GD]           = {.type = NLA_U32},
 156        [DCB_BCN_ATTR_GI]           = {.type = NLA_U32},
 157        [DCB_BCN_ATTR_TMAX]         = {.type = NLA_U32},
 158        [DCB_BCN_ATTR_TD]           = {.type = NLA_U32},
 159        [DCB_BCN_ATTR_RMIN]         = {.type = NLA_U32},
 160        [DCB_BCN_ATTR_W]            = {.type = NLA_U32},
 161        [DCB_BCN_ATTR_RD]           = {.type = NLA_U32},
 162        [DCB_BCN_ATTR_RU]           = {.type = NLA_U32},
 163        [DCB_BCN_ATTR_WRTT]         = {.type = NLA_U32},
 164        [DCB_BCN_ATTR_RI]           = {.type = NLA_U32},
 165        [DCB_BCN_ATTR_C]            = {.type = NLA_U32},
 166        [DCB_BCN_ATTR_ALL]          = {.type = NLA_FLAG},
 167};
 168
 169/* DCB APP nested attributes. */
 170static const struct nla_policy dcbnl_app_nest[DCB_APP_ATTR_MAX + 1] = {
 171        [DCB_APP_ATTR_IDTYPE]       = {.type = NLA_U8},
 172        [DCB_APP_ATTR_ID]           = {.type = NLA_U16},
 173        [DCB_APP_ATTR_PRIORITY]     = {.type = NLA_U8},
 174};
 175
 176/* IEEE 802.1Qaz nested attributes. */
 177static const struct nla_policy dcbnl_ieee_policy[DCB_ATTR_IEEE_MAX + 1] = {
 178        [DCB_ATTR_IEEE_ETS]         = {.len = sizeof(struct ieee_ets)},
 179        [DCB_ATTR_IEEE_PFC]         = {.len = sizeof(struct ieee_pfc)},
 180        [DCB_ATTR_IEEE_APP_TABLE]   = {.type = NLA_NESTED},
 181};
 182
 183static const struct nla_policy dcbnl_ieee_app[DCB_ATTR_IEEE_APP_MAX + 1] = {
 184        [DCB_ATTR_IEEE_APP]         = {.len = sizeof(struct dcb_app)},
 185};
 186
 187/* DCB number of traffic classes nested attributes. */
 188static const struct nla_policy dcbnl_featcfg_nest[DCB_FEATCFG_ATTR_MAX + 1] = {
 189        [DCB_FEATCFG_ATTR_ALL]      = {.type = NLA_FLAG},
 190        [DCB_FEATCFG_ATTR_PG]       = {.type = NLA_U8},
 191        [DCB_FEATCFG_ATTR_PFC]      = {.type = NLA_U8},
 192        [DCB_FEATCFG_ATTR_APP]      = {.type = NLA_U8},
 193};
 194
 195static LIST_HEAD(dcb_app_list);
 196static DEFINE_SPINLOCK(dcb_lock);
 197
 198/* standard netlink reply call */
 199static int dcbnl_reply(u8 value, u8 event, u8 cmd, u8 attr, u32 pid,
 200                       u32 seq, u16 flags)
 201{
 202        struct sk_buff *dcbnl_skb;
 203        struct dcbmsg *dcb;
 204        struct nlmsghdr *nlh;
 205        int ret = -EINVAL;
 206
 207        dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
 208        if (!dcbnl_skb)
 209                return ret;
 210
 211        nlh = NLMSG_NEW(dcbnl_skb, pid, seq, event, sizeof(*dcb), flags);
 212
 213        dcb = NLMSG_DATA(nlh);
 214        dcb->dcb_family = AF_UNSPEC;
 215        dcb->cmd = cmd;
 216        dcb->dcb_pad = 0;
 217
 218        ret = nla_put_u8(dcbnl_skb, attr, value);
 219        if (ret)
 220                goto err;
 221
 222        /* end the message, assign the nlmsg_len. */
 223        nlmsg_end(dcbnl_skb, nlh);
 224        ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
 225        if (ret)
 226                return -EINVAL;
 227
 228        return 0;
 229nlmsg_failure:
 230err:
 231        kfree_skb(dcbnl_skb);
 232        return ret;
 233}
 234
 235static int dcbnl_getstate(struct net_device *netdev, struct nlattr **tb,
 236                          u32 pid, u32 seq, u16 flags)
 237{
 238        int ret = -EINVAL;
 239
 240        /* if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->getstate) */
 241        if (!netdev->dcbnl_ops->getstate)
 242                return ret;
 243
 244        ret = dcbnl_reply(netdev->dcbnl_ops->getstate(netdev), RTM_GETDCB,
 245                          DCB_CMD_GSTATE, DCB_ATTR_STATE, pid, seq, flags);
 246
 247        return ret;
 248}
 249
 250static int dcbnl_getpfccfg(struct net_device *netdev, struct nlattr **tb,
 251                           u32 pid, u32 seq, u16 flags)
 252{
 253        struct sk_buff *dcbnl_skb;
 254        struct nlmsghdr *nlh;
 255        struct dcbmsg *dcb;
 256        struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1], *nest;
 257        u8 value;
 258        int ret = -EINVAL;
 259        int i;
 260        int getall = 0;
 261
 262        if (!tb[DCB_ATTR_PFC_CFG] || !netdev->dcbnl_ops->getpfccfg)
 263                return ret;
 264
 265        ret = nla_parse_nested(data, DCB_PFC_UP_ATTR_MAX,
 266                               tb[DCB_ATTR_PFC_CFG],
 267                               dcbnl_pfc_up_nest);
 268        if (ret)
 269                goto err_out;
 270
 271        dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
 272        if (!dcbnl_skb)
 273                goto err_out;
 274
 275        nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
 276
 277        dcb = NLMSG_DATA(nlh);
 278        dcb->dcb_family = AF_UNSPEC;
 279        dcb->cmd = DCB_CMD_PFC_GCFG;
 280
 281        nest = nla_nest_start(dcbnl_skb, DCB_ATTR_PFC_CFG);
 282        if (!nest)
 283                goto err;
 284
 285        if (data[DCB_PFC_UP_ATTR_ALL])
 286                getall = 1;
 287
 288        for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) {
 289                if (!getall && !data[i])
 290                        continue;
 291
 292                netdev->dcbnl_ops->getpfccfg(netdev, i - DCB_PFC_UP_ATTR_0,
 293                                             &value);
 294                ret = nla_put_u8(dcbnl_skb, i, value);
 295
 296                if (ret) {
 297                        nla_nest_cancel(dcbnl_skb, nest);
 298                        goto err;
 299                }
 300        }
 301        nla_nest_end(dcbnl_skb, nest);
 302
 303        nlmsg_end(dcbnl_skb, nlh);
 304
 305        ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
 306        if (ret)
 307                goto err_out;
 308
 309        return 0;
 310nlmsg_failure:
 311err:
 312        kfree_skb(dcbnl_skb);
 313err_out:
 314        return -EINVAL;
 315}
 316
 317static int dcbnl_getperm_hwaddr(struct net_device *netdev, struct nlattr **tb,
 318                                u32 pid, u32 seq, u16 flags)
 319{
 320        struct sk_buff *dcbnl_skb;
 321        struct nlmsghdr *nlh;
 322        struct dcbmsg *dcb;
 323        u8 perm_addr[MAX_ADDR_LEN];
 324        int ret = -EINVAL;
 325
 326        if (!netdev->dcbnl_ops->getpermhwaddr)
 327                return ret;
 328
 329        dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
 330        if (!dcbnl_skb)
 331                goto err_out;
 332
 333        nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
 334
 335        dcb = NLMSG_DATA(nlh);
 336        dcb->dcb_family = AF_UNSPEC;
 337        dcb->cmd = DCB_CMD_GPERM_HWADDR;
 338
 339        netdev->dcbnl_ops->getpermhwaddr(netdev, perm_addr);
 340
 341        ret = nla_put(dcbnl_skb, DCB_ATTR_PERM_HWADDR, sizeof(perm_addr),
 342                      perm_addr);
 343
 344        nlmsg_end(dcbnl_skb, nlh);
 345
 346        ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
 347        if (ret)
 348                goto err_out;
 349
 350        return 0;
 351
 352nlmsg_failure:
 353        kfree_skb(dcbnl_skb);
 354err_out:
 355        return -EINVAL;
 356}
 357
 358static int dcbnl_getcap(struct net_device *netdev, struct nlattr **tb,
 359                        u32 pid, u32 seq, u16 flags)
 360{
 361        struct sk_buff *dcbnl_skb;
 362        struct nlmsghdr *nlh;
 363        struct dcbmsg *dcb;
 364        struct nlattr *data[DCB_CAP_ATTR_MAX + 1], *nest;
 365        u8 value;
 366        int ret = -EINVAL;
 367        int i;
 368        int getall = 0;
 369
 370        if (!tb[DCB_ATTR_CAP] || !netdev->dcbnl_ops->getcap)
 371                return ret;
 372
 373        ret = nla_parse_nested(data, DCB_CAP_ATTR_MAX, tb[DCB_ATTR_CAP],
 374                               dcbnl_cap_nest);
 375        if (ret)
 376                goto err_out;
 377
 378        dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
 379        if (!dcbnl_skb)
 380                goto err_out;
 381
 382        nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
 383
 384        dcb = NLMSG_DATA(nlh);
 385        dcb->dcb_family = AF_UNSPEC;
 386        dcb->cmd = DCB_CMD_GCAP;
 387
 388        nest = nla_nest_start(dcbnl_skb, DCB_ATTR_CAP);
 389        if (!nest)
 390                goto err;
 391
 392        if (data[DCB_CAP_ATTR_ALL])
 393                getall = 1;
 394
 395        for (i = DCB_CAP_ATTR_ALL+1; i <= DCB_CAP_ATTR_MAX; i++) {
 396                if (!getall && !data[i])
 397                        continue;
 398
 399                if (!netdev->dcbnl_ops->getcap(netdev, i, &value)) {
 400                        ret = nla_put_u8(dcbnl_skb, i, value);
 401
 402                        if (ret) {
 403                                nla_nest_cancel(dcbnl_skb, nest);
 404                                goto err;
 405                        }
 406                }
 407        }
 408        nla_nest_end(dcbnl_skb, nest);
 409
 410        nlmsg_end(dcbnl_skb, nlh);
 411
 412        ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
 413        if (ret)
 414                goto err_out;
 415
 416        return 0;
 417nlmsg_failure:
 418err:
 419        kfree_skb(dcbnl_skb);
 420err_out:
 421        return -EINVAL;
 422}
 423
 424static int dcbnl_getnumtcs(struct net_device *netdev, struct nlattr **tb,
 425                           u32 pid, u32 seq, u16 flags)
 426{
 427        struct sk_buff *dcbnl_skb;
 428        struct nlmsghdr *nlh;
 429        struct dcbmsg *dcb;
 430        struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1], *nest;
 431        u8 value;
 432        int ret = -EINVAL;
 433        int i;
 434        int getall = 0;
 435
 436        if (!tb[DCB_ATTR_NUMTCS] || !netdev->dcbnl_ops->getnumtcs)
 437                return ret;
 438
 439        ret = nla_parse_nested(data, DCB_NUMTCS_ATTR_MAX, tb[DCB_ATTR_NUMTCS],
 440                               dcbnl_numtcs_nest);
 441        if (ret) {
 442                ret = -EINVAL;
 443                goto err_out;
 444        }
 445
 446        dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
 447        if (!dcbnl_skb) {
 448                ret = -EINVAL;
 449                goto err_out;
 450        }
 451
 452        nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
 453
 454        dcb = NLMSG_DATA(nlh);
 455        dcb->dcb_family = AF_UNSPEC;
 456        dcb->cmd = DCB_CMD_GNUMTCS;
 457
 458        nest = nla_nest_start(dcbnl_skb, DCB_ATTR_NUMTCS);
 459        if (!nest) {
 460                ret = -EINVAL;
 461                goto err;
 462        }
 463
 464        if (data[DCB_NUMTCS_ATTR_ALL])
 465                getall = 1;
 466
 467        for (i = DCB_NUMTCS_ATTR_ALL+1; i <= DCB_NUMTCS_ATTR_MAX; i++) {
 468                if (!getall && !data[i])
 469                        continue;
 470
 471                ret = netdev->dcbnl_ops->getnumtcs(netdev, i, &value);
 472                if (!ret) {
 473                        ret = nla_put_u8(dcbnl_skb, i, value);
 474
 475                        if (ret) {
 476                                nla_nest_cancel(dcbnl_skb, nest);
 477                                ret = -EINVAL;
 478                                goto err;
 479                        }
 480                } else {
 481                        goto err;
 482                }
 483        }
 484        nla_nest_end(dcbnl_skb, nest);
 485
 486        nlmsg_end(dcbnl_skb, nlh);
 487
 488        ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
 489        if (ret) {
 490                ret = -EINVAL;
 491                goto err_out;
 492        }
 493
 494        return 0;
 495nlmsg_failure:
 496err:
 497        kfree_skb(dcbnl_skb);
 498err_out:
 499        return ret;
 500}
 501
 502static int dcbnl_setnumtcs(struct net_device *netdev, struct nlattr **tb,
 503                           u32 pid, u32 seq, u16 flags)
 504{
 505        struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1];
 506        int ret = -EINVAL;
 507        u8 value;
 508        int i;
 509
 510        if (!tb[DCB_ATTR_NUMTCS] || !netdev->dcbnl_ops->setnumtcs)
 511                return ret;
 512
 513        ret = nla_parse_nested(data, DCB_NUMTCS_ATTR_MAX, tb[DCB_ATTR_NUMTCS],
 514                               dcbnl_numtcs_nest);
 515
 516        if (ret) {
 517                ret = -EINVAL;
 518                goto err;
 519        }
 520
 521        for (i = DCB_NUMTCS_ATTR_ALL+1; i <= DCB_NUMTCS_ATTR_MAX; i++) {
 522                if (data[i] == NULL)
 523                        continue;
 524
 525                value = nla_get_u8(data[i]);
 526
 527                ret = netdev->dcbnl_ops->setnumtcs(netdev, i, value);
 528
 529                if (ret)
 530                        goto operr;
 531        }
 532
 533operr:
 534        ret = dcbnl_reply(!!ret, RTM_SETDCB, DCB_CMD_SNUMTCS,
 535                          DCB_ATTR_NUMTCS, pid, seq, flags);
 536
 537err:
 538        return ret;
 539}
 540
 541static int dcbnl_getpfcstate(struct net_device *netdev, struct nlattr **tb,
 542                             u32 pid, u32 seq, u16 flags)
 543{
 544        int ret = -EINVAL;
 545
 546        if (!netdev->dcbnl_ops->getpfcstate)
 547                return ret;
 548
 549        ret = dcbnl_reply(netdev->dcbnl_ops->getpfcstate(netdev), RTM_GETDCB,
 550                          DCB_CMD_PFC_GSTATE, DCB_ATTR_PFC_STATE,
 551                          pid, seq, flags);
 552
 553        return ret;
 554}
 555
 556static int dcbnl_setpfcstate(struct net_device *netdev, struct nlattr **tb,
 557                             u32 pid, u32 seq, u16 flags)
 558{
 559        int ret = -EINVAL;
 560        u8 value;
 561
 562        if (!tb[DCB_ATTR_PFC_STATE] || !netdev->dcbnl_ops->setpfcstate)
 563                return ret;
 564
 565        value = nla_get_u8(tb[DCB_ATTR_PFC_STATE]);
 566
 567        netdev->dcbnl_ops->setpfcstate(netdev, value);
 568
 569        ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_PFC_SSTATE, DCB_ATTR_PFC_STATE,
 570                          pid, seq, flags);
 571
 572        return ret;
 573}
 574
 575static int dcbnl_getapp(struct net_device *netdev, struct nlattr **tb,
 576                        u32 pid, u32 seq, u16 flags)
 577{
 578        struct sk_buff *dcbnl_skb;
 579        struct nlmsghdr *nlh;
 580        struct dcbmsg *dcb;
 581        struct nlattr *app_nest;
 582        struct nlattr *app_tb[DCB_APP_ATTR_MAX + 1];
 583        u16 id;
 584        u8 up, idtype;
 585        int ret = -EINVAL;
 586
 587        if (!tb[DCB_ATTR_APP])
 588                goto out;
 589
 590        ret = nla_parse_nested(app_tb, DCB_APP_ATTR_MAX, tb[DCB_ATTR_APP],
 591                               dcbnl_app_nest);
 592        if (ret)
 593                goto out;
 594
 595        ret = -EINVAL;
 596        /* all must be non-null */
 597        if ((!app_tb[DCB_APP_ATTR_IDTYPE]) ||
 598            (!app_tb[DCB_APP_ATTR_ID]))
 599                goto out;
 600
 601        /* either by eth type or by socket number */
 602        idtype = nla_get_u8(app_tb[DCB_APP_ATTR_IDTYPE]);
 603        if ((idtype != DCB_APP_IDTYPE_ETHTYPE) &&
 604            (idtype != DCB_APP_IDTYPE_PORTNUM))
 605                goto out;
 606
 607        id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]);
 608
 609        if (netdev->dcbnl_ops->getapp) {
 610                up = netdev->dcbnl_ops->getapp(netdev, idtype, id);
 611        } else {
 612                struct dcb_app app = {
 613                                        .selector = idtype,
 614                                        .protocol = id,
 615                                     };
 616                up = dcb_getapp(netdev, &app);
 617        }
 618
 619        /* send this back */
 620        dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
 621        if (!dcbnl_skb)
 622                goto out;
 623
 624        nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
 625        dcb = NLMSG_DATA(nlh);
 626        dcb->dcb_family = AF_UNSPEC;
 627        dcb->cmd = DCB_CMD_GAPP;
 628
 629        app_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_APP);
 630        if (!app_nest)
 631                goto out_cancel;
 632
 633        ret = nla_put_u8(dcbnl_skb, DCB_APP_ATTR_IDTYPE, idtype);
 634        if (ret)
 635                goto out_cancel;
 636
 637        ret = nla_put_u16(dcbnl_skb, DCB_APP_ATTR_ID, id);
 638        if (ret)
 639                goto out_cancel;
 640
 641        ret = nla_put_u8(dcbnl_skb, DCB_APP_ATTR_PRIORITY, up);
 642        if (ret)
 643                goto out_cancel;
 644
 645        nla_nest_end(dcbnl_skb, app_nest);
 646        nlmsg_end(dcbnl_skb, nlh);
 647
 648        ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
 649        if (ret)
 650                goto nlmsg_failure;
 651
 652        goto out;
 653
 654out_cancel:
 655        nla_nest_cancel(dcbnl_skb, app_nest);
 656nlmsg_failure:
 657        kfree_skb(dcbnl_skb);
 658out:
 659        return ret;
 660}
 661
 662static int dcbnl_setapp(struct net_device *netdev, struct nlattr **tb,
 663                        u32 pid, u32 seq, u16 flags)
 664{
 665        int err, ret = -EINVAL;
 666        u16 id;
 667        u8 up, idtype;
 668        struct nlattr *app_tb[DCB_APP_ATTR_MAX + 1];
 669
 670        if (!tb[DCB_ATTR_APP])
 671                goto out;
 672
 673        ret = nla_parse_nested(app_tb, DCB_APP_ATTR_MAX, tb[DCB_ATTR_APP],
 674                               dcbnl_app_nest);
 675        if (ret)
 676                goto out;
 677
 678        ret = -EINVAL;
 679        /* all must be non-null */
 680        if ((!app_tb[DCB_APP_ATTR_IDTYPE]) ||
 681            (!app_tb[DCB_APP_ATTR_ID]) ||
 682            (!app_tb[DCB_APP_ATTR_PRIORITY]))
 683                goto out;
 684
 685        /* either by eth type or by socket number */
 686        idtype = nla_get_u8(app_tb[DCB_APP_ATTR_IDTYPE]);
 687        if ((idtype != DCB_APP_IDTYPE_ETHTYPE) &&
 688            (idtype != DCB_APP_IDTYPE_PORTNUM))
 689                goto out;
 690
 691        id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]);
 692        up = nla_get_u8(app_tb[DCB_APP_ATTR_PRIORITY]);
 693
 694        if (netdev->dcbnl_ops->setapp) {
 695                err = netdev->dcbnl_ops->setapp(netdev, idtype, id, up);
 696        } else {
 697                struct dcb_app app;
 698                app.selector = idtype;
 699                app.protocol = id;
 700                app.priority = up;
 701                err = dcb_setapp(netdev, &app);
 702        }
 703
 704        ret = dcbnl_reply(err, RTM_SETDCB, DCB_CMD_SAPP, DCB_ATTR_APP,
 705                          pid, seq, flags);
 706out:
 707        return ret;
 708}
 709
 710static int __dcbnl_pg_getcfg(struct net_device *netdev, struct nlattr **tb,
 711                             u32 pid, u32 seq, u16 flags, int dir)
 712{
 713        struct sk_buff *dcbnl_skb;
 714        struct nlmsghdr *nlh;
 715        struct dcbmsg *dcb;
 716        struct nlattr *pg_nest, *param_nest, *data;
 717        struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1];
 718        struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1];
 719        u8 prio, pgid, tc_pct, up_map;
 720        int ret  = -EINVAL;
 721        int getall = 0;
 722        int i;
 723
 724        if (!tb[DCB_ATTR_PG_CFG] ||
 725            !netdev->dcbnl_ops->getpgtccfgtx ||
 726            !netdev->dcbnl_ops->getpgtccfgrx ||
 727            !netdev->dcbnl_ops->getpgbwgcfgtx ||
 728            !netdev->dcbnl_ops->getpgbwgcfgrx)
 729                return ret;
 730
 731        ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX,
 732                               tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest);
 733
 734        if (ret)
 735                goto err_out;
 736
 737        dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
 738        if (!dcbnl_skb)
 739                goto err_out;
 740
 741        nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
 742
 743        dcb = NLMSG_DATA(nlh);
 744        dcb->dcb_family = AF_UNSPEC;
 745        dcb->cmd = (dir) ? DCB_CMD_PGRX_GCFG : DCB_CMD_PGTX_GCFG;
 746
 747        pg_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_PG_CFG);
 748        if (!pg_nest)
 749                goto err;
 750
 751        if (pg_tb[DCB_PG_ATTR_TC_ALL])
 752                getall = 1;
 753
 754        for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) {
 755                if (!getall && !pg_tb[i])
 756                        continue;
 757
 758                if (pg_tb[DCB_PG_ATTR_TC_ALL])
 759                        data = pg_tb[DCB_PG_ATTR_TC_ALL];
 760                else
 761                        data = pg_tb[i];
 762                ret = nla_parse_nested(param_tb, DCB_TC_ATTR_PARAM_MAX,
 763                                       data, dcbnl_tc_param_nest);
 764                if (ret)
 765                        goto err_pg;
 766
 767                param_nest = nla_nest_start(dcbnl_skb, i);
 768                if (!param_nest)
 769                        goto err_pg;
 770
 771                pgid = DCB_ATTR_VALUE_UNDEFINED;
 772                prio = DCB_ATTR_VALUE_UNDEFINED;
 773                tc_pct = DCB_ATTR_VALUE_UNDEFINED;
 774                up_map = DCB_ATTR_VALUE_UNDEFINED;
 775
 776                if (dir) {
 777                        /* Rx */
 778                        netdev->dcbnl_ops->getpgtccfgrx(netdev,
 779                                                i - DCB_PG_ATTR_TC_0, &prio,
 780                                                &pgid, &tc_pct, &up_map);
 781                } else {
 782                        /* Tx */
 783                        netdev->dcbnl_ops->getpgtccfgtx(netdev,
 784                                                i - DCB_PG_ATTR_TC_0, &prio,
 785                                                &pgid, &tc_pct, &up_map);
 786                }
 787
 788                if (param_tb[DCB_TC_ATTR_PARAM_PGID] ||
 789                    param_tb[DCB_TC_ATTR_PARAM_ALL]) {
 790                        ret = nla_put_u8(dcbnl_skb,
 791                                         DCB_TC_ATTR_PARAM_PGID, pgid);
 792                        if (ret)
 793                                goto err_param;
 794                }
 795                if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING] ||
 796                    param_tb[DCB_TC_ATTR_PARAM_ALL]) {
 797                        ret = nla_put_u8(dcbnl_skb,
 798                                         DCB_TC_ATTR_PARAM_UP_MAPPING, up_map);
 799                        if (ret)
 800                                goto err_param;
 801                }
 802                if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO] ||
 803                    param_tb[DCB_TC_ATTR_PARAM_ALL]) {
 804                        ret = nla_put_u8(dcbnl_skb,
 805                                         DCB_TC_ATTR_PARAM_STRICT_PRIO, prio);
 806                        if (ret)
 807                                goto err_param;
 808                }
 809                if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT] ||
 810                    param_tb[DCB_TC_ATTR_PARAM_ALL]) {
 811                        ret = nla_put_u8(dcbnl_skb, DCB_TC_ATTR_PARAM_BW_PCT,
 812                                         tc_pct);
 813                        if (ret)
 814                                goto err_param;
 815                }
 816                nla_nest_end(dcbnl_skb, param_nest);
 817        }
 818
 819        if (pg_tb[DCB_PG_ATTR_BW_ID_ALL])
 820                getall = 1;
 821        else
 822                getall = 0;
 823
 824        for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) {
 825                if (!getall && !pg_tb[i])
 826                        continue;
 827
 828                tc_pct = DCB_ATTR_VALUE_UNDEFINED;
 829
 830                if (dir) {
 831                        /* Rx */
 832                        netdev->dcbnl_ops->getpgbwgcfgrx(netdev,
 833                                        i - DCB_PG_ATTR_BW_ID_0, &tc_pct);
 834                } else {
 835                        /* Tx */
 836                        netdev->dcbnl_ops->getpgbwgcfgtx(netdev,
 837                                        i - DCB_PG_ATTR_BW_ID_0, &tc_pct);
 838                }
 839                ret = nla_put_u8(dcbnl_skb, i, tc_pct);
 840
 841                if (ret)
 842                        goto err_pg;
 843        }
 844
 845        nla_nest_end(dcbnl_skb, pg_nest);
 846
 847        nlmsg_end(dcbnl_skb, nlh);
 848
 849        ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
 850        if (ret)
 851                goto err_out;
 852
 853        return 0;
 854
 855err_param:
 856        nla_nest_cancel(dcbnl_skb, param_nest);
 857err_pg:
 858        nla_nest_cancel(dcbnl_skb, pg_nest);
 859nlmsg_failure:
 860err:
 861        kfree_skb(dcbnl_skb);
 862err_out:
 863        ret  = -EINVAL;
 864        return ret;
 865}
 866
 867static int dcbnl_pgtx_getcfg(struct net_device *netdev, struct nlattr **tb,
 868                             u32 pid, u32 seq, u16 flags)
 869{
 870        return __dcbnl_pg_getcfg(netdev, tb, pid, seq, flags, 0);
 871}
 872
 873static int dcbnl_pgrx_getcfg(struct net_device *netdev, struct nlattr **tb,
 874                             u32 pid, u32 seq, u16 flags)
 875{
 876        return __dcbnl_pg_getcfg(netdev, tb, pid, seq, flags, 1);
 877}
 878
 879static int dcbnl_setstate(struct net_device *netdev, struct nlattr **tb,
 880                          u32 pid, u32 seq, u16 flags)
 881{
 882        int ret = -EINVAL;
 883        u8 value;
 884
 885        if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->setstate)
 886                return ret;
 887
 888        value = nla_get_u8(tb[DCB_ATTR_STATE]);
 889
 890        ret = dcbnl_reply(netdev->dcbnl_ops->setstate(netdev, value),
 891                          RTM_SETDCB, DCB_CMD_SSTATE, DCB_ATTR_STATE,
 892                          pid, seq, flags);
 893
 894        return ret;
 895}
 896
 897static int dcbnl_setpfccfg(struct net_device *netdev, struct nlattr **tb,
 898                           u32 pid, u32 seq, u16 flags)
 899{
 900        struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1];
 901        int i;
 902        int ret = -EINVAL;
 903        u8 value;
 904
 905        if (!tb[DCB_ATTR_PFC_CFG] || !netdev->dcbnl_ops->setpfccfg)
 906                return ret;
 907
 908        ret = nla_parse_nested(data, DCB_PFC_UP_ATTR_MAX,
 909                               tb[DCB_ATTR_PFC_CFG],
 910                               dcbnl_pfc_up_nest);
 911        if (ret)
 912                goto err;
 913
 914        for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) {
 915                if (data[i] == NULL)
 916                        continue;
 917                value = nla_get_u8(data[i]);
 918                netdev->dcbnl_ops->setpfccfg(netdev,
 919                        data[i]->nla_type - DCB_PFC_UP_ATTR_0, value);
 920        }
 921
 922        ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_PFC_SCFG, DCB_ATTR_PFC_CFG,
 923                          pid, seq, flags);
 924err:
 925        return ret;
 926}
 927
 928static int dcbnl_setall(struct net_device *netdev, struct nlattr **tb,
 929                        u32 pid, u32 seq, u16 flags)
 930{
 931        int ret = -EINVAL;
 932
 933        if (!tb[DCB_ATTR_SET_ALL] || !netdev->dcbnl_ops->setall)
 934                return ret;
 935
 936        ret = dcbnl_reply(netdev->dcbnl_ops->setall(netdev), RTM_SETDCB,
 937                          DCB_CMD_SET_ALL, DCB_ATTR_SET_ALL, pid, seq, flags);
 938
 939        return ret;
 940}
 941
 942static int __dcbnl_pg_setcfg(struct net_device *netdev, struct nlattr **tb,
 943                             u32 pid, u32 seq, u16 flags, int dir)
 944{
 945        struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1];
 946        struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1];
 947        int ret = -EINVAL;
 948        int i;
 949        u8 pgid;
 950        u8 up_map;
 951        u8 prio;
 952        u8 tc_pct;
 953
 954        if (!tb[DCB_ATTR_PG_CFG] ||
 955            !netdev->dcbnl_ops->setpgtccfgtx ||
 956            !netdev->dcbnl_ops->setpgtccfgrx ||
 957            !netdev->dcbnl_ops->setpgbwgcfgtx ||
 958            !netdev->dcbnl_ops->setpgbwgcfgrx)
 959                return ret;
 960
 961        ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX,
 962                               tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest);
 963        if (ret)
 964                goto err;
 965
 966        for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) {
 967                if (!pg_tb[i])
 968                        continue;
 969
 970                ret = nla_parse_nested(param_tb, DCB_TC_ATTR_PARAM_MAX,
 971                                       pg_tb[i], dcbnl_tc_param_nest);
 972                if (ret)
 973                        goto err;
 974
 975                pgid = DCB_ATTR_VALUE_UNDEFINED;
 976                prio = DCB_ATTR_VALUE_UNDEFINED;
 977                tc_pct = DCB_ATTR_VALUE_UNDEFINED;
 978                up_map = DCB_ATTR_VALUE_UNDEFINED;
 979
 980                if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO])
 981                        prio =
 982                            nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO]);
 983
 984                if (param_tb[DCB_TC_ATTR_PARAM_PGID])
 985                        pgid = nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_PGID]);
 986
 987                if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT])
 988                        tc_pct = nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_BW_PCT]);
 989
 990                if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING])
 991                        up_map =
 992                             nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING]);
 993
 994                /* dir: Tx = 0, Rx = 1 */
 995                if (dir) {
 996                        /* Rx */
 997                        netdev->dcbnl_ops->setpgtccfgrx(netdev,
 998                                i - DCB_PG_ATTR_TC_0,
 999                                prio, pgid, tc_pct, up_map);
1000                } else {
1001                        /* Tx */
1002                        netdev->dcbnl_ops->setpgtccfgtx(netdev,
1003                                i - DCB_PG_ATTR_TC_0,
1004                                prio, pgid, tc_pct, up_map);
1005                }
1006        }
1007
1008        for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) {
1009                if (!pg_tb[i])
1010                        continue;
1011
1012                tc_pct = nla_get_u8(pg_tb[i]);
1013
1014                /* dir: Tx = 0, Rx = 1 */
1015                if (dir) {
1016                        /* Rx */
1017                        netdev->dcbnl_ops->setpgbwgcfgrx(netdev,
1018                                         i - DCB_PG_ATTR_BW_ID_0, tc_pct);
1019                } else {
1020                        /* Tx */
1021                        netdev->dcbnl_ops->setpgbwgcfgtx(netdev,
1022                                         i - DCB_PG_ATTR_BW_ID_0, tc_pct);
1023                }
1024        }
1025
1026        ret = dcbnl_reply(0, RTM_SETDCB,
1027                          (dir ? DCB_CMD_PGRX_SCFG : DCB_CMD_PGTX_SCFG),
1028                          DCB_ATTR_PG_CFG, pid, seq, flags);
1029
1030err:
1031        return ret;
1032}
1033
1034static int dcbnl_pgtx_setcfg(struct net_device *netdev, struct nlattr **tb,
1035                             u32 pid, u32 seq, u16 flags)
1036{
1037        return __dcbnl_pg_setcfg(netdev, tb, pid, seq, flags, 0);
1038}
1039
1040static int dcbnl_pgrx_setcfg(struct net_device *netdev, struct nlattr **tb,
1041                             u32 pid, u32 seq, u16 flags)
1042{
1043        return __dcbnl_pg_setcfg(netdev, tb, pid, seq, flags, 1);
1044}
1045
1046static int dcbnl_bcn_getcfg(struct net_device *netdev, struct nlattr **tb,
1047                            u32 pid, u32 seq, u16 flags)
1048{
1049        struct sk_buff *dcbnl_skb;
1050        struct nlmsghdr *nlh;
1051        struct dcbmsg *dcb;
1052        struct nlattr *bcn_nest;
1053        struct nlattr *bcn_tb[DCB_BCN_ATTR_MAX + 1];
1054        u8 value_byte;
1055        u32 value_integer;
1056        int ret  = -EINVAL;
1057        bool getall = false;
1058        int i;
1059
1060        if (!tb[DCB_ATTR_BCN] || !netdev->dcbnl_ops->getbcnrp ||
1061            !netdev->dcbnl_ops->getbcncfg)
1062                return ret;
1063
1064        ret = nla_parse_nested(bcn_tb, DCB_BCN_ATTR_MAX,
1065                               tb[DCB_ATTR_BCN], dcbnl_bcn_nest);
1066
1067        if (ret)
1068                goto err_out;
1069
1070        dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1071        if (!dcbnl_skb)
1072                goto err_out;
1073
1074        nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
1075
1076        dcb = NLMSG_DATA(nlh);
1077        dcb->dcb_family = AF_UNSPEC;
1078        dcb->cmd = DCB_CMD_BCN_GCFG;
1079
1080        bcn_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_BCN);
1081        if (!bcn_nest)
1082                goto err;
1083
1084        if (bcn_tb[DCB_BCN_ATTR_ALL])
1085                getall = true;
1086
1087        for (i = DCB_BCN_ATTR_RP_0; i <= DCB_BCN_ATTR_RP_7; i++) {
1088                if (!getall && !bcn_tb[i])
1089                        continue;
1090
1091                netdev->dcbnl_ops->getbcnrp(netdev, i - DCB_BCN_ATTR_RP_0,
1092                                            &value_byte);
1093                ret = nla_put_u8(dcbnl_skb, i, value_byte);
1094                if (ret)
1095                        goto err_bcn;
1096        }
1097
1098        for (i = DCB_BCN_ATTR_BCNA_0; i <= DCB_BCN_ATTR_RI; i++) {
1099                if (!getall && !bcn_tb[i])
1100                        continue;
1101
1102                netdev->dcbnl_ops->getbcncfg(netdev, i,
1103                                             &value_integer);
1104                ret = nla_put_u32(dcbnl_skb, i, value_integer);
1105                if (ret)
1106                        goto err_bcn;
1107        }
1108
1109        nla_nest_end(dcbnl_skb, bcn_nest);
1110
1111        nlmsg_end(dcbnl_skb, nlh);
1112
1113        ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
1114        if (ret)
1115                goto err_out;
1116
1117        return 0;
1118
1119err_bcn:
1120        nla_nest_cancel(dcbnl_skb, bcn_nest);
1121nlmsg_failure:
1122err:
1123        kfree_skb(dcbnl_skb);
1124err_out:
1125        ret  = -EINVAL;
1126        return ret;
1127}
1128
1129static int dcbnl_bcn_setcfg(struct net_device *netdev, struct nlattr **tb,
1130                            u32 pid, u32 seq, u16 flags)
1131{
1132        struct nlattr *data[DCB_BCN_ATTR_MAX + 1];
1133        int i;
1134        int ret = -EINVAL;
1135        u8 value_byte;
1136        u32 value_int;
1137
1138        if (!tb[DCB_ATTR_BCN] || !netdev->dcbnl_ops->setbcncfg ||
1139            !netdev->dcbnl_ops->setbcnrp)
1140                return ret;
1141
1142        ret = nla_parse_nested(data, DCB_BCN_ATTR_MAX,
1143                               tb[DCB_ATTR_BCN],
1144                               dcbnl_pfc_up_nest);
1145        if (ret)
1146                goto err;
1147
1148        for (i = DCB_BCN_ATTR_RP_0; i <= DCB_BCN_ATTR_RP_7; i++) {
1149                if (data[i] == NULL)
1150                        continue;
1151                value_byte = nla_get_u8(data[i]);
1152                netdev->dcbnl_ops->setbcnrp(netdev,
1153                        data[i]->nla_type - DCB_BCN_ATTR_RP_0, value_byte);
1154        }
1155
1156        for (i = DCB_BCN_ATTR_BCNA_0; i <= DCB_BCN_ATTR_RI; i++) {
1157                if (data[i] == NULL)
1158                        continue;
1159                value_int = nla_get_u32(data[i]);
1160                netdev->dcbnl_ops->setbcncfg(netdev,
1161                                             i, value_int);
1162        }
1163
1164        ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_BCN_SCFG, DCB_ATTR_BCN,
1165                          pid, seq, flags);
1166err:
1167        return ret;
1168}
1169
1170static int dcbnl_build_peer_app(struct net_device *netdev, struct sk_buff* skb,
1171                                int app_nested_type, int app_info_type,
1172                                int app_entry_type)
1173{
1174        struct dcb_peer_app_info info;
1175        struct dcb_app *table = NULL;
1176        const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
1177        u16 app_count;
1178        int err;
1179
1180
1181        /**
1182         * retrieve the peer app configuration form the driver. If the driver
1183         * handlers fail exit without doing anything
1184         */
1185        err = ops->peer_getappinfo(netdev, &info, &app_count);
1186        if (!err && app_count) {
1187                table = kmalloc(sizeof(struct dcb_app) * app_count, GFP_KERNEL);
1188                if (!table)
1189                        return -ENOMEM;
1190
1191                err = ops->peer_getapptable(netdev, table);
1192        }
1193
1194        if (!err) {
1195                u16 i;
1196                struct nlattr *app;
1197
1198                /**
1199                 * build the message, from here on the only possible failure
1200                 * is due to the skb size
1201                 */
1202                err = -EMSGSIZE;
1203
1204                app = nla_nest_start(skb, app_nested_type);
1205                if (!app)
1206                        goto nla_put_failure;
1207
1208                if (app_info_type)
1209                        NLA_PUT(skb, app_info_type, sizeof(info), &info);
1210
1211                for (i = 0; i < app_count; i++)
1212                        NLA_PUT(skb, app_entry_type, sizeof(struct dcb_app),
1213                                &table[i]);
1214
1215                nla_nest_end(skb, app);
1216        }
1217        err = 0;
1218
1219nla_put_failure:
1220        kfree(table);
1221        return err;
1222}
1223
1224/* Handle IEEE 802.1Qaz GET commands. */
1225static int dcbnl_ieee_fill(struct sk_buff *skb, struct net_device *netdev)
1226{
1227        struct nlattr *ieee, *app;
1228        struct dcb_app_type *itr;
1229        const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
1230        int dcbx;
1231        int err = -EMSGSIZE;
1232
1233        NLA_PUT_STRING(skb, DCB_ATTR_IFNAME, netdev->name);
1234
1235        ieee = nla_nest_start(skb, DCB_ATTR_IEEE);
1236        if (!ieee)
1237                goto nla_put_failure;
1238
1239        if (ops->ieee_getets) {
1240                struct ieee_ets ets;
1241                err = ops->ieee_getets(netdev, &ets);
1242                if (!err)
1243                        NLA_PUT(skb, DCB_ATTR_IEEE_ETS, sizeof(ets), &ets);
1244        }
1245
1246        if (ops->ieee_getpfc) {
1247                struct ieee_pfc pfc;
1248                err = ops->ieee_getpfc(netdev, &pfc);
1249                if (!err)
1250                        NLA_PUT(skb, DCB_ATTR_IEEE_PFC, sizeof(pfc), &pfc);
1251        }
1252
1253        app = nla_nest_start(skb, DCB_ATTR_IEEE_APP_TABLE);
1254        if (!app)
1255                goto nla_put_failure;
1256
1257        spin_lock(&dcb_lock);
1258        list_for_each_entry(itr, &dcb_app_list, list) {
1259                if (itr->ifindex == netdev->ifindex) {
1260                        err = nla_put(skb, DCB_ATTR_IEEE_APP, sizeof(itr->app),
1261                                         &itr->app);
1262                        if (err) {
1263                                spin_unlock(&dcb_lock);
1264                                goto nla_put_failure;
1265                        }
1266                }
1267        }
1268
1269        if (netdev->dcbnl_ops->getdcbx)
1270                dcbx = netdev->dcbnl_ops->getdcbx(netdev);
1271        else
1272                dcbx = -EOPNOTSUPP;
1273
1274        spin_unlock(&dcb_lock);
1275        nla_nest_end(skb, app);
1276
1277        /* get peer info if available */
1278        if (ops->ieee_peer_getets) {
1279                struct ieee_ets ets;
1280                err = ops->ieee_peer_getets(netdev, &ets);
1281                if (!err)
1282                        NLA_PUT(skb, DCB_ATTR_IEEE_PEER_ETS, sizeof(ets), &ets);
1283        }
1284
1285        if (ops->ieee_peer_getpfc) {
1286                struct ieee_pfc pfc;
1287                err = ops->ieee_peer_getpfc(netdev, &pfc);
1288                if (!err)
1289                        NLA_PUT(skb, DCB_ATTR_IEEE_PEER_PFC, sizeof(pfc), &pfc);
1290        }
1291
1292        if (ops->peer_getappinfo && ops->peer_getapptable) {
1293                err = dcbnl_build_peer_app(netdev, skb,
1294                                           DCB_ATTR_IEEE_PEER_APP,
1295                                           DCB_ATTR_IEEE_APP_UNSPEC,
1296                                           DCB_ATTR_IEEE_APP);
1297                if (err)
1298                        goto nla_put_failure;
1299        }
1300
1301        nla_nest_end(skb, ieee);
1302        if (dcbx >= 0) {
1303                err = nla_put_u8(skb, DCB_ATTR_DCBX, dcbx);
1304                if (err)
1305                        goto nla_put_failure;
1306        }
1307
1308        return 0;
1309
1310nla_put_failure:
1311        return err;
1312}
1313
1314static int dcbnl_cee_pg_fill(struct sk_buff *skb, struct net_device *dev,
1315                             int dir)
1316{
1317        u8 pgid, up_map, prio, tc_pct;
1318        const struct dcbnl_rtnl_ops *ops = dev->dcbnl_ops;
1319        int i = dir ? DCB_ATTR_CEE_TX_PG : DCB_ATTR_CEE_RX_PG;
1320        struct nlattr *pg = nla_nest_start(skb, i);
1321
1322        if (!pg)
1323                goto nla_put_failure;
1324
1325        for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) {
1326                struct nlattr *tc_nest = nla_nest_start(skb, i);
1327
1328                if (!tc_nest)
1329                        goto nla_put_failure;
1330
1331                pgid = DCB_ATTR_VALUE_UNDEFINED;
1332                prio = DCB_ATTR_VALUE_UNDEFINED;
1333                tc_pct = DCB_ATTR_VALUE_UNDEFINED;
1334                up_map = DCB_ATTR_VALUE_UNDEFINED;
1335
1336                if (!dir)
1337                        ops->getpgtccfgrx(dev, i - DCB_PG_ATTR_TC_0,
1338                                          &prio, &pgid, &tc_pct, &up_map);
1339                else
1340                        ops->getpgtccfgtx(dev, i - DCB_PG_ATTR_TC_0,
1341                                          &prio, &pgid, &tc_pct, &up_map);
1342
1343                NLA_PUT_U8(skb, DCB_TC_ATTR_PARAM_PGID, pgid);
1344                NLA_PUT_U8(skb, DCB_TC_ATTR_PARAM_UP_MAPPING, up_map);
1345                NLA_PUT_U8(skb, DCB_TC_ATTR_PARAM_STRICT_PRIO, prio);
1346                NLA_PUT_U8(skb, DCB_TC_ATTR_PARAM_BW_PCT, tc_pct);
1347                nla_nest_end(skb, tc_nest);
1348        }
1349
1350        for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) {
1351                tc_pct = DCB_ATTR_VALUE_UNDEFINED;
1352
1353                if (!dir)
1354                        ops->getpgbwgcfgrx(dev, i - DCB_PG_ATTR_BW_ID_0,
1355                                           &tc_pct);
1356                else
1357                        ops->getpgbwgcfgtx(dev, i - DCB_PG_ATTR_BW_ID_0,
1358                                           &tc_pct);
1359                NLA_PUT_U8(skb, i, tc_pct);
1360        }
1361        nla_nest_end(skb, pg);
1362        return 0;
1363
1364nla_put_failure:
1365        return -EMSGSIZE;
1366}
1367
1368static int dcbnl_cee_fill(struct sk_buff *skb, struct net_device *netdev)
1369{
1370        struct nlattr *cee, *app;
1371        struct dcb_app_type *itr;
1372        const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
1373        int dcbx, i, err = -EMSGSIZE;
1374        u8 value;
1375
1376        NLA_PUT_STRING(skb, DCB_ATTR_IFNAME, netdev->name);
1377
1378        cee = nla_nest_start(skb, DCB_ATTR_CEE);
1379        if (!cee)
1380                goto nla_put_failure;
1381
1382        /* local pg */
1383        if (ops->getpgtccfgtx && ops->getpgbwgcfgtx) {
1384                err = dcbnl_cee_pg_fill(skb, netdev, 1);
1385                if (err)
1386                        goto nla_put_failure;
1387        }
1388
1389        if (ops->getpgtccfgrx && ops->getpgbwgcfgrx) {
1390                err = dcbnl_cee_pg_fill(skb, netdev, 0);
1391                if (err)
1392                        goto nla_put_failure;
1393        }
1394
1395        /* local pfc */
1396        if (ops->getpfccfg) {
1397                struct nlattr *pfc_nest = nla_nest_start(skb, DCB_ATTR_CEE_PFC);
1398
1399                if (!pfc_nest)
1400                        goto nla_put_failure;
1401
1402                for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) {
1403                        ops->getpfccfg(netdev, i - DCB_PFC_UP_ATTR_0, &value);
1404                        NLA_PUT_U8(skb, i, value);
1405                }
1406                nla_nest_end(skb, pfc_nest);
1407        }
1408
1409        /* local app */
1410        spin_lock(&dcb_lock);
1411        app = nla_nest_start(skb, DCB_ATTR_CEE_APP_TABLE);
1412        if (!app)
1413                goto dcb_unlock;
1414
1415        list_for_each_entry(itr, &dcb_app_list, list) {
1416                if (itr->ifindex == netdev->ifindex) {
1417                        struct nlattr *app_nest = nla_nest_start(skb,
1418                                                                 DCB_ATTR_APP);
1419                        if (!app_nest)
1420                                goto dcb_unlock;
1421
1422                        err = nla_put_u8(skb, DCB_APP_ATTR_IDTYPE,
1423                                         itr->app.selector);
1424                        if (err)
1425                                goto dcb_unlock;
1426
1427                        err = nla_put_u16(skb, DCB_APP_ATTR_ID,
1428                                          itr->app.protocol);
1429                        if (err)
1430                                goto dcb_unlock;
1431
1432                        err = nla_put_u8(skb, DCB_APP_ATTR_PRIORITY,
1433                                         itr->app.priority);
1434                        if (err)
1435                                goto dcb_unlock;
1436
1437                        nla_nest_end(skb, app_nest);
1438                }
1439        }
1440        nla_nest_end(skb, app);
1441
1442        if (netdev->dcbnl_ops->getdcbx)
1443                dcbx = netdev->dcbnl_ops->getdcbx(netdev);
1444        else
1445                dcbx = -EOPNOTSUPP;
1446
1447        spin_unlock(&dcb_lock);
1448
1449        /* features flags */
1450        if (ops->getfeatcfg) {
1451                struct nlattr *feat = nla_nest_start(skb, DCB_ATTR_CEE_FEAT);
1452                if (!feat)
1453                        goto nla_put_failure;
1454
1455                for (i = DCB_FEATCFG_ATTR_ALL + 1; i <= DCB_FEATCFG_ATTR_MAX;
1456                     i++)
1457                        if (!ops->getfeatcfg(netdev, i, &value))
1458                                NLA_PUT_U8(skb, i, value);
1459
1460                nla_nest_end(skb, feat);
1461        }
1462
1463        /* peer info if available */
1464        if (ops->cee_peer_getpg) {
1465                struct cee_pg pg;
1466                err = ops->cee_peer_getpg(netdev, &pg);
1467                if (!err)
1468                        NLA_PUT(skb, DCB_ATTR_CEE_PEER_PG, sizeof(pg), &pg);
1469        }
1470
1471        if (ops->cee_peer_getpfc) {
1472                struct cee_pfc pfc;
1473                err = ops->cee_peer_getpfc(netdev, &pfc);
1474                if (!err)
1475                        NLA_PUT(skb, DCB_ATTR_CEE_PEER_PFC, sizeof(pfc), &pfc);
1476        }
1477
1478        if (ops->peer_getappinfo && ops->peer_getapptable) {
1479                err = dcbnl_build_peer_app(netdev, skb,
1480                                           DCB_ATTR_CEE_PEER_APP_TABLE,
1481                                           DCB_ATTR_CEE_PEER_APP_INFO,
1482                                           DCB_ATTR_CEE_PEER_APP);
1483                if (err)
1484                        goto nla_put_failure;
1485        }
1486        nla_nest_end(skb, cee);
1487
1488        /* DCBX state */
1489        if (dcbx >= 0) {
1490                err = nla_put_u8(skb, DCB_ATTR_DCBX, dcbx);
1491                if (err)
1492                        goto nla_put_failure;
1493        }
1494        return 0;
1495
1496dcb_unlock:
1497        spin_unlock(&dcb_lock);
1498nla_put_failure:
1499        return err;
1500}
1501
1502static int dcbnl_notify(struct net_device *dev, int event, int cmd,
1503                        u32 seq, u32 pid, int dcbx_ver)
1504{
1505        struct net *net = dev_net(dev);
1506        struct sk_buff *skb;
1507        struct nlmsghdr *nlh;
1508        struct dcbmsg *dcb;
1509        const struct dcbnl_rtnl_ops *ops = dev->dcbnl_ops;
1510        int err;
1511
1512        if (!ops)
1513                return -EOPNOTSUPP;
1514
1515        skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1516        if (!skb)
1517                return -ENOBUFS;
1518
1519        nlh = nlmsg_put(skb, pid, 0, event, sizeof(*dcb), 0);
1520        if (nlh == NULL) {
1521                nlmsg_free(skb);
1522                return -EMSGSIZE;
1523        }
1524
1525        dcb = NLMSG_DATA(nlh);
1526        dcb->dcb_family = AF_UNSPEC;
1527        dcb->cmd = cmd;
1528
1529        if (dcbx_ver == DCB_CAP_DCBX_VER_IEEE)
1530                err = dcbnl_ieee_fill(skb, dev);
1531        else
1532                err = dcbnl_cee_fill(skb, dev);
1533
1534        if (err < 0) {
1535                /* Report error to broadcast listeners */
1536                nlmsg_cancel(skb, nlh);
1537                kfree_skb(skb);
1538                rtnl_set_sk_err(net, RTNLGRP_DCB, err);
1539        } else {
1540                /* End nlmsg and notify broadcast listeners */
1541                nlmsg_end(skb, nlh);
1542                rtnl_notify(skb, net, 0, RTNLGRP_DCB, NULL, GFP_KERNEL);
1543        }
1544
1545        return err;
1546}
1547
1548int dcbnl_ieee_notify(struct net_device *dev, int event, int cmd,
1549                      u32 seq, u32 pid)
1550{
1551        return dcbnl_notify(dev, event, cmd, seq, pid, DCB_CAP_DCBX_VER_IEEE);
1552}
1553EXPORT_SYMBOL(dcbnl_ieee_notify);
1554
1555int dcbnl_cee_notify(struct net_device *dev, int event, int cmd,
1556                     u32 seq, u32 pid)
1557{
1558        return dcbnl_notify(dev, event, cmd, seq, pid, DCB_CAP_DCBX_VER_CEE);
1559}
1560EXPORT_SYMBOL(dcbnl_cee_notify);
1561
1562/* Handle IEEE 802.1Qaz SET commands. If any requested operation can not
1563 * be completed the entire msg is aborted and error value is returned.
1564 * No attempt is made to reconcile the case where only part of the
1565 * cmd can be completed.
1566 */
1567static int dcbnl_ieee_set(struct net_device *netdev, struct nlattr **tb,
1568                          u32 pid, u32 seq, u16 flags)
1569{
1570        const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
1571        struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1];
1572        int err = -EOPNOTSUPP;
1573
1574        if (!ops)
1575                return err;
1576
1577        if (!tb[DCB_ATTR_IEEE])
1578                return -EINVAL;
1579
1580        err = nla_parse_nested(ieee, DCB_ATTR_IEEE_MAX,
1581                               tb[DCB_ATTR_IEEE], dcbnl_ieee_policy);
1582        if (err)
1583                return err;
1584
1585        if (ieee[DCB_ATTR_IEEE_ETS] && ops->ieee_setets) {
1586                struct ieee_ets *ets = nla_data(ieee[DCB_ATTR_IEEE_ETS]);
1587                err = ops->ieee_setets(netdev, ets);
1588                if (err)
1589                        goto err;
1590        }
1591
1592        if (ieee[DCB_ATTR_IEEE_PFC] && ops->ieee_setpfc) {
1593                struct ieee_pfc *pfc = nla_data(ieee[DCB_ATTR_IEEE_PFC]);
1594                err = ops->ieee_setpfc(netdev, pfc);
1595                if (err)
1596                        goto err;
1597        }
1598
1599        if (ieee[DCB_ATTR_IEEE_APP_TABLE]) {
1600                struct nlattr *attr;
1601                int rem;
1602
1603                nla_for_each_nested(attr, ieee[DCB_ATTR_IEEE_APP_TABLE], rem) {
1604                        struct dcb_app *app_data;
1605                        if (nla_type(attr) != DCB_ATTR_IEEE_APP)
1606                                continue;
1607                        app_data = nla_data(attr);
1608                        if (ops->ieee_setapp)
1609                                err = ops->ieee_setapp(netdev, app_data);
1610                        else
1611                                err = dcb_ieee_setapp(netdev, app_data);
1612                        if (err)
1613                                goto err;
1614                }
1615        }
1616
1617err:
1618        dcbnl_reply(err, RTM_SETDCB, DCB_CMD_IEEE_SET, DCB_ATTR_IEEE,
1619                    pid, seq, flags);
1620        dcbnl_ieee_notify(netdev, RTM_SETDCB, DCB_CMD_IEEE_SET, seq, 0);
1621        return err;
1622}
1623
1624static int dcbnl_ieee_get(struct net_device *netdev, struct nlattr **tb,
1625                          u32 pid, u32 seq, u16 flags)
1626{
1627        struct net *net = dev_net(netdev);
1628        struct sk_buff *skb;
1629        struct nlmsghdr *nlh;
1630        struct dcbmsg *dcb;
1631        const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
1632        int err;
1633
1634        if (!ops)
1635                return -EOPNOTSUPP;
1636
1637        skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1638        if (!skb)
1639                return -ENOBUFS;
1640
1641        nlh = nlmsg_put(skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
1642        if (nlh == NULL) {
1643                nlmsg_free(skb);
1644                return -EMSGSIZE;
1645        }
1646
1647        dcb = NLMSG_DATA(nlh);
1648        dcb->dcb_family = AF_UNSPEC;
1649        dcb->cmd = DCB_CMD_IEEE_GET;
1650
1651        err = dcbnl_ieee_fill(skb, netdev);
1652
1653        if (err < 0) {
1654                nlmsg_cancel(skb, nlh);
1655                kfree_skb(skb);
1656        } else {
1657                nlmsg_end(skb, nlh);
1658                err = rtnl_unicast(skb, net, pid);
1659        }
1660
1661        return err;
1662}
1663
1664static int dcbnl_ieee_del(struct net_device *netdev, struct nlattr **tb,
1665                          u32 pid, u32 seq, u16 flags)
1666{
1667        const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
1668        struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1];
1669        int err = -EOPNOTSUPP;
1670
1671        if (!ops)
1672                return -EOPNOTSUPP;
1673
1674        if (!tb[DCB_ATTR_IEEE])
1675                return -EINVAL;
1676
1677        err = nla_parse_nested(ieee, DCB_ATTR_IEEE_MAX,
1678                               tb[DCB_ATTR_IEEE], dcbnl_ieee_policy);
1679        if (err)
1680                return err;
1681
1682        if (ieee[DCB_ATTR_IEEE_APP_TABLE]) {
1683                struct nlattr *attr;
1684                int rem;
1685
1686                nla_for_each_nested(attr, ieee[DCB_ATTR_IEEE_APP_TABLE], rem) {
1687                        struct dcb_app *app_data;
1688
1689                        if (nla_type(attr) != DCB_ATTR_IEEE_APP)
1690                                continue;
1691                        app_data = nla_data(attr);
1692                        if (ops->ieee_delapp)
1693                                err = ops->ieee_delapp(netdev, app_data);
1694                        else
1695                                err = dcb_ieee_delapp(netdev, app_data);
1696                        if (err)
1697                                goto err;
1698                }
1699        }
1700
1701err:
1702        dcbnl_reply(err, RTM_SETDCB, DCB_CMD_IEEE_DEL, DCB_ATTR_IEEE,
1703                    pid, seq, flags);
1704        dcbnl_ieee_notify(netdev, RTM_SETDCB, DCB_CMD_IEEE_DEL, seq, 0);
1705        return err;
1706}
1707
1708
1709/* DCBX configuration */
1710static int dcbnl_getdcbx(struct net_device *netdev, struct nlattr **tb,
1711                         u32 pid, u32 seq, u16 flags)
1712{
1713        int ret;
1714
1715        if (!netdev->dcbnl_ops->getdcbx)
1716                return -EOPNOTSUPP;
1717
1718        ret = dcbnl_reply(netdev->dcbnl_ops->getdcbx(netdev), RTM_GETDCB,
1719                          DCB_CMD_GDCBX, DCB_ATTR_DCBX, pid, seq, flags);
1720
1721        return ret;
1722}
1723
1724static int dcbnl_setdcbx(struct net_device *netdev, struct nlattr **tb,
1725                         u32 pid, u32 seq, u16 flags)
1726{
1727        int ret;
1728        u8 value;
1729
1730        if (!netdev->dcbnl_ops->setdcbx)
1731                return -EOPNOTSUPP;
1732
1733        if (!tb[DCB_ATTR_DCBX])
1734                return -EINVAL;
1735
1736        value = nla_get_u8(tb[DCB_ATTR_DCBX]);
1737
1738        ret = dcbnl_reply(netdev->dcbnl_ops->setdcbx(netdev, value),
1739                          RTM_SETDCB, DCB_CMD_SDCBX, DCB_ATTR_DCBX,
1740                          pid, seq, flags);
1741
1742        return ret;
1743}
1744
1745static int dcbnl_getfeatcfg(struct net_device *netdev, struct nlattr **tb,
1746                            u32 pid, u32 seq, u16 flags)
1747{
1748        struct sk_buff *dcbnl_skb;
1749        struct nlmsghdr *nlh;
1750        struct dcbmsg *dcb;
1751        struct nlattr *data[DCB_FEATCFG_ATTR_MAX + 1], *nest;
1752        u8 value;
1753        int ret, i;
1754        int getall = 0;
1755
1756        if (!netdev->dcbnl_ops->getfeatcfg)
1757                return -EOPNOTSUPP;
1758
1759        if (!tb[DCB_ATTR_FEATCFG])
1760                return -EINVAL;
1761
1762        ret = nla_parse_nested(data, DCB_FEATCFG_ATTR_MAX, tb[DCB_ATTR_FEATCFG],
1763                               dcbnl_featcfg_nest);
1764        if (ret)
1765                goto err_out;
1766
1767        dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1768        if (!dcbnl_skb) {
1769                ret = -ENOBUFS;
1770                goto err_out;
1771        }
1772
1773        nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
1774
1775        dcb = NLMSG_DATA(nlh);
1776        dcb->dcb_family = AF_UNSPEC;
1777        dcb->cmd = DCB_CMD_GFEATCFG;
1778
1779        nest = nla_nest_start(dcbnl_skb, DCB_ATTR_FEATCFG);
1780        if (!nest) {
1781                ret = -EMSGSIZE;
1782                goto nla_put_failure;
1783        }
1784
1785        if (data[DCB_FEATCFG_ATTR_ALL])
1786                getall = 1;
1787
1788        for (i = DCB_FEATCFG_ATTR_ALL+1; i <= DCB_FEATCFG_ATTR_MAX; i++) {
1789                if (!getall && !data[i])
1790                        continue;
1791
1792                ret = netdev->dcbnl_ops->getfeatcfg(netdev, i, &value);
1793                if (!ret)
1794                        ret = nla_put_u8(dcbnl_skb, i, value);
1795
1796                if (ret) {
1797                        nla_nest_cancel(dcbnl_skb, nest);
1798                        goto nla_put_failure;
1799                }
1800        }
1801        nla_nest_end(dcbnl_skb, nest);
1802
1803        nlmsg_end(dcbnl_skb, nlh);
1804
1805        return rtnl_unicast(dcbnl_skb, &init_net, pid);
1806nla_put_failure:
1807        nlmsg_cancel(dcbnl_skb, nlh);
1808nlmsg_failure:
1809        kfree_skb(dcbnl_skb);
1810err_out:
1811        return ret;
1812}
1813
1814static int dcbnl_setfeatcfg(struct net_device *netdev, struct nlattr **tb,
1815                            u32 pid, u32 seq, u16 flags)
1816{
1817        struct nlattr *data[DCB_FEATCFG_ATTR_MAX + 1];
1818        int ret, i;
1819        u8 value;
1820
1821        if (!netdev->dcbnl_ops->setfeatcfg)
1822                return -ENOTSUPP;
1823
1824        if (!tb[DCB_ATTR_FEATCFG])
1825                return -EINVAL;
1826
1827        ret = nla_parse_nested(data, DCB_FEATCFG_ATTR_MAX, tb[DCB_ATTR_FEATCFG],
1828                               dcbnl_featcfg_nest);
1829
1830        if (ret)
1831                goto err;
1832
1833        for (i = DCB_FEATCFG_ATTR_ALL+1; i <= DCB_FEATCFG_ATTR_MAX; i++) {
1834                if (data[i] == NULL)
1835                        continue;
1836
1837                value = nla_get_u8(data[i]);
1838
1839                ret = netdev->dcbnl_ops->setfeatcfg(netdev, i, value);
1840
1841                if (ret)
1842                        goto err;
1843        }
1844err:
1845        dcbnl_reply(ret, RTM_SETDCB, DCB_CMD_SFEATCFG, DCB_ATTR_FEATCFG,
1846                    pid, seq, flags);
1847
1848        return ret;
1849}
1850
1851/* Handle CEE DCBX GET commands. */
1852static int dcbnl_cee_get(struct net_device *netdev, struct nlattr **tb,
1853                         u32 pid, u32 seq, u16 flags)
1854{
1855        struct net *net = dev_net(netdev);
1856        struct sk_buff *skb;
1857        struct nlmsghdr *nlh;
1858        struct dcbmsg *dcb;
1859        const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
1860        int err;
1861
1862        if (!ops)
1863                return -EOPNOTSUPP;
1864
1865        skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1866        if (!skb)
1867                return -ENOBUFS;
1868
1869        nlh = nlmsg_put(skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
1870        if (nlh == NULL) {
1871                nlmsg_free(skb);
1872                return -EMSGSIZE;
1873        }
1874
1875        dcb = NLMSG_DATA(nlh);
1876        dcb->dcb_family = AF_UNSPEC;
1877        dcb->cmd = DCB_CMD_CEE_GET;
1878
1879        err = dcbnl_cee_fill(skb, netdev);
1880
1881        if (err < 0) {
1882                nlmsg_cancel(skb, nlh);
1883                nlmsg_free(skb);
1884        } else {
1885                nlmsg_end(skb, nlh);
1886                err = rtnl_unicast(skb, net, pid);
1887        }
1888        return err;
1889}
1890
1891static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
1892{
1893        struct net *net = sock_net(skb->sk);
1894        struct net_device *netdev;
1895        struct dcbmsg  *dcb = (struct dcbmsg *)NLMSG_DATA(nlh);
1896        struct nlattr *tb[DCB_ATTR_MAX + 1];
1897        u32 pid = skb ? NETLINK_CB(skb).pid : 0;
1898        int ret = -EINVAL;
1899
1900        if (!net_eq(net, &init_net))
1901                return -EINVAL;
1902
1903        ret = nlmsg_parse(nlh, sizeof(*dcb), tb, DCB_ATTR_MAX,
1904                          dcbnl_rtnl_policy);
1905        if (ret < 0)
1906                return ret;
1907
1908        if (!tb[DCB_ATTR_IFNAME])
1909                return -EINVAL;
1910
1911        netdev = dev_get_by_name(&init_net, nla_data(tb[DCB_ATTR_IFNAME]));
1912        if (!netdev)
1913                return -EINVAL;
1914
1915        if (!netdev->dcbnl_ops)
1916                goto errout;
1917
1918        switch (dcb->cmd) {
1919        case DCB_CMD_GSTATE:
1920                ret = dcbnl_getstate(netdev, tb, pid, nlh->nlmsg_seq,
1921                                     nlh->nlmsg_flags);
1922                goto out;
1923        case DCB_CMD_PFC_GCFG:
1924                ret = dcbnl_getpfccfg(netdev, tb, pid, nlh->nlmsg_seq,
1925                                      nlh->nlmsg_flags);
1926                goto out;
1927        case DCB_CMD_GPERM_HWADDR:
1928                ret = dcbnl_getperm_hwaddr(netdev, tb, pid, nlh->nlmsg_seq,
1929                                           nlh->nlmsg_flags);
1930                goto out;
1931        case DCB_CMD_PGTX_GCFG:
1932                ret = dcbnl_pgtx_getcfg(netdev, tb, pid, nlh->nlmsg_seq,
1933                                        nlh->nlmsg_flags);
1934                goto out;
1935        case DCB_CMD_PGRX_GCFG:
1936                ret = dcbnl_pgrx_getcfg(netdev, tb, pid, nlh->nlmsg_seq,
1937                                        nlh->nlmsg_flags);
1938                goto out;
1939        case DCB_CMD_BCN_GCFG:
1940                ret = dcbnl_bcn_getcfg(netdev, tb, pid, nlh->nlmsg_seq,
1941                                       nlh->nlmsg_flags);
1942                goto out;
1943        case DCB_CMD_SSTATE:
1944                ret = dcbnl_setstate(netdev, tb, pid, nlh->nlmsg_seq,
1945                                     nlh->nlmsg_flags);
1946                goto out;
1947        case DCB_CMD_PFC_SCFG:
1948                ret = dcbnl_setpfccfg(netdev, tb, pid, nlh->nlmsg_seq,
1949                                      nlh->nlmsg_flags);
1950                goto out;
1951
1952        case DCB_CMD_SET_ALL:
1953                ret = dcbnl_setall(netdev, tb, pid, nlh->nlmsg_seq,
1954                                   nlh->nlmsg_flags);
1955                goto out;
1956        case DCB_CMD_PGTX_SCFG:
1957                ret = dcbnl_pgtx_setcfg(netdev, tb, pid, nlh->nlmsg_seq,
1958                                        nlh->nlmsg_flags);
1959                goto out;
1960        case DCB_CMD_PGRX_SCFG:
1961                ret = dcbnl_pgrx_setcfg(netdev, tb, pid, nlh->nlmsg_seq,
1962                                        nlh->nlmsg_flags);
1963                goto out;
1964        case DCB_CMD_GCAP:
1965                ret = dcbnl_getcap(netdev, tb, pid, nlh->nlmsg_seq,
1966                                   nlh->nlmsg_flags);
1967                goto out;
1968        case DCB_CMD_GNUMTCS:
1969                ret = dcbnl_getnumtcs(netdev, tb, pid, nlh->nlmsg_seq,
1970                                      nlh->nlmsg_flags);
1971                goto out;
1972        case DCB_CMD_SNUMTCS:
1973                ret = dcbnl_setnumtcs(netdev, tb, pid, nlh->nlmsg_seq,
1974                                      nlh->nlmsg_flags);
1975                goto out;
1976        case DCB_CMD_PFC_GSTATE:
1977                ret = dcbnl_getpfcstate(netdev, tb, pid, nlh->nlmsg_seq,
1978                                        nlh->nlmsg_flags);
1979                goto out;
1980        case DCB_CMD_PFC_SSTATE:
1981                ret = dcbnl_setpfcstate(netdev, tb, pid, nlh->nlmsg_seq,
1982                                        nlh->nlmsg_flags);
1983                goto out;
1984        case DCB_CMD_BCN_SCFG:
1985                ret = dcbnl_bcn_setcfg(netdev, tb, pid, nlh->nlmsg_seq,
1986                                       nlh->nlmsg_flags);
1987                goto out;
1988        case DCB_CMD_GAPP:
1989                ret = dcbnl_getapp(netdev, tb, pid, nlh->nlmsg_seq,
1990                                   nlh->nlmsg_flags);
1991                goto out;
1992        case DCB_CMD_SAPP:
1993                ret = dcbnl_setapp(netdev, tb, pid, nlh->nlmsg_seq,
1994                                   nlh->nlmsg_flags);
1995                goto out;
1996        case DCB_CMD_IEEE_SET:
1997                ret = dcbnl_ieee_set(netdev, tb, pid, nlh->nlmsg_seq,
1998                                     nlh->nlmsg_flags);
1999                goto out;
2000        case DCB_CMD_IEEE_GET:
2001                ret = dcbnl_ieee_get(netdev, tb, pid, nlh->nlmsg_seq,
2002                                     nlh->nlmsg_flags);
2003                goto out;
2004        case DCB_CMD_IEEE_DEL:
2005                ret = dcbnl_ieee_del(netdev, tb, pid, nlh->nlmsg_seq,
2006                                     nlh->nlmsg_flags);
2007                goto out;
2008        case DCB_CMD_GDCBX:
2009                ret = dcbnl_getdcbx(netdev, tb, pid, nlh->nlmsg_seq,
2010                                    nlh->nlmsg_flags);
2011                goto out;
2012        case DCB_CMD_SDCBX:
2013                ret = dcbnl_setdcbx(netdev, tb, pid, nlh->nlmsg_seq,
2014                                    nlh->nlmsg_flags);
2015                goto out;
2016        case DCB_CMD_GFEATCFG:
2017                ret = dcbnl_getfeatcfg(netdev, tb, pid, nlh->nlmsg_seq,
2018                                       nlh->nlmsg_flags);
2019                goto out;
2020        case DCB_CMD_SFEATCFG:
2021                ret = dcbnl_setfeatcfg(netdev, tb, pid, nlh->nlmsg_seq,
2022                                       nlh->nlmsg_flags);
2023                goto out;
2024        case DCB_CMD_CEE_GET:
2025                ret = dcbnl_cee_get(netdev, tb, pid, nlh->nlmsg_seq,
2026                                    nlh->nlmsg_flags);
2027                goto out;
2028        default:
2029                goto errout;
2030        }
2031errout:
2032        ret = -EINVAL;
2033out:
2034        dev_put(netdev);
2035        return ret;
2036}
2037
2038/**
2039 * dcb_getapp - retrieve the DCBX application user priority
2040 *
2041 * On success returns a non-zero 802.1p user priority bitmap
2042 * otherwise returns 0 as the invalid user priority bitmap to
2043 * indicate an error.
2044 */
2045u8 dcb_getapp(struct net_device *dev, struct dcb_app *app)
2046{
2047        struct dcb_app_type *itr;
2048        u8 prio = 0;
2049
2050        spin_lock(&dcb_lock);
2051        list_for_each_entry(itr, &dcb_app_list, list) {
2052                if (itr->app.selector == app->selector &&
2053                    itr->app.protocol == app->protocol &&
2054                    itr->ifindex == dev->ifindex) {
2055                        prio = itr->app.priority;
2056                        break;
2057                }
2058        }
2059        spin_unlock(&dcb_lock);
2060
2061        return prio;
2062}
2063EXPORT_SYMBOL(dcb_getapp);
2064
2065/**
2066 * dcb_setapp - add CEE dcb application data to app list
2067 *
2068 * Priority 0 is an invalid priority in CEE spec. This routine
2069 * removes applications from the app list if the priority is
2070 * set to zero.
2071 */
2072int dcb_setapp(struct net_device *dev, struct dcb_app *new)
2073{
2074        struct dcb_app_type *itr;
2075        struct dcb_app_type event;
2076
2077        event.ifindex = dev->ifindex;
2078        memcpy(&event.app, new, sizeof(event.app));
2079        if (dev->dcbnl_ops->getdcbx)
2080                event.dcbx = dev->dcbnl_ops->getdcbx(dev);
2081
2082        spin_lock(&dcb_lock);
2083        /* Search for existing match and replace */
2084        list_for_each_entry(itr, &dcb_app_list, list) {
2085                if (itr->app.selector == new->selector &&
2086                    itr->app.protocol == new->protocol &&
2087                    itr->ifindex == dev->ifindex) {
2088                        if (new->priority)
2089                                itr->app.priority = new->priority;
2090                        else {
2091                                list_del(&itr->list);
2092                                kfree(itr);
2093                        }
2094                        goto out;
2095                }
2096        }
2097        /* App type does not exist add new application type */
2098        if (new->priority) {
2099                struct dcb_app_type *entry;
2100                entry = kmalloc(sizeof(struct dcb_app_type), GFP_ATOMIC);
2101                if (!entry) {
2102                        spin_unlock(&dcb_lock);
2103                        return -ENOMEM;
2104                }
2105
2106                memcpy(&entry->app, new, sizeof(*new));
2107                entry->ifindex = dev->ifindex;
2108                list_add(&entry->list, &dcb_app_list);
2109        }
2110out:
2111        spin_unlock(&dcb_lock);
2112        call_dcbevent_notifiers(DCB_APP_EVENT, &event);
2113        return 0;
2114}
2115EXPORT_SYMBOL(dcb_setapp);
2116
2117/**
2118 * dcb_ieee_getapp_mask - retrieve the IEEE DCB application priority
2119 *
2120 * Helper routine which on success returns a non-zero 802.1Qaz user
2121 * priority bitmap otherwise returns 0 to indicate the dcb_app was
2122 * not found in APP list.
2123 */
2124u8 dcb_ieee_getapp_mask(struct net_device *dev, struct dcb_app *app)
2125{
2126        struct dcb_app_type *itr;
2127        u8 prio = 0;
2128
2129        spin_lock(&dcb_lock);
2130        list_for_each_entry(itr, &dcb_app_list, list) {
2131                if (itr->app.selector == app->selector &&
2132                    itr->app.protocol == app->protocol &&
2133                    itr->ifindex == dev->ifindex) {
2134                        prio |= 1 << itr->app.priority;
2135                }
2136        }
2137        spin_unlock(&dcb_lock);
2138
2139        return prio;
2140}
2141EXPORT_SYMBOL(dcb_ieee_getapp_mask);
2142
2143/**
2144 * dcb_ieee_setapp - add IEEE dcb application data to app list
2145 *
2146 * This adds Application data to the list. Multiple application
2147 * entries may exists for the same selector and protocol as long
2148 * as the priorities are different.
2149 */
2150int dcb_ieee_setapp(struct net_device *dev, struct dcb_app *new)
2151{
2152        struct dcb_app_type *itr, *entry;
2153        struct dcb_app_type event;
2154        int err = 0;
2155
2156        event.ifindex = dev->ifindex;
2157        memcpy(&event.app, new, sizeof(event.app));
2158        if (dev->dcbnl_ops->getdcbx)
2159                event.dcbx = dev->dcbnl_ops->getdcbx(dev);
2160
2161        spin_lock(&dcb_lock);
2162        /* Search for existing match and abort if found */
2163        list_for_each_entry(itr, &dcb_app_list, list) {
2164                if (itr->app.selector == new->selector &&
2165                    itr->app.protocol == new->protocol &&
2166                    itr->app.priority == new->priority &&
2167                    itr->ifindex == dev->ifindex) {
2168                        err = -EEXIST;
2169                        goto out;
2170                }
2171        }
2172
2173        /* App entry does not exist add new entry */
2174        entry = kmalloc(sizeof(struct dcb_app_type), GFP_ATOMIC);
2175        if (!entry) {
2176                err = -ENOMEM;
2177                goto out;
2178        }
2179
2180        memcpy(&entry->app, new, sizeof(*new));
2181        entry->ifindex = dev->ifindex;
2182        list_add(&entry->list, &dcb_app_list);
2183out:
2184        spin_unlock(&dcb_lock);
2185        if (!err)
2186                call_dcbevent_notifiers(DCB_APP_EVENT, &event);
2187        return err;
2188}
2189EXPORT_SYMBOL(dcb_ieee_setapp);
2190
2191/**
2192 * dcb_ieee_delapp - delete IEEE dcb application data from list
2193 *
2194 * This removes a matching APP data from the APP list
2195 */
2196int dcb_ieee_delapp(struct net_device *dev, struct dcb_app *del)
2197{
2198        struct dcb_app_type *itr;
2199        struct dcb_app_type event;
2200        int err = -ENOENT;
2201
2202        event.ifindex = dev->ifindex;
2203        memcpy(&event.app, del, sizeof(event.app));
2204        if (dev->dcbnl_ops->getdcbx)
2205                event.dcbx = dev->dcbnl_ops->getdcbx(dev);
2206
2207        spin_lock(&dcb_lock);
2208        /* Search for existing match and remove it. */
2209        list_for_each_entry(itr, &dcb_app_list, list) {
2210                if (itr->app.selector == del->selector &&
2211                    itr->app.protocol == del->protocol &&
2212                    itr->app.priority == del->priority &&
2213                    itr->ifindex == dev->ifindex) {
2214                        list_del(&itr->list);
2215                        kfree(itr);
2216                        err = 0;
2217                        goto out;
2218                }
2219        }
2220
2221out:
2222        spin_unlock(&dcb_lock);
2223        if (!err)
2224                call_dcbevent_notifiers(DCB_APP_EVENT, &event);
2225        return err;
2226}
2227EXPORT_SYMBOL(dcb_ieee_delapp);
2228
2229static void dcb_flushapp(void)
2230{
2231        struct dcb_app_type *app;
2232        struct dcb_app_type *tmp;
2233
2234        spin_lock(&dcb_lock);
2235        list_for_each_entry_safe(app, tmp, &dcb_app_list, list) {
2236                list_del(&app->list);
2237                kfree(app);
2238        }
2239        spin_unlock(&dcb_lock);
2240}
2241
2242static int __init dcbnl_init(void)
2243{
2244        INIT_LIST_HEAD(&dcb_app_list);
2245
2246        rtnl_register(PF_UNSPEC, RTM_GETDCB, dcb_doit, NULL, NULL);
2247        rtnl_register(PF_UNSPEC, RTM_SETDCB, dcb_doit, NULL, NULL);
2248
2249        return 0;
2250}
2251module_init(dcbnl_init);
2252
2253static void __exit dcbnl_exit(void)
2254{
2255        rtnl_unregister(PF_UNSPEC, RTM_GETDCB);
2256        rtnl_unregister(PF_UNSPEC, RTM_SETDCB);
2257        dcb_flushapp();
2258}
2259module_exit(dcbnl_exit);
2260
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.