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