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