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