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