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 err;
1430
1431        if (!ops)
1432                return -EOPNOTSUPP;
1433
1434        if (!tb[DCB_ATTR_IEEE])
1435                return -EINVAL;
1436
1437        err = nla_parse_nested_deprecated(ieee, DCB_ATTR_IEEE_MAX,
1438                                          tb[DCB_ATTR_IEEE],
1439                                          dcbnl_ieee_policy, NULL);
1440        if (err)
1441                return err;
1442
1443        if (ieee[DCB_ATTR_IEEE_ETS] && ops->ieee_setets) {
1444                struct ieee_ets *ets = nla_data(ieee[DCB_ATTR_IEEE_ETS]);
1445                err = ops->ieee_setets(netdev, ets);
1446                if (err)
1447                        goto err;
1448        }
1449
1450        if (ieee[DCB_ATTR_IEEE_MAXRATE] && ops->ieee_setmaxrate) {
1451                struct ieee_maxrate *maxrate =
1452                        nla_data(ieee[DCB_ATTR_IEEE_MAXRATE]);
1453                err = ops->ieee_setmaxrate(netdev, maxrate);
1454                if (err)
1455                        goto err;
1456        }
1457
1458        if (ieee[DCB_ATTR_IEEE_QCN] && ops->ieee_setqcn) {
1459                struct ieee_qcn *qcn =
1460                        nla_data(ieee[DCB_ATTR_IEEE_QCN]);
1461
1462                err = ops->ieee_setqcn(netdev, qcn);
1463                if (err)
1464                        goto err;
1465        }
1466
1467        if (ieee[DCB_ATTR_IEEE_PFC] && ops->ieee_setpfc) {
1468                struct ieee_pfc *pfc = nla_data(ieee[DCB_ATTR_IEEE_PFC]);
1469                err = ops->ieee_setpfc(netdev, pfc);
1470                if (err)
1471                        goto err;
1472        }
1473
1474        if (ieee[DCB_ATTR_DCB_BUFFER] && ops->dcbnl_setbuffer) {
1475                struct dcbnl_buffer *buffer =
1476                        nla_data(ieee[DCB_ATTR_DCB_BUFFER]);
1477
1478                err = ops->dcbnl_setbuffer(netdev, buffer);
1479                if (err)
1480                        goto err;
1481        }
1482
1483        if (ieee[DCB_ATTR_IEEE_APP_TABLE]) {
1484                struct nlattr *attr;
1485                int rem;
1486
1487                nla_for_each_nested(attr, ieee[DCB_ATTR_IEEE_APP_TABLE], rem) {
1488                        struct dcb_app *app_data;
1489
1490                        if (nla_type(attr) != DCB_ATTR_IEEE_APP)
1491                                continue;
1492
1493                        if (nla_len(attr) < sizeof(struct dcb_app)) {
1494                                err = -ERANGE;
1495                                goto err;
1496                        }
1497
1498                        app_data = nla_data(attr);
1499                        if (ops->ieee_setapp)
1500                                err = ops->ieee_setapp(netdev, app_data);
1501                        else
1502                                err = dcb_ieee_setapp(netdev, app_data);
1503                        if (err)
1504                                goto err;
1505                }
1506        }
1507
1508err:
1509        err = nla_put_u8(skb, DCB_ATTR_IEEE, err);
1510        dcbnl_ieee_notify(netdev, RTM_SETDCB, DCB_CMD_IEEE_SET, seq, 0);
1511        return err;
1512}
1513
1514static int dcbnl_ieee_get(struct net_device *netdev, struct nlmsghdr *nlh,
1515                          u32 seq, struct nlattr **tb, struct sk_buff *skb)
1516{
1517        const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
1518
1519        if (!ops)
1520                return -EOPNOTSUPP;
1521
1522        return dcbnl_ieee_fill(skb, netdev);
1523}
1524
1525static int dcbnl_ieee_del(struct net_device *netdev, struct nlmsghdr *nlh,
1526                          u32 seq, struct nlattr **tb, struct sk_buff *skb)
1527{
1528        const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
1529        struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1];
1530        int err;
1531
1532        if (!ops)
1533                return -EOPNOTSUPP;
1534
1535        if (!tb[DCB_ATTR_IEEE])
1536                return -EINVAL;
1537
1538        err = nla_parse_nested_deprecated(ieee, DCB_ATTR_IEEE_MAX,
1539                                          tb[DCB_ATTR_IEEE],
1540                                          dcbnl_ieee_policy, NULL);
1541        if (err)
1542                return err;
1543
1544        if (ieee[DCB_ATTR_IEEE_APP_TABLE]) {
1545                struct nlattr *attr;
1546                int rem;
1547
1548                nla_for_each_nested(attr, ieee[DCB_ATTR_IEEE_APP_TABLE], rem) {
1549                        struct dcb_app *app_data;
1550
1551                        if (nla_type(attr) != DCB_ATTR_IEEE_APP)
1552                                continue;
1553                        app_data = nla_data(attr);
1554                        if (ops->ieee_delapp)
1555                                err = ops->ieee_delapp(netdev, app_data);
1556                        else
1557                                err = dcb_ieee_delapp(netdev, app_data);
1558                        if (err)
1559                                goto err;
1560                }
1561        }
1562
1563err:
1564        err = nla_put_u8(skb, DCB_ATTR_IEEE, err);
1565        dcbnl_ieee_notify(netdev, RTM_SETDCB, DCB_CMD_IEEE_DEL, seq, 0);
1566        return err;
1567}
1568
1569
1570/* DCBX configuration */
1571static int dcbnl_getdcbx(struct net_device *netdev, struct nlmsghdr *nlh,
1572                         u32 seq, struct nlattr **tb, struct sk_buff *skb)
1573{
1574        if (!netdev->dcbnl_ops->getdcbx)
1575                return -EOPNOTSUPP;
1576
1577        return nla_put_u8(skb, DCB_ATTR_DCBX,
1578                          netdev->dcbnl_ops->getdcbx(netdev));
1579}
1580
1581static int dcbnl_setdcbx(struct net_device *netdev, struct nlmsghdr *nlh,
1582                         u32 seq, struct nlattr **tb, struct sk_buff *skb)
1583{
1584        u8 value;
1585
1586        if (!netdev->dcbnl_ops->setdcbx)
1587                return -EOPNOTSUPP;
1588
1589        if (!tb[DCB_ATTR_DCBX])
1590                return -EINVAL;
1591
1592        value = nla_get_u8(tb[DCB_ATTR_DCBX]);
1593
1594        return nla_put_u8(skb, DCB_ATTR_DCBX,
1595                          netdev->dcbnl_ops->setdcbx(netdev, value));
1596}
1597
1598static int dcbnl_getfeatcfg(struct net_device *netdev, struct nlmsghdr *nlh,
1599                            u32 seq, struct nlattr **tb, struct sk_buff *skb)
1600{
1601        struct nlattr *data[DCB_FEATCFG_ATTR_MAX + 1], *nest;
1602        u8 value;
1603        int ret, i;
1604        int getall = 0;
1605
1606        if (!netdev->dcbnl_ops->getfeatcfg)
1607                return -EOPNOTSUPP;
1608
1609        if (!tb[DCB_ATTR_FEATCFG])
1610                return -EINVAL;
1611
1612        ret = nla_parse_nested_deprecated(data, DCB_FEATCFG_ATTR_MAX,
1613                                          tb[DCB_ATTR_FEATCFG],
1614                                          dcbnl_featcfg_nest, NULL);
1615        if (ret)
1616                return ret;
1617
1618        nest = nla_nest_start_noflag(skb, DCB_ATTR_FEATCFG);
1619        if (!nest)
1620                return -EMSGSIZE;
1621
1622        if (data[DCB_FEATCFG_ATTR_ALL])
1623                getall = 1;
1624
1625        for (i = DCB_FEATCFG_ATTR_ALL+1; i <= DCB_FEATCFG_ATTR_MAX; i++) {
1626                if (!getall && !data[i])
1627                        continue;
1628
1629                ret = netdev->dcbnl_ops->getfeatcfg(netdev, i, &value);
1630                if (!ret)
1631                        ret = nla_put_u8(skb, i, value);
1632
1633                if (ret) {
1634                        nla_nest_cancel(skb, nest);
1635                        goto nla_put_failure;
1636                }
1637        }
1638        nla_nest_end(skb, nest);
1639
1640nla_put_failure:
1641        return ret;
1642}
1643
1644static int dcbnl_setfeatcfg(struct net_device *netdev, struct nlmsghdr *nlh,
1645                            u32 seq, struct nlattr **tb, struct sk_buff *skb)
1646{
1647        struct nlattr *data[DCB_FEATCFG_ATTR_MAX + 1];
1648        int ret, i;
1649        u8 value;
1650
1651        if (!netdev->dcbnl_ops->setfeatcfg)
1652                return -ENOTSUPP;
1653
1654        if (!tb[DCB_ATTR_FEATCFG])
1655                return -EINVAL;
1656
1657        ret = nla_parse_nested_deprecated(data, DCB_FEATCFG_ATTR_MAX,
1658                                          tb[DCB_ATTR_FEATCFG],
1659                                          dcbnl_featcfg_nest, NULL);
1660
1661        if (ret)
1662                goto err;
1663
1664        for (i = DCB_FEATCFG_ATTR_ALL+1; i <= DCB_FEATCFG_ATTR_MAX; i++) {
1665                if (data[i] == NULL)
1666                        continue;
1667
1668                value = nla_get_u8(data[i]);
1669
1670                ret = netdev->dcbnl_ops->setfeatcfg(netdev, i, value);
1671
1672                if (ret)
1673                        goto err;
1674        }
1675err:
1676        ret = nla_put_u8(skb, DCB_ATTR_FEATCFG, ret);
1677
1678        return ret;
1679}
1680
1681/* Handle CEE DCBX GET commands. */
1682static int dcbnl_cee_get(struct net_device *netdev, struct nlmsghdr *nlh,
1683                         u32 seq, struct nlattr **tb, struct sk_buff *skb)
1684{
1685        const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
1686
1687        if (!ops)
1688                return -EOPNOTSUPP;
1689
1690        return dcbnl_cee_fill(skb, netdev);
1691}
1692
1693struct reply_func {
1694        /* reply netlink message type */
1695        int     type;
1696
1697        /* function to fill message contents */
1698        int   (*cb)(struct net_device *, struct nlmsghdr *, u32,
1699                    struct nlattr **, struct sk_buff *);
1700};
1701
1702static const struct reply_func reply_funcs[DCB_CMD_MAX+1] = {
1703        [DCB_CMD_GSTATE]        = { RTM_GETDCB, dcbnl_getstate },
1704        [DCB_CMD_SSTATE]        = { RTM_SETDCB, dcbnl_setstate },
1705        [DCB_CMD_PFC_GCFG]      = { RTM_GETDCB, dcbnl_getpfccfg },
1706        [DCB_CMD_PFC_SCFG]      = { RTM_SETDCB, dcbnl_setpfccfg },
1707        [DCB_CMD_GPERM_HWADDR]  = { RTM_GETDCB, dcbnl_getperm_hwaddr },
1708        [DCB_CMD_GCAP]          = { RTM_GETDCB, dcbnl_getcap },
1709        [DCB_CMD_GNUMTCS]       = { RTM_GETDCB, dcbnl_getnumtcs },
1710        [DCB_CMD_SNUMTCS]       = { RTM_SETDCB, dcbnl_setnumtcs },
1711        [DCB_CMD_PFC_GSTATE]    = { RTM_GETDCB, dcbnl_getpfcstate },
1712        [DCB_CMD_PFC_SSTATE]    = { RTM_SETDCB, dcbnl_setpfcstate },
1713        [DCB_CMD_GAPP]          = { RTM_GETDCB, dcbnl_getapp },
1714        [DCB_CMD_SAPP]          = { RTM_SETDCB, dcbnl_setapp },
1715        [DCB_CMD_PGTX_GCFG]     = { RTM_GETDCB, dcbnl_pgtx_getcfg },
1716        [DCB_CMD_PGTX_SCFG]     = { RTM_SETDCB, dcbnl_pgtx_setcfg },
1717        [DCB_CMD_PGRX_GCFG]     = { RTM_GETDCB, dcbnl_pgrx_getcfg },
1718        [DCB_CMD_PGRX_SCFG]     = { RTM_SETDCB, dcbnl_pgrx_setcfg },
1719        [DCB_CMD_SET_ALL]       = { RTM_SETDCB, dcbnl_setall },
1720        [DCB_CMD_BCN_GCFG]      = { RTM_GETDCB, dcbnl_bcn_getcfg },
1721        [DCB_CMD_BCN_SCFG]      = { RTM_SETDCB, dcbnl_bcn_setcfg },
1722        [DCB_CMD_IEEE_GET]      = { RTM_GETDCB, dcbnl_ieee_get },
1723        [DCB_CMD_IEEE_SET]      = { RTM_SETDCB, dcbnl_ieee_set },
1724        [DCB_CMD_IEEE_DEL]      = { RTM_SETDCB, dcbnl_ieee_del },
1725        [DCB_CMD_GDCBX]         = { RTM_GETDCB, dcbnl_getdcbx },
1726        [DCB_CMD_SDCBX]         = { RTM_SETDCB, dcbnl_setdcbx },
1727        [DCB_CMD_GFEATCFG]      = { RTM_GETDCB, dcbnl_getfeatcfg },
1728        [DCB_CMD_SFEATCFG]      = { RTM_SETDCB, dcbnl_setfeatcfg },
1729        [DCB_CMD_CEE_GET]       = { RTM_GETDCB, dcbnl_cee_get },
1730};
1731
1732static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
1733                    struct netlink_ext_ack *extack)
1734{
1735        struct net *net = sock_net(skb->sk);
1736        struct net_device *netdev;
1737        struct dcbmsg *dcb = nlmsg_data(nlh);
1738        struct nlattr *tb[DCB_ATTR_MAX + 1];
1739        u32 portid = skb ? NETLINK_CB(skb).portid : 0;
1740        int ret = -EINVAL;
1741        struct sk_buff *reply_skb;
1742        struct nlmsghdr *reply_nlh = NULL;
1743        const struct reply_func *fn;
1744
1745        if ((nlh->nlmsg_type == RTM_SETDCB) && !netlink_capable(skb, CAP_NET_ADMIN))
1746                return -EPERM;
1747
1748        ret = nlmsg_parse_deprecated(nlh, sizeof(*dcb), tb, DCB_ATTR_MAX,
1749                                     dcbnl_rtnl_policy, extack);
1750        if (ret < 0)
1751                return ret;
1752
1753        if (dcb->cmd > DCB_CMD_MAX)
1754                return -EINVAL;
1755
1756        /* check if a reply function has been defined for the command */
1757        fn = &reply_funcs[dcb->cmd];
1758        if (!fn->cb)
1759                return -EOPNOTSUPP;
1760
1761        if (!tb[DCB_ATTR_IFNAME])
1762                return -EINVAL;
1763
1764        netdev = __dev_get_by_name(net, nla_data(tb[DCB_ATTR_IFNAME]));
1765        if (!netdev)
1766                return -ENODEV;
1767
1768        if (!netdev->dcbnl_ops)
1769                return -EOPNOTSUPP;
1770
1771        reply_skb = dcbnl_newmsg(fn->type, dcb->cmd, portid, nlh->nlmsg_seq,
1772                                 nlh->nlmsg_flags, &reply_nlh);
1773        if (!reply_skb)
1774                return -ENOBUFS;
1775
1776        ret = fn->cb(netdev, nlh, nlh->nlmsg_seq, tb, reply_skb);
1777        if (ret < 0) {
1778                nlmsg_free(reply_skb);
1779                goto out;
1780        }
1781
1782        nlmsg_end(reply_skb, reply_nlh);
1783
1784        ret = rtnl_unicast(reply_skb, net, portid);
1785out:
1786        return ret;
1787}
1788
1789static struct dcb_app_type *dcb_app_lookup(const struct dcb_app *app,
1790                                           int ifindex, int prio)
1791{
1792        struct dcb_app_type *itr;
1793
1794        list_for_each_entry(itr, &dcb_app_list, list) {
1795                if (itr->app.selector == app->selector &&
1796                    itr->app.protocol == app->protocol &&
1797                    itr->ifindex == ifindex &&
1798                    ((prio == -1) || itr->app.priority == prio))
1799                        return itr;
1800        }
1801
1802        return NULL;
1803}
1804
1805static int dcb_app_add(const struct dcb_app *app, int ifindex)
1806{
1807        struct dcb_app_type *entry;
1808
1809        entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
1810        if (!entry)
1811                return -ENOMEM;
1812
1813        memcpy(&entry->app, app, sizeof(*app));
1814        entry->ifindex = ifindex;
1815        list_add(&entry->list, &dcb_app_list);
1816
1817        return 0;
1818}
1819
1820/**
1821 * dcb_getapp - retrieve the DCBX application user priority
1822 *
1823 * On success returns a non-zero 802.1p user priority bitmap
1824 * otherwise returns 0 as the invalid user priority bitmap to
1825 * indicate an error.
1826 */
1827u8 dcb_getapp(struct net_device *dev, struct dcb_app *app)
1828{
1829        struct dcb_app_type *itr;
1830        u8 prio = 0;
1831
1832        spin_lock_bh(&dcb_lock);
1833        itr = dcb_app_lookup(app, dev->ifindex, -1);
1834        if (itr)
1835                prio = itr->app.priority;
1836        spin_unlock_bh(&dcb_lock);
1837
1838        return prio;
1839}
1840EXPORT_SYMBOL(dcb_getapp);
1841
1842/**
1843 * dcb_setapp - add CEE dcb application data to app list
1844 *
1845 * Priority 0 is an invalid priority in CEE spec. This routine
1846 * removes applications from the app list if the priority is
1847 * set to zero. Priority is expected to be 8-bit 802.1p user priority bitmap
1848 */
1849int dcb_setapp(struct net_device *dev, struct dcb_app *new)
1850{
1851        struct dcb_app_type *itr;
1852        struct dcb_app_type event;
1853        int err = 0;
1854
1855        event.ifindex = dev->ifindex;
1856        memcpy(&event.app, new, sizeof(event.app));
1857        if (dev->dcbnl_ops->getdcbx)
1858                event.dcbx = dev->dcbnl_ops->getdcbx(dev);
1859
1860        spin_lock_bh(&dcb_lock);
1861        /* Search for existing match and replace */
1862        itr = dcb_app_lookup(new, dev->ifindex, -1);
1863        if (itr) {
1864                if (new->priority)
1865                        itr->app.priority = new->priority;
1866                else {
1867                        list_del(&itr->list);
1868                        kfree(itr);
1869                }
1870                goto out;
1871        }
1872        /* App type does not exist add new application type */
1873        if (new->priority)
1874                err = dcb_app_add(new, dev->ifindex);
1875out:
1876        spin_unlock_bh(&dcb_lock);
1877        if (!err)
1878                call_dcbevent_notifiers(DCB_APP_EVENT, &event);
1879        return err;
1880}
1881EXPORT_SYMBOL(dcb_setapp);
1882
1883/**
1884 * dcb_ieee_getapp_mask - retrieve the IEEE DCB application priority
1885 *
1886 * Helper routine which on success returns a non-zero 802.1Qaz user
1887 * priority bitmap otherwise returns 0 to indicate the dcb_app was
1888 * not found in APP list.
1889 */
1890u8 dcb_ieee_getapp_mask(struct net_device *dev, struct dcb_app *app)
1891{
1892        struct dcb_app_type *itr;
1893        u8 prio = 0;
1894
1895        spin_lock_bh(&dcb_lock);
1896        itr = dcb_app_lookup(app, dev->ifindex, -1);
1897        if (itr)
1898                prio |= 1 << itr->app.priority;
1899        spin_unlock_bh(&dcb_lock);
1900
1901        return prio;
1902}
1903EXPORT_SYMBOL(dcb_ieee_getapp_mask);
1904
1905/**
1906 * dcb_ieee_setapp - add IEEE dcb application data to app list
1907 *
1908 * This adds Application data to the list. Multiple application
1909 * entries may exists for the same selector and protocol as long
1910 * as the priorities are different. Priority is expected to be a
1911 * 3-bit unsigned integer
1912 */
1913int dcb_ieee_setapp(struct net_device *dev, struct dcb_app *new)
1914{
1915        struct dcb_app_type event;
1916        int err = 0;
1917
1918        event.ifindex = dev->ifindex;
1919        memcpy(&event.app, new, sizeof(event.app));
1920        if (dev->dcbnl_ops->getdcbx)
1921                event.dcbx = dev->dcbnl_ops->getdcbx(dev);
1922
1923        spin_lock_bh(&dcb_lock);
1924        /* Search for existing match and abort if found */
1925        if (dcb_app_lookup(new, dev->ifindex, new->priority)) {
1926                err = -EEXIST;
1927                goto out;
1928        }
1929
1930        err = dcb_app_add(new, dev->ifindex);
1931out:
1932        spin_unlock_bh(&dcb_lock);
1933        if (!err)
1934                call_dcbevent_notifiers(DCB_APP_EVENT, &event);
1935        return err;
1936}
1937EXPORT_SYMBOL(dcb_ieee_setapp);
1938
1939/**
1940 * dcb_ieee_delapp - delete IEEE dcb application data from list
1941 *
1942 * This removes a matching APP data from the APP list
1943 */
1944int dcb_ieee_delapp(struct net_device *dev, struct dcb_app *del)
1945{
1946        struct dcb_app_type *itr;
1947        struct dcb_app_type event;
1948        int err = -ENOENT;
1949
1950        event.ifindex = dev->ifindex;
1951        memcpy(&event.app, del, sizeof(event.app));
1952        if (dev->dcbnl_ops->getdcbx)
1953                event.dcbx = dev->dcbnl_ops->getdcbx(dev);
1954
1955        spin_lock_bh(&dcb_lock);
1956        /* Search for existing match and remove it. */
1957        if ((itr = dcb_app_lookup(del, dev->ifindex, del->priority))) {
1958                list_del(&itr->list);
1959                kfree(itr);
1960                err = 0;
1961        }
1962
1963        spin_unlock_bh(&dcb_lock);
1964        if (!err)
1965                call_dcbevent_notifiers(DCB_APP_EVENT, &event);
1966        return err;
1967}
1968EXPORT_SYMBOL(dcb_ieee_delapp);
1969
1970/**
1971 * dcb_ieee_getapp_prio_dscp_mask_map - For a given device, find mapping from
1972 * priorities to the DSCP values assigned to that priority. Initialize p_map
1973 * such that each map element holds a bit mask of DSCP values configured for
1974 * that priority by APP entries.
1975 */
1976void dcb_ieee_getapp_prio_dscp_mask_map(const struct net_device *dev,
1977                                        struct dcb_ieee_app_prio_map *p_map)
1978{
1979        int ifindex = dev->ifindex;
1980        struct dcb_app_type *itr;
1981        u8 prio;
1982
1983        memset(p_map->map, 0, sizeof(p_map->map));
1984
1985        spin_lock_bh(&dcb_lock);
1986        list_for_each_entry(itr, &dcb_app_list, list) {
1987                if (itr->ifindex == ifindex &&
1988                    itr->app.selector == IEEE_8021QAZ_APP_SEL_DSCP &&
1989                    itr->app.protocol < 64 &&
1990                    itr->app.priority < IEEE_8021QAZ_MAX_TCS) {
1991                        prio = itr->app.priority;
1992                        p_map->map[prio] |= 1ULL << itr->app.protocol;
1993                }
1994        }
1995        spin_unlock_bh(&dcb_lock);
1996}
1997EXPORT_SYMBOL(dcb_ieee_getapp_prio_dscp_mask_map);
1998
1999/**
2000 * dcb_ieee_getapp_dscp_prio_mask_map - For a given device, find mapping from
2001 * DSCP values to the priorities assigned to that DSCP value. Initialize p_map
2002 * such that each map element holds a bit mask of priorities configured for a
2003 * given DSCP value by APP entries.
2004 */
2005void
2006dcb_ieee_getapp_dscp_prio_mask_map(const struct net_device *dev,
2007                                   struct dcb_ieee_app_dscp_map *p_map)
2008{
2009        int ifindex = dev->ifindex;
2010        struct dcb_app_type *itr;
2011
2012        memset(p_map->map, 0, sizeof(p_map->map));
2013
2014        spin_lock_bh(&dcb_lock);
2015        list_for_each_entry(itr, &dcb_app_list, list) {
2016                if (itr->ifindex == ifindex &&
2017                    itr->app.selector == IEEE_8021QAZ_APP_SEL_DSCP &&
2018                    itr->app.protocol < 64 &&
2019                    itr->app.priority < IEEE_8021QAZ_MAX_TCS)
2020                        p_map->map[itr->app.protocol] |= 1 << itr->app.priority;
2021        }
2022        spin_unlock_bh(&dcb_lock);
2023}
2024EXPORT_SYMBOL(dcb_ieee_getapp_dscp_prio_mask_map);
2025
2026/**
2027 * Per 802.1Q-2014, the selector value of 1 is used for matching on Ethernet
2028 * type, with valid PID values >= 1536. A special meaning is then assigned to
2029 * protocol value of 0: "default priority. For use when priority is not
2030 * otherwise specified".
2031 *
2032 * dcb_ieee_getapp_default_prio_mask - For a given device, find all APP entries
2033 * of the form {$PRIO, ETHERTYPE, 0} and construct a bit mask of all default
2034 * priorities set by these entries.
2035 */
2036u8 dcb_ieee_getapp_default_prio_mask(const struct net_device *dev)
2037{
2038        int ifindex = dev->ifindex;
2039        struct dcb_app_type *itr;
2040        u8 mask = 0;
2041
2042        spin_lock_bh(&dcb_lock);
2043        list_for_each_entry(itr, &dcb_app_list, list) {
2044                if (itr->ifindex == ifindex &&
2045                    itr->app.selector == IEEE_8021QAZ_APP_SEL_ETHERTYPE &&
2046                    itr->app.protocol == 0 &&
2047                    itr->app.priority < IEEE_8021QAZ_MAX_TCS)
2048                        mask |= 1 << itr->app.priority;
2049        }
2050        spin_unlock_bh(&dcb_lock);
2051
2052        return mask;
2053}
2054EXPORT_SYMBOL(dcb_ieee_getapp_default_prio_mask);
2055
2056static int __init dcbnl_init(void)
2057{
2058        INIT_LIST_HEAD(&dcb_app_list);
2059
2060        rtnl_register(PF_UNSPEC, RTM_GETDCB, dcb_doit, NULL, 0);
2061        rtnl_register(PF_UNSPEC, RTM_SETDCB, dcb_doit, NULL, 0);
2062
2063        return 0;
2064}
2065device_initcall(dcbnl_init);
2066