cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

dcbnl.c (54625B)


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