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