162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2008-2011, Intel Corporation.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Description: Data Center Bridging netlink interface
662306a36Sopenharmony_ci * Author: Lucy Liu <lucy.liu@intel.com>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/netdevice.h>
1062306a36Sopenharmony_ci#include <linux/netlink.h>
1162306a36Sopenharmony_ci#include <linux/slab.h>
1262306a36Sopenharmony_ci#include <net/netlink.h>
1362306a36Sopenharmony_ci#include <net/rtnetlink.h>
1462306a36Sopenharmony_ci#include <linux/dcbnl.h>
1562306a36Sopenharmony_ci#include <net/dcbevent.h>
1662306a36Sopenharmony_ci#include <linux/rtnetlink.h>
1762306a36Sopenharmony_ci#include <linux/init.h>
1862306a36Sopenharmony_ci#include <net/sock.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci/* Data Center Bridging (DCB) is a collection of Ethernet enhancements
2162306a36Sopenharmony_ci * intended to allow network traffic with differing requirements
2262306a36Sopenharmony_ci * (highly reliable, no drops vs. best effort vs. low latency) to operate
2362306a36Sopenharmony_ci * and co-exist on Ethernet.  Current DCB features are:
2462306a36Sopenharmony_ci *
2562306a36Sopenharmony_ci * Enhanced Transmission Selection (aka Priority Grouping [PG]) - provides a
2662306a36Sopenharmony_ci *   framework for assigning bandwidth guarantees to traffic classes.
2762306a36Sopenharmony_ci *
2862306a36Sopenharmony_ci * Priority-based Flow Control (PFC) - provides a flow control mechanism which
2962306a36Sopenharmony_ci *   can work independently for each 802.1p priority.
3062306a36Sopenharmony_ci *
3162306a36Sopenharmony_ci * Congestion Notification - provides a mechanism for end-to-end congestion
3262306a36Sopenharmony_ci *   control for protocols which do not have built-in congestion management.
3362306a36Sopenharmony_ci *
3462306a36Sopenharmony_ci * More information about the emerging standards for these Ethernet features
3562306a36Sopenharmony_ci * can be found at: http://www.ieee802.org/1/pages/dcbridges.html
3662306a36Sopenharmony_ci *
3762306a36Sopenharmony_ci * This file implements an rtnetlink interface to allow configuration of DCB
3862306a36Sopenharmony_ci * features for capable devices.
3962306a36Sopenharmony_ci */
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci/**************** DCB attribute policies *************************************/
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci/* DCB netlink attributes policy */
4462306a36Sopenharmony_cistatic const struct nla_policy dcbnl_rtnl_policy[DCB_ATTR_MAX + 1] = {
4562306a36Sopenharmony_ci	[DCB_ATTR_IFNAME]      = {.type = NLA_NUL_STRING, .len = IFNAMSIZ - 1},
4662306a36Sopenharmony_ci	[DCB_ATTR_STATE]       = {.type = NLA_U8},
4762306a36Sopenharmony_ci	[DCB_ATTR_PFC_CFG]     = {.type = NLA_NESTED},
4862306a36Sopenharmony_ci	[DCB_ATTR_PG_CFG]      = {.type = NLA_NESTED},
4962306a36Sopenharmony_ci	[DCB_ATTR_SET_ALL]     = {.type = NLA_U8},
5062306a36Sopenharmony_ci	[DCB_ATTR_PERM_HWADDR] = {.type = NLA_FLAG},
5162306a36Sopenharmony_ci	[DCB_ATTR_CAP]         = {.type = NLA_NESTED},
5262306a36Sopenharmony_ci	[DCB_ATTR_PFC_STATE]   = {.type = NLA_U8},
5362306a36Sopenharmony_ci	[DCB_ATTR_BCN]         = {.type = NLA_NESTED},
5462306a36Sopenharmony_ci	[DCB_ATTR_APP]         = {.type = NLA_NESTED},
5562306a36Sopenharmony_ci	[DCB_ATTR_IEEE]	       = {.type = NLA_NESTED},
5662306a36Sopenharmony_ci	[DCB_ATTR_DCBX]        = {.type = NLA_U8},
5762306a36Sopenharmony_ci	[DCB_ATTR_FEATCFG]     = {.type = NLA_NESTED},
5862306a36Sopenharmony_ci};
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci/* DCB priority flow control to User Priority nested attributes */
6162306a36Sopenharmony_cistatic const struct nla_policy dcbnl_pfc_up_nest[DCB_PFC_UP_ATTR_MAX + 1] = {
6262306a36Sopenharmony_ci	[DCB_PFC_UP_ATTR_0]   = {.type = NLA_U8},
6362306a36Sopenharmony_ci	[DCB_PFC_UP_ATTR_1]   = {.type = NLA_U8},
6462306a36Sopenharmony_ci	[DCB_PFC_UP_ATTR_2]   = {.type = NLA_U8},
6562306a36Sopenharmony_ci	[DCB_PFC_UP_ATTR_3]   = {.type = NLA_U8},
6662306a36Sopenharmony_ci	[DCB_PFC_UP_ATTR_4]   = {.type = NLA_U8},
6762306a36Sopenharmony_ci	[DCB_PFC_UP_ATTR_5]   = {.type = NLA_U8},
6862306a36Sopenharmony_ci	[DCB_PFC_UP_ATTR_6]   = {.type = NLA_U8},
6962306a36Sopenharmony_ci	[DCB_PFC_UP_ATTR_7]   = {.type = NLA_U8},
7062306a36Sopenharmony_ci	[DCB_PFC_UP_ATTR_ALL] = {.type = NLA_FLAG},
7162306a36Sopenharmony_ci};
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci/* DCB priority grouping nested attributes */
7462306a36Sopenharmony_cistatic const struct nla_policy dcbnl_pg_nest[DCB_PG_ATTR_MAX + 1] = {
7562306a36Sopenharmony_ci	[DCB_PG_ATTR_TC_0]      = {.type = NLA_NESTED},
7662306a36Sopenharmony_ci	[DCB_PG_ATTR_TC_1]      = {.type = NLA_NESTED},
7762306a36Sopenharmony_ci	[DCB_PG_ATTR_TC_2]      = {.type = NLA_NESTED},
7862306a36Sopenharmony_ci	[DCB_PG_ATTR_TC_3]      = {.type = NLA_NESTED},
7962306a36Sopenharmony_ci	[DCB_PG_ATTR_TC_4]      = {.type = NLA_NESTED},
8062306a36Sopenharmony_ci	[DCB_PG_ATTR_TC_5]      = {.type = NLA_NESTED},
8162306a36Sopenharmony_ci	[DCB_PG_ATTR_TC_6]      = {.type = NLA_NESTED},
8262306a36Sopenharmony_ci	[DCB_PG_ATTR_TC_7]      = {.type = NLA_NESTED},
8362306a36Sopenharmony_ci	[DCB_PG_ATTR_TC_ALL]    = {.type = NLA_NESTED},
8462306a36Sopenharmony_ci	[DCB_PG_ATTR_BW_ID_0]   = {.type = NLA_U8},
8562306a36Sopenharmony_ci	[DCB_PG_ATTR_BW_ID_1]   = {.type = NLA_U8},
8662306a36Sopenharmony_ci	[DCB_PG_ATTR_BW_ID_2]   = {.type = NLA_U8},
8762306a36Sopenharmony_ci	[DCB_PG_ATTR_BW_ID_3]   = {.type = NLA_U8},
8862306a36Sopenharmony_ci	[DCB_PG_ATTR_BW_ID_4]   = {.type = NLA_U8},
8962306a36Sopenharmony_ci	[DCB_PG_ATTR_BW_ID_5]   = {.type = NLA_U8},
9062306a36Sopenharmony_ci	[DCB_PG_ATTR_BW_ID_6]   = {.type = NLA_U8},
9162306a36Sopenharmony_ci	[DCB_PG_ATTR_BW_ID_7]   = {.type = NLA_U8},
9262306a36Sopenharmony_ci	[DCB_PG_ATTR_BW_ID_ALL] = {.type = NLA_FLAG},
9362306a36Sopenharmony_ci};
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci/* DCB traffic class nested attributes. */
9662306a36Sopenharmony_cistatic const struct nla_policy dcbnl_tc_param_nest[DCB_TC_ATTR_PARAM_MAX + 1] = {
9762306a36Sopenharmony_ci	[DCB_TC_ATTR_PARAM_PGID]            = {.type = NLA_U8},
9862306a36Sopenharmony_ci	[DCB_TC_ATTR_PARAM_UP_MAPPING]      = {.type = NLA_U8},
9962306a36Sopenharmony_ci	[DCB_TC_ATTR_PARAM_STRICT_PRIO]     = {.type = NLA_U8},
10062306a36Sopenharmony_ci	[DCB_TC_ATTR_PARAM_BW_PCT]          = {.type = NLA_U8},
10162306a36Sopenharmony_ci	[DCB_TC_ATTR_PARAM_ALL]             = {.type = NLA_FLAG},
10262306a36Sopenharmony_ci};
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci/* DCB capabilities nested attributes. */
10562306a36Sopenharmony_cistatic const struct nla_policy dcbnl_cap_nest[DCB_CAP_ATTR_MAX + 1] = {
10662306a36Sopenharmony_ci	[DCB_CAP_ATTR_ALL]     = {.type = NLA_FLAG},
10762306a36Sopenharmony_ci	[DCB_CAP_ATTR_PG]      = {.type = NLA_U8},
10862306a36Sopenharmony_ci	[DCB_CAP_ATTR_PFC]     = {.type = NLA_U8},
10962306a36Sopenharmony_ci	[DCB_CAP_ATTR_UP2TC]   = {.type = NLA_U8},
11062306a36Sopenharmony_ci	[DCB_CAP_ATTR_PG_TCS]  = {.type = NLA_U8},
11162306a36Sopenharmony_ci	[DCB_CAP_ATTR_PFC_TCS] = {.type = NLA_U8},
11262306a36Sopenharmony_ci	[DCB_CAP_ATTR_GSP]     = {.type = NLA_U8},
11362306a36Sopenharmony_ci	[DCB_CAP_ATTR_BCN]     = {.type = NLA_U8},
11462306a36Sopenharmony_ci	[DCB_CAP_ATTR_DCBX]    = {.type = NLA_U8},
11562306a36Sopenharmony_ci};
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci/* DCB capabilities nested attributes. */
11862306a36Sopenharmony_cistatic const struct nla_policy dcbnl_numtcs_nest[DCB_NUMTCS_ATTR_MAX + 1] = {
11962306a36Sopenharmony_ci	[DCB_NUMTCS_ATTR_ALL]     = {.type = NLA_FLAG},
12062306a36Sopenharmony_ci	[DCB_NUMTCS_ATTR_PG]      = {.type = NLA_U8},
12162306a36Sopenharmony_ci	[DCB_NUMTCS_ATTR_PFC]     = {.type = NLA_U8},
12262306a36Sopenharmony_ci};
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci/* DCB BCN nested attributes. */
12562306a36Sopenharmony_cistatic const struct nla_policy dcbnl_bcn_nest[DCB_BCN_ATTR_MAX + 1] = {
12662306a36Sopenharmony_ci	[DCB_BCN_ATTR_RP_0]         = {.type = NLA_U8},
12762306a36Sopenharmony_ci	[DCB_BCN_ATTR_RP_1]         = {.type = NLA_U8},
12862306a36Sopenharmony_ci	[DCB_BCN_ATTR_RP_2]         = {.type = NLA_U8},
12962306a36Sopenharmony_ci	[DCB_BCN_ATTR_RP_3]         = {.type = NLA_U8},
13062306a36Sopenharmony_ci	[DCB_BCN_ATTR_RP_4]         = {.type = NLA_U8},
13162306a36Sopenharmony_ci	[DCB_BCN_ATTR_RP_5]         = {.type = NLA_U8},
13262306a36Sopenharmony_ci	[DCB_BCN_ATTR_RP_6]         = {.type = NLA_U8},
13362306a36Sopenharmony_ci	[DCB_BCN_ATTR_RP_7]         = {.type = NLA_U8},
13462306a36Sopenharmony_ci	[DCB_BCN_ATTR_RP_ALL]       = {.type = NLA_FLAG},
13562306a36Sopenharmony_ci	[DCB_BCN_ATTR_BCNA_0]       = {.type = NLA_U32},
13662306a36Sopenharmony_ci	[DCB_BCN_ATTR_BCNA_1]       = {.type = NLA_U32},
13762306a36Sopenharmony_ci	[DCB_BCN_ATTR_ALPHA]        = {.type = NLA_U32},
13862306a36Sopenharmony_ci	[DCB_BCN_ATTR_BETA]         = {.type = NLA_U32},
13962306a36Sopenharmony_ci	[DCB_BCN_ATTR_GD]           = {.type = NLA_U32},
14062306a36Sopenharmony_ci	[DCB_BCN_ATTR_GI]           = {.type = NLA_U32},
14162306a36Sopenharmony_ci	[DCB_BCN_ATTR_TMAX]         = {.type = NLA_U32},
14262306a36Sopenharmony_ci	[DCB_BCN_ATTR_TD]           = {.type = NLA_U32},
14362306a36Sopenharmony_ci	[DCB_BCN_ATTR_RMIN]         = {.type = NLA_U32},
14462306a36Sopenharmony_ci	[DCB_BCN_ATTR_W]            = {.type = NLA_U32},
14562306a36Sopenharmony_ci	[DCB_BCN_ATTR_RD]           = {.type = NLA_U32},
14662306a36Sopenharmony_ci	[DCB_BCN_ATTR_RU]           = {.type = NLA_U32},
14762306a36Sopenharmony_ci	[DCB_BCN_ATTR_WRTT]         = {.type = NLA_U32},
14862306a36Sopenharmony_ci	[DCB_BCN_ATTR_RI]           = {.type = NLA_U32},
14962306a36Sopenharmony_ci	[DCB_BCN_ATTR_C]            = {.type = NLA_U32},
15062306a36Sopenharmony_ci	[DCB_BCN_ATTR_ALL]          = {.type = NLA_FLAG},
15162306a36Sopenharmony_ci};
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci/* DCB APP nested attributes. */
15462306a36Sopenharmony_cistatic const struct nla_policy dcbnl_app_nest[DCB_APP_ATTR_MAX + 1] = {
15562306a36Sopenharmony_ci	[DCB_APP_ATTR_IDTYPE]       = {.type = NLA_U8},
15662306a36Sopenharmony_ci	[DCB_APP_ATTR_ID]           = {.type = NLA_U16},
15762306a36Sopenharmony_ci	[DCB_APP_ATTR_PRIORITY]     = {.type = NLA_U8},
15862306a36Sopenharmony_ci};
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci/* IEEE 802.1Qaz nested attributes. */
16162306a36Sopenharmony_cistatic const struct nla_policy dcbnl_ieee_policy[DCB_ATTR_IEEE_MAX + 1] = {
16262306a36Sopenharmony_ci	[DCB_ATTR_IEEE_ETS]	    = {.len = sizeof(struct ieee_ets)},
16362306a36Sopenharmony_ci	[DCB_ATTR_IEEE_PFC]	    = {.len = sizeof(struct ieee_pfc)},
16462306a36Sopenharmony_ci	[DCB_ATTR_IEEE_APP_TABLE]   = {.type = NLA_NESTED},
16562306a36Sopenharmony_ci	[DCB_ATTR_IEEE_MAXRATE]   = {.len = sizeof(struct ieee_maxrate)},
16662306a36Sopenharmony_ci	[DCB_ATTR_IEEE_QCN]         = {.len = sizeof(struct ieee_qcn)},
16762306a36Sopenharmony_ci	[DCB_ATTR_IEEE_QCN_STATS]   = {.len = sizeof(struct ieee_qcn_stats)},
16862306a36Sopenharmony_ci	[DCB_ATTR_DCB_BUFFER]       = {.len = sizeof(struct dcbnl_buffer)},
16962306a36Sopenharmony_ci	[DCB_ATTR_DCB_APP_TRUST_TABLE] = {.type = NLA_NESTED},
17062306a36Sopenharmony_ci};
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci/* DCB number of traffic classes nested attributes. */
17362306a36Sopenharmony_cistatic const struct nla_policy dcbnl_featcfg_nest[DCB_FEATCFG_ATTR_MAX + 1] = {
17462306a36Sopenharmony_ci	[DCB_FEATCFG_ATTR_ALL]      = {.type = NLA_FLAG},
17562306a36Sopenharmony_ci	[DCB_FEATCFG_ATTR_PG]       = {.type = NLA_U8},
17662306a36Sopenharmony_ci	[DCB_FEATCFG_ATTR_PFC]      = {.type = NLA_U8},
17762306a36Sopenharmony_ci	[DCB_FEATCFG_ATTR_APP]      = {.type = NLA_U8},
17862306a36Sopenharmony_ci};
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_cistatic LIST_HEAD(dcb_app_list);
18162306a36Sopenharmony_cistatic LIST_HEAD(dcb_rewr_list);
18262306a36Sopenharmony_cistatic DEFINE_SPINLOCK(dcb_lock);
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_cistatic enum ieee_attrs_app dcbnl_app_attr_type_get(u8 selector)
18562306a36Sopenharmony_ci{
18662306a36Sopenharmony_ci	switch (selector) {
18762306a36Sopenharmony_ci	case IEEE_8021QAZ_APP_SEL_ETHERTYPE:
18862306a36Sopenharmony_ci	case IEEE_8021QAZ_APP_SEL_STREAM:
18962306a36Sopenharmony_ci	case IEEE_8021QAZ_APP_SEL_DGRAM:
19062306a36Sopenharmony_ci	case IEEE_8021QAZ_APP_SEL_ANY:
19162306a36Sopenharmony_ci	case IEEE_8021QAZ_APP_SEL_DSCP:
19262306a36Sopenharmony_ci		return DCB_ATTR_IEEE_APP;
19362306a36Sopenharmony_ci	case DCB_APP_SEL_PCP:
19462306a36Sopenharmony_ci		return DCB_ATTR_DCB_APP;
19562306a36Sopenharmony_ci	default:
19662306a36Sopenharmony_ci		return DCB_ATTR_IEEE_APP_UNSPEC;
19762306a36Sopenharmony_ci	}
19862306a36Sopenharmony_ci}
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_cistatic bool dcbnl_app_attr_type_validate(enum ieee_attrs_app type)
20162306a36Sopenharmony_ci{
20262306a36Sopenharmony_ci	switch (type) {
20362306a36Sopenharmony_ci	case DCB_ATTR_IEEE_APP:
20462306a36Sopenharmony_ci	case DCB_ATTR_DCB_APP:
20562306a36Sopenharmony_ci		return true;
20662306a36Sopenharmony_ci	default:
20762306a36Sopenharmony_ci		return false;
20862306a36Sopenharmony_ci	}
20962306a36Sopenharmony_ci}
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_cistatic bool dcbnl_app_selector_validate(enum ieee_attrs_app type, u8 selector)
21262306a36Sopenharmony_ci{
21362306a36Sopenharmony_ci	return dcbnl_app_attr_type_get(selector) == type;
21462306a36Sopenharmony_ci}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_cistatic struct sk_buff *dcbnl_newmsg(int type, u8 cmd, u32 port, u32 seq,
21762306a36Sopenharmony_ci				    u32 flags, struct nlmsghdr **nlhp)
21862306a36Sopenharmony_ci{
21962306a36Sopenharmony_ci	struct sk_buff *skb;
22062306a36Sopenharmony_ci	struct dcbmsg *dcb;
22162306a36Sopenharmony_ci	struct nlmsghdr *nlh;
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
22462306a36Sopenharmony_ci	if (!skb)
22562306a36Sopenharmony_ci		return NULL;
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	nlh = nlmsg_put(skb, port, seq, type, sizeof(*dcb), flags);
22862306a36Sopenharmony_ci	BUG_ON(!nlh);
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	dcb = nlmsg_data(nlh);
23162306a36Sopenharmony_ci	dcb->dcb_family = AF_UNSPEC;
23262306a36Sopenharmony_ci	dcb->cmd = cmd;
23362306a36Sopenharmony_ci	dcb->dcb_pad = 0;
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	if (nlhp)
23662306a36Sopenharmony_ci		*nlhp = nlh;
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	return skb;
23962306a36Sopenharmony_ci}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_cistatic int dcbnl_getstate(struct net_device *netdev, struct nlmsghdr *nlh,
24262306a36Sopenharmony_ci			  u32 seq, struct nlattr **tb, struct sk_buff *skb)
24362306a36Sopenharmony_ci{
24462306a36Sopenharmony_ci	/* if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->getstate) */
24562306a36Sopenharmony_ci	if (!netdev->dcbnl_ops->getstate)
24662306a36Sopenharmony_ci		return -EOPNOTSUPP;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	return nla_put_u8(skb, DCB_ATTR_STATE,
24962306a36Sopenharmony_ci			  netdev->dcbnl_ops->getstate(netdev));
25062306a36Sopenharmony_ci}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_cistatic int dcbnl_getpfccfg(struct net_device *netdev, struct nlmsghdr *nlh,
25362306a36Sopenharmony_ci			   u32 seq, struct nlattr **tb, struct sk_buff *skb)
25462306a36Sopenharmony_ci{
25562306a36Sopenharmony_ci	struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1], *nest;
25662306a36Sopenharmony_ci	u8 value;
25762306a36Sopenharmony_ci	int ret;
25862306a36Sopenharmony_ci	int i;
25962306a36Sopenharmony_ci	int getall = 0;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	if (!tb[DCB_ATTR_PFC_CFG])
26262306a36Sopenharmony_ci		return -EINVAL;
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	if (!netdev->dcbnl_ops->getpfccfg)
26562306a36Sopenharmony_ci		return -EOPNOTSUPP;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	ret = nla_parse_nested_deprecated(data, DCB_PFC_UP_ATTR_MAX,
26862306a36Sopenharmony_ci					  tb[DCB_ATTR_PFC_CFG],
26962306a36Sopenharmony_ci					  dcbnl_pfc_up_nest, NULL);
27062306a36Sopenharmony_ci	if (ret)
27162306a36Sopenharmony_ci		return ret;
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	nest = nla_nest_start_noflag(skb, DCB_ATTR_PFC_CFG);
27462306a36Sopenharmony_ci	if (!nest)
27562306a36Sopenharmony_ci		return -EMSGSIZE;
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	if (data[DCB_PFC_UP_ATTR_ALL])
27862306a36Sopenharmony_ci		getall = 1;
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) {
28162306a36Sopenharmony_ci		if (!getall && !data[i])
28262306a36Sopenharmony_ci			continue;
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci		netdev->dcbnl_ops->getpfccfg(netdev, i - DCB_PFC_UP_ATTR_0,
28562306a36Sopenharmony_ci		                             &value);
28662306a36Sopenharmony_ci		ret = nla_put_u8(skb, i, value);
28762306a36Sopenharmony_ci		if (ret) {
28862306a36Sopenharmony_ci			nla_nest_cancel(skb, nest);
28962306a36Sopenharmony_ci			return ret;
29062306a36Sopenharmony_ci		}
29162306a36Sopenharmony_ci	}
29262306a36Sopenharmony_ci	nla_nest_end(skb, nest);
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	return 0;
29562306a36Sopenharmony_ci}
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_cistatic int dcbnl_getperm_hwaddr(struct net_device *netdev, struct nlmsghdr *nlh,
29862306a36Sopenharmony_ci				u32 seq, struct nlattr **tb, struct sk_buff *skb)
29962306a36Sopenharmony_ci{
30062306a36Sopenharmony_ci	u8 perm_addr[MAX_ADDR_LEN];
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	if (!netdev->dcbnl_ops->getpermhwaddr)
30362306a36Sopenharmony_ci		return -EOPNOTSUPP;
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	memset(perm_addr, 0, sizeof(perm_addr));
30662306a36Sopenharmony_ci	netdev->dcbnl_ops->getpermhwaddr(netdev, perm_addr);
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	return nla_put(skb, DCB_ATTR_PERM_HWADDR, sizeof(perm_addr), perm_addr);
30962306a36Sopenharmony_ci}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_cistatic int dcbnl_getcap(struct net_device *netdev, struct nlmsghdr *nlh,
31262306a36Sopenharmony_ci			u32 seq, struct nlattr **tb, struct sk_buff *skb)
31362306a36Sopenharmony_ci{
31462306a36Sopenharmony_ci	struct nlattr *data[DCB_CAP_ATTR_MAX + 1], *nest;
31562306a36Sopenharmony_ci	u8 value;
31662306a36Sopenharmony_ci	int ret;
31762306a36Sopenharmony_ci	int i;
31862306a36Sopenharmony_ci	int getall = 0;
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	if (!tb[DCB_ATTR_CAP])
32162306a36Sopenharmony_ci		return -EINVAL;
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	if (!netdev->dcbnl_ops->getcap)
32462306a36Sopenharmony_ci		return -EOPNOTSUPP;
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	ret = nla_parse_nested_deprecated(data, DCB_CAP_ATTR_MAX,
32762306a36Sopenharmony_ci					  tb[DCB_ATTR_CAP], dcbnl_cap_nest,
32862306a36Sopenharmony_ci					  NULL);
32962306a36Sopenharmony_ci	if (ret)
33062306a36Sopenharmony_ci		return ret;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	nest = nla_nest_start_noflag(skb, DCB_ATTR_CAP);
33362306a36Sopenharmony_ci	if (!nest)
33462306a36Sopenharmony_ci		return -EMSGSIZE;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	if (data[DCB_CAP_ATTR_ALL])
33762306a36Sopenharmony_ci		getall = 1;
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	for (i = DCB_CAP_ATTR_ALL+1; i <= DCB_CAP_ATTR_MAX; i++) {
34062306a36Sopenharmony_ci		if (!getall && !data[i])
34162306a36Sopenharmony_ci			continue;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci		if (!netdev->dcbnl_ops->getcap(netdev, i, &value)) {
34462306a36Sopenharmony_ci			ret = nla_put_u8(skb, i, value);
34562306a36Sopenharmony_ci			if (ret) {
34662306a36Sopenharmony_ci				nla_nest_cancel(skb, nest);
34762306a36Sopenharmony_ci				return ret;
34862306a36Sopenharmony_ci			}
34962306a36Sopenharmony_ci		}
35062306a36Sopenharmony_ci	}
35162306a36Sopenharmony_ci	nla_nest_end(skb, nest);
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	return 0;
35462306a36Sopenharmony_ci}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_cistatic int dcbnl_getnumtcs(struct net_device *netdev, struct nlmsghdr *nlh,
35762306a36Sopenharmony_ci			   u32 seq, struct nlattr **tb, struct sk_buff *skb)
35862306a36Sopenharmony_ci{
35962306a36Sopenharmony_ci	struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1], *nest;
36062306a36Sopenharmony_ci	u8 value;
36162306a36Sopenharmony_ci	int ret;
36262306a36Sopenharmony_ci	int i;
36362306a36Sopenharmony_ci	int getall = 0;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	if (!tb[DCB_ATTR_NUMTCS])
36662306a36Sopenharmony_ci		return -EINVAL;
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	if (!netdev->dcbnl_ops->getnumtcs)
36962306a36Sopenharmony_ci		return -EOPNOTSUPP;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	ret = nla_parse_nested_deprecated(data, DCB_NUMTCS_ATTR_MAX,
37262306a36Sopenharmony_ci					  tb[DCB_ATTR_NUMTCS],
37362306a36Sopenharmony_ci					  dcbnl_numtcs_nest, NULL);
37462306a36Sopenharmony_ci	if (ret)
37562306a36Sopenharmony_ci		return ret;
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	nest = nla_nest_start_noflag(skb, DCB_ATTR_NUMTCS);
37862306a36Sopenharmony_ci	if (!nest)
37962306a36Sopenharmony_ci		return -EMSGSIZE;
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	if (data[DCB_NUMTCS_ATTR_ALL])
38262306a36Sopenharmony_ci		getall = 1;
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	for (i = DCB_NUMTCS_ATTR_ALL+1; i <= DCB_NUMTCS_ATTR_MAX; i++) {
38562306a36Sopenharmony_ci		if (!getall && !data[i])
38662306a36Sopenharmony_ci			continue;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci		ret = netdev->dcbnl_ops->getnumtcs(netdev, i, &value);
38962306a36Sopenharmony_ci		if (!ret) {
39062306a36Sopenharmony_ci			ret = nla_put_u8(skb, i, value);
39162306a36Sopenharmony_ci			if (ret) {
39262306a36Sopenharmony_ci				nla_nest_cancel(skb, nest);
39362306a36Sopenharmony_ci				return ret;
39462306a36Sopenharmony_ci			}
39562306a36Sopenharmony_ci		} else
39662306a36Sopenharmony_ci			return -EINVAL;
39762306a36Sopenharmony_ci	}
39862306a36Sopenharmony_ci	nla_nest_end(skb, nest);
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	return 0;
40162306a36Sopenharmony_ci}
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_cistatic int dcbnl_setnumtcs(struct net_device *netdev, struct nlmsghdr *nlh,
40462306a36Sopenharmony_ci			   u32 seq, struct nlattr **tb, struct sk_buff *skb)
40562306a36Sopenharmony_ci{
40662306a36Sopenharmony_ci	struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1];
40762306a36Sopenharmony_ci	int ret;
40862306a36Sopenharmony_ci	u8 value;
40962306a36Sopenharmony_ci	int i;
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	if (!tb[DCB_ATTR_NUMTCS])
41262306a36Sopenharmony_ci		return -EINVAL;
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	if (!netdev->dcbnl_ops->setnumtcs)
41562306a36Sopenharmony_ci		return -EOPNOTSUPP;
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	ret = nla_parse_nested_deprecated(data, DCB_NUMTCS_ATTR_MAX,
41862306a36Sopenharmony_ci					  tb[DCB_ATTR_NUMTCS],
41962306a36Sopenharmony_ci					  dcbnl_numtcs_nest, NULL);
42062306a36Sopenharmony_ci	if (ret)
42162306a36Sopenharmony_ci		return ret;
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	for (i = DCB_NUMTCS_ATTR_ALL+1; i <= DCB_NUMTCS_ATTR_MAX; i++) {
42462306a36Sopenharmony_ci		if (data[i] == NULL)
42562306a36Sopenharmony_ci			continue;
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci		value = nla_get_u8(data[i]);
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci		ret = netdev->dcbnl_ops->setnumtcs(netdev, i, value);
43062306a36Sopenharmony_ci		if (ret)
43162306a36Sopenharmony_ci			break;
43262306a36Sopenharmony_ci	}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	return nla_put_u8(skb, DCB_ATTR_NUMTCS, !!ret);
43562306a36Sopenharmony_ci}
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_cistatic int dcbnl_getpfcstate(struct net_device *netdev, struct nlmsghdr *nlh,
43862306a36Sopenharmony_ci			     u32 seq, struct nlattr **tb, struct sk_buff *skb)
43962306a36Sopenharmony_ci{
44062306a36Sopenharmony_ci	if (!netdev->dcbnl_ops->getpfcstate)
44162306a36Sopenharmony_ci		return -EOPNOTSUPP;
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	return nla_put_u8(skb, DCB_ATTR_PFC_STATE,
44462306a36Sopenharmony_ci			  netdev->dcbnl_ops->getpfcstate(netdev));
44562306a36Sopenharmony_ci}
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_cistatic int dcbnl_setpfcstate(struct net_device *netdev, struct nlmsghdr *nlh,
44862306a36Sopenharmony_ci			     u32 seq, struct nlattr **tb, struct sk_buff *skb)
44962306a36Sopenharmony_ci{
45062306a36Sopenharmony_ci	u8 value;
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	if (!tb[DCB_ATTR_PFC_STATE])
45362306a36Sopenharmony_ci		return -EINVAL;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	if (!netdev->dcbnl_ops->setpfcstate)
45662306a36Sopenharmony_ci		return -EOPNOTSUPP;
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	value = nla_get_u8(tb[DCB_ATTR_PFC_STATE]);
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	netdev->dcbnl_ops->setpfcstate(netdev, value);
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	return nla_put_u8(skb, DCB_ATTR_PFC_STATE, 0);
46362306a36Sopenharmony_ci}
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_cistatic int dcbnl_getapp(struct net_device *netdev, struct nlmsghdr *nlh,
46662306a36Sopenharmony_ci			u32 seq, struct nlattr **tb, struct sk_buff *skb)
46762306a36Sopenharmony_ci{
46862306a36Sopenharmony_ci	struct nlattr *app_nest;
46962306a36Sopenharmony_ci	struct nlattr *app_tb[DCB_APP_ATTR_MAX + 1];
47062306a36Sopenharmony_ci	u16 id;
47162306a36Sopenharmony_ci	u8 up, idtype;
47262306a36Sopenharmony_ci	int ret;
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	if (!tb[DCB_ATTR_APP])
47562306a36Sopenharmony_ci		return -EINVAL;
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	ret = nla_parse_nested_deprecated(app_tb, DCB_APP_ATTR_MAX,
47862306a36Sopenharmony_ci					  tb[DCB_ATTR_APP], dcbnl_app_nest,
47962306a36Sopenharmony_ci					  NULL);
48062306a36Sopenharmony_ci	if (ret)
48162306a36Sopenharmony_ci		return ret;
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	/* all must be non-null */
48462306a36Sopenharmony_ci	if ((!app_tb[DCB_APP_ATTR_IDTYPE]) ||
48562306a36Sopenharmony_ci	    (!app_tb[DCB_APP_ATTR_ID]))
48662306a36Sopenharmony_ci		return -EINVAL;
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	/* either by eth type or by socket number */
48962306a36Sopenharmony_ci	idtype = nla_get_u8(app_tb[DCB_APP_ATTR_IDTYPE]);
49062306a36Sopenharmony_ci	if ((idtype != DCB_APP_IDTYPE_ETHTYPE) &&
49162306a36Sopenharmony_ci	    (idtype != DCB_APP_IDTYPE_PORTNUM))
49262306a36Sopenharmony_ci		return -EINVAL;
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]);
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	if (netdev->dcbnl_ops->getapp) {
49762306a36Sopenharmony_ci		ret = netdev->dcbnl_ops->getapp(netdev, idtype, id);
49862306a36Sopenharmony_ci		if (ret < 0)
49962306a36Sopenharmony_ci			return ret;
50062306a36Sopenharmony_ci		else
50162306a36Sopenharmony_ci			up = ret;
50262306a36Sopenharmony_ci	} else {
50362306a36Sopenharmony_ci		struct dcb_app app = {
50462306a36Sopenharmony_ci					.selector = idtype,
50562306a36Sopenharmony_ci					.protocol = id,
50662306a36Sopenharmony_ci				     };
50762306a36Sopenharmony_ci		up = dcb_getapp(netdev, &app);
50862306a36Sopenharmony_ci	}
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	app_nest = nla_nest_start_noflag(skb, DCB_ATTR_APP);
51162306a36Sopenharmony_ci	if (!app_nest)
51262306a36Sopenharmony_ci		return -EMSGSIZE;
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	ret = nla_put_u8(skb, DCB_APP_ATTR_IDTYPE, idtype);
51562306a36Sopenharmony_ci	if (ret)
51662306a36Sopenharmony_ci		goto out_cancel;
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	ret = nla_put_u16(skb, DCB_APP_ATTR_ID, id);
51962306a36Sopenharmony_ci	if (ret)
52062306a36Sopenharmony_ci		goto out_cancel;
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	ret = nla_put_u8(skb, DCB_APP_ATTR_PRIORITY, up);
52362306a36Sopenharmony_ci	if (ret)
52462306a36Sopenharmony_ci		goto out_cancel;
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	nla_nest_end(skb, app_nest);
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	return 0;
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ciout_cancel:
53162306a36Sopenharmony_ci	nla_nest_cancel(skb, app_nest);
53262306a36Sopenharmony_ci	return ret;
53362306a36Sopenharmony_ci}
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_cistatic int dcbnl_setapp(struct net_device *netdev, struct nlmsghdr *nlh,
53662306a36Sopenharmony_ci			u32 seq, struct nlattr **tb, struct sk_buff *skb)
53762306a36Sopenharmony_ci{
53862306a36Sopenharmony_ci	int ret;
53962306a36Sopenharmony_ci	u16 id;
54062306a36Sopenharmony_ci	u8 up, idtype;
54162306a36Sopenharmony_ci	struct nlattr *app_tb[DCB_APP_ATTR_MAX + 1];
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	if (!tb[DCB_ATTR_APP])
54462306a36Sopenharmony_ci		return -EINVAL;
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	ret = nla_parse_nested_deprecated(app_tb, DCB_APP_ATTR_MAX,
54762306a36Sopenharmony_ci					  tb[DCB_ATTR_APP], dcbnl_app_nest,
54862306a36Sopenharmony_ci					  NULL);
54962306a36Sopenharmony_ci	if (ret)
55062306a36Sopenharmony_ci		return ret;
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	/* all must be non-null */
55362306a36Sopenharmony_ci	if ((!app_tb[DCB_APP_ATTR_IDTYPE]) ||
55462306a36Sopenharmony_ci	    (!app_tb[DCB_APP_ATTR_ID]) ||
55562306a36Sopenharmony_ci	    (!app_tb[DCB_APP_ATTR_PRIORITY]))
55662306a36Sopenharmony_ci		return -EINVAL;
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	/* either by eth type or by socket number */
55962306a36Sopenharmony_ci	idtype = nla_get_u8(app_tb[DCB_APP_ATTR_IDTYPE]);
56062306a36Sopenharmony_ci	if ((idtype != DCB_APP_IDTYPE_ETHTYPE) &&
56162306a36Sopenharmony_ci	    (idtype != DCB_APP_IDTYPE_PORTNUM))
56262306a36Sopenharmony_ci		return -EINVAL;
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci	id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]);
56562306a36Sopenharmony_ci	up = nla_get_u8(app_tb[DCB_APP_ATTR_PRIORITY]);
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	if (netdev->dcbnl_ops->setapp) {
56862306a36Sopenharmony_ci		ret = netdev->dcbnl_ops->setapp(netdev, idtype, id, up);
56962306a36Sopenharmony_ci		if (ret < 0)
57062306a36Sopenharmony_ci			return ret;
57162306a36Sopenharmony_ci	} else {
57262306a36Sopenharmony_ci		struct dcb_app app;
57362306a36Sopenharmony_ci		app.selector = idtype;
57462306a36Sopenharmony_ci		app.protocol = id;
57562306a36Sopenharmony_ci		app.priority = up;
57662306a36Sopenharmony_ci		ret = dcb_setapp(netdev, &app);
57762306a36Sopenharmony_ci	}
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	ret = nla_put_u8(skb, DCB_ATTR_APP, ret);
58062306a36Sopenharmony_ci	dcbnl_cee_notify(netdev, RTM_SETDCB, DCB_CMD_SAPP, seq, 0);
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	return ret;
58362306a36Sopenharmony_ci}
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_cistatic int __dcbnl_pg_getcfg(struct net_device *netdev, struct nlmsghdr *nlh,
58662306a36Sopenharmony_ci			     struct nlattr **tb, struct sk_buff *skb, int dir)
58762306a36Sopenharmony_ci{
58862306a36Sopenharmony_ci	struct nlattr *pg_nest, *param_nest, *data;
58962306a36Sopenharmony_ci	struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1];
59062306a36Sopenharmony_ci	struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1];
59162306a36Sopenharmony_ci	u8 prio, pgid, tc_pct, up_map;
59262306a36Sopenharmony_ci	int ret;
59362306a36Sopenharmony_ci	int getall = 0;
59462306a36Sopenharmony_ci	int i;
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	if (!tb[DCB_ATTR_PG_CFG])
59762306a36Sopenharmony_ci		return -EINVAL;
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	if (!netdev->dcbnl_ops->getpgtccfgtx ||
60062306a36Sopenharmony_ci	    !netdev->dcbnl_ops->getpgtccfgrx ||
60162306a36Sopenharmony_ci	    !netdev->dcbnl_ops->getpgbwgcfgtx ||
60262306a36Sopenharmony_ci	    !netdev->dcbnl_ops->getpgbwgcfgrx)
60362306a36Sopenharmony_ci		return -EOPNOTSUPP;
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	ret = nla_parse_nested_deprecated(pg_tb, DCB_PG_ATTR_MAX,
60662306a36Sopenharmony_ci					  tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest,
60762306a36Sopenharmony_ci					  NULL);
60862306a36Sopenharmony_ci	if (ret)
60962306a36Sopenharmony_ci		return ret;
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	pg_nest = nla_nest_start_noflag(skb, DCB_ATTR_PG_CFG);
61262306a36Sopenharmony_ci	if (!pg_nest)
61362306a36Sopenharmony_ci		return -EMSGSIZE;
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	if (pg_tb[DCB_PG_ATTR_TC_ALL])
61662306a36Sopenharmony_ci		getall = 1;
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) {
61962306a36Sopenharmony_ci		if (!getall && !pg_tb[i])
62062306a36Sopenharmony_ci			continue;
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci		if (pg_tb[DCB_PG_ATTR_TC_ALL])
62362306a36Sopenharmony_ci			data = pg_tb[DCB_PG_ATTR_TC_ALL];
62462306a36Sopenharmony_ci		else
62562306a36Sopenharmony_ci			data = pg_tb[i];
62662306a36Sopenharmony_ci		ret = nla_parse_nested_deprecated(param_tb,
62762306a36Sopenharmony_ci						  DCB_TC_ATTR_PARAM_MAX, data,
62862306a36Sopenharmony_ci						  dcbnl_tc_param_nest, NULL);
62962306a36Sopenharmony_ci		if (ret)
63062306a36Sopenharmony_ci			goto err_pg;
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci		param_nest = nla_nest_start_noflag(skb, i);
63362306a36Sopenharmony_ci		if (!param_nest)
63462306a36Sopenharmony_ci			goto err_pg;
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci		pgid = DCB_ATTR_VALUE_UNDEFINED;
63762306a36Sopenharmony_ci		prio = DCB_ATTR_VALUE_UNDEFINED;
63862306a36Sopenharmony_ci		tc_pct = DCB_ATTR_VALUE_UNDEFINED;
63962306a36Sopenharmony_ci		up_map = DCB_ATTR_VALUE_UNDEFINED;
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci		if (dir) {
64262306a36Sopenharmony_ci			/* Rx */
64362306a36Sopenharmony_ci			netdev->dcbnl_ops->getpgtccfgrx(netdev,
64462306a36Sopenharmony_ci						i - DCB_PG_ATTR_TC_0, &prio,
64562306a36Sopenharmony_ci						&pgid, &tc_pct, &up_map);
64662306a36Sopenharmony_ci		} else {
64762306a36Sopenharmony_ci			/* Tx */
64862306a36Sopenharmony_ci			netdev->dcbnl_ops->getpgtccfgtx(netdev,
64962306a36Sopenharmony_ci						i - DCB_PG_ATTR_TC_0, &prio,
65062306a36Sopenharmony_ci						&pgid, &tc_pct, &up_map);
65162306a36Sopenharmony_ci		}
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci		if (param_tb[DCB_TC_ATTR_PARAM_PGID] ||
65462306a36Sopenharmony_ci		    param_tb[DCB_TC_ATTR_PARAM_ALL]) {
65562306a36Sopenharmony_ci			ret = nla_put_u8(skb,
65662306a36Sopenharmony_ci			                 DCB_TC_ATTR_PARAM_PGID, pgid);
65762306a36Sopenharmony_ci			if (ret)
65862306a36Sopenharmony_ci				goto err_param;
65962306a36Sopenharmony_ci		}
66062306a36Sopenharmony_ci		if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING] ||
66162306a36Sopenharmony_ci		    param_tb[DCB_TC_ATTR_PARAM_ALL]) {
66262306a36Sopenharmony_ci			ret = nla_put_u8(skb,
66362306a36Sopenharmony_ci			                 DCB_TC_ATTR_PARAM_UP_MAPPING, up_map);
66462306a36Sopenharmony_ci			if (ret)
66562306a36Sopenharmony_ci				goto err_param;
66662306a36Sopenharmony_ci		}
66762306a36Sopenharmony_ci		if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO] ||
66862306a36Sopenharmony_ci		    param_tb[DCB_TC_ATTR_PARAM_ALL]) {
66962306a36Sopenharmony_ci			ret = nla_put_u8(skb,
67062306a36Sopenharmony_ci			                 DCB_TC_ATTR_PARAM_STRICT_PRIO, prio);
67162306a36Sopenharmony_ci			if (ret)
67262306a36Sopenharmony_ci				goto err_param;
67362306a36Sopenharmony_ci		}
67462306a36Sopenharmony_ci		if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT] ||
67562306a36Sopenharmony_ci		    param_tb[DCB_TC_ATTR_PARAM_ALL]) {
67662306a36Sopenharmony_ci			ret = nla_put_u8(skb, DCB_TC_ATTR_PARAM_BW_PCT,
67762306a36Sopenharmony_ci			                 tc_pct);
67862306a36Sopenharmony_ci			if (ret)
67962306a36Sopenharmony_ci				goto err_param;
68062306a36Sopenharmony_ci		}
68162306a36Sopenharmony_ci		nla_nest_end(skb, param_nest);
68262306a36Sopenharmony_ci	}
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	if (pg_tb[DCB_PG_ATTR_BW_ID_ALL])
68562306a36Sopenharmony_ci		getall = 1;
68662306a36Sopenharmony_ci	else
68762306a36Sopenharmony_ci		getall = 0;
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) {
69062306a36Sopenharmony_ci		if (!getall && !pg_tb[i])
69162306a36Sopenharmony_ci			continue;
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci		tc_pct = DCB_ATTR_VALUE_UNDEFINED;
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci		if (dir) {
69662306a36Sopenharmony_ci			/* Rx */
69762306a36Sopenharmony_ci			netdev->dcbnl_ops->getpgbwgcfgrx(netdev,
69862306a36Sopenharmony_ci					i - DCB_PG_ATTR_BW_ID_0, &tc_pct);
69962306a36Sopenharmony_ci		} else {
70062306a36Sopenharmony_ci			/* Tx */
70162306a36Sopenharmony_ci			netdev->dcbnl_ops->getpgbwgcfgtx(netdev,
70262306a36Sopenharmony_ci					i - DCB_PG_ATTR_BW_ID_0, &tc_pct);
70362306a36Sopenharmony_ci		}
70462306a36Sopenharmony_ci		ret = nla_put_u8(skb, i, tc_pct);
70562306a36Sopenharmony_ci		if (ret)
70662306a36Sopenharmony_ci			goto err_pg;
70762306a36Sopenharmony_ci	}
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci	nla_nest_end(skb, pg_nest);
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	return 0;
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_cierr_param:
71462306a36Sopenharmony_ci	nla_nest_cancel(skb, param_nest);
71562306a36Sopenharmony_cierr_pg:
71662306a36Sopenharmony_ci	nla_nest_cancel(skb, pg_nest);
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci	return -EMSGSIZE;
71962306a36Sopenharmony_ci}
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_cistatic int dcbnl_pgtx_getcfg(struct net_device *netdev, struct nlmsghdr *nlh,
72262306a36Sopenharmony_ci			     u32 seq, struct nlattr **tb, struct sk_buff *skb)
72362306a36Sopenharmony_ci{
72462306a36Sopenharmony_ci	return __dcbnl_pg_getcfg(netdev, nlh, tb, skb, 0);
72562306a36Sopenharmony_ci}
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_cistatic int dcbnl_pgrx_getcfg(struct net_device *netdev, struct nlmsghdr *nlh,
72862306a36Sopenharmony_ci			     u32 seq, struct nlattr **tb, struct sk_buff *skb)
72962306a36Sopenharmony_ci{
73062306a36Sopenharmony_ci	return __dcbnl_pg_getcfg(netdev, nlh, tb, skb, 1);
73162306a36Sopenharmony_ci}
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_cistatic int dcbnl_setstate(struct net_device *netdev, struct nlmsghdr *nlh,
73462306a36Sopenharmony_ci			  u32 seq, struct nlattr **tb, struct sk_buff *skb)
73562306a36Sopenharmony_ci{
73662306a36Sopenharmony_ci	u8 value;
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci	if (!tb[DCB_ATTR_STATE])
73962306a36Sopenharmony_ci		return -EINVAL;
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci	if (!netdev->dcbnl_ops->setstate)
74262306a36Sopenharmony_ci		return -EOPNOTSUPP;
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci	value = nla_get_u8(tb[DCB_ATTR_STATE]);
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ci	return nla_put_u8(skb, DCB_ATTR_STATE,
74762306a36Sopenharmony_ci			  netdev->dcbnl_ops->setstate(netdev, value));
74862306a36Sopenharmony_ci}
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_cistatic int dcbnl_setpfccfg(struct net_device *netdev, struct nlmsghdr *nlh,
75162306a36Sopenharmony_ci			   u32 seq, struct nlattr **tb, struct sk_buff *skb)
75262306a36Sopenharmony_ci{
75362306a36Sopenharmony_ci	struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1];
75462306a36Sopenharmony_ci	int i;
75562306a36Sopenharmony_ci	int ret;
75662306a36Sopenharmony_ci	u8 value;
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci	if (!tb[DCB_ATTR_PFC_CFG])
75962306a36Sopenharmony_ci		return -EINVAL;
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci	if (!netdev->dcbnl_ops->setpfccfg)
76262306a36Sopenharmony_ci		return -EOPNOTSUPP;
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci	ret = nla_parse_nested_deprecated(data, DCB_PFC_UP_ATTR_MAX,
76562306a36Sopenharmony_ci					  tb[DCB_ATTR_PFC_CFG],
76662306a36Sopenharmony_ci					  dcbnl_pfc_up_nest, NULL);
76762306a36Sopenharmony_ci	if (ret)
76862306a36Sopenharmony_ci		return ret;
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) {
77162306a36Sopenharmony_ci		if (data[i] == NULL)
77262306a36Sopenharmony_ci			continue;
77362306a36Sopenharmony_ci		value = nla_get_u8(data[i]);
77462306a36Sopenharmony_ci		netdev->dcbnl_ops->setpfccfg(netdev,
77562306a36Sopenharmony_ci			data[i]->nla_type - DCB_PFC_UP_ATTR_0, value);
77662306a36Sopenharmony_ci	}
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci	return nla_put_u8(skb, DCB_ATTR_PFC_CFG, 0);
77962306a36Sopenharmony_ci}
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_cistatic int dcbnl_setall(struct net_device *netdev, struct nlmsghdr *nlh,
78262306a36Sopenharmony_ci			u32 seq, struct nlattr **tb, struct sk_buff *skb)
78362306a36Sopenharmony_ci{
78462306a36Sopenharmony_ci	int ret;
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci	if (!tb[DCB_ATTR_SET_ALL])
78762306a36Sopenharmony_ci		return -EINVAL;
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci	if (!netdev->dcbnl_ops->setall)
79062306a36Sopenharmony_ci		return -EOPNOTSUPP;
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci	ret = nla_put_u8(skb, DCB_ATTR_SET_ALL,
79362306a36Sopenharmony_ci			 netdev->dcbnl_ops->setall(netdev));
79462306a36Sopenharmony_ci	dcbnl_cee_notify(netdev, RTM_SETDCB, DCB_CMD_SET_ALL, seq, 0);
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci	return ret;
79762306a36Sopenharmony_ci}
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_cistatic int __dcbnl_pg_setcfg(struct net_device *netdev, struct nlmsghdr *nlh,
80062306a36Sopenharmony_ci			     u32 seq, struct nlattr **tb, struct sk_buff *skb,
80162306a36Sopenharmony_ci			     int dir)
80262306a36Sopenharmony_ci{
80362306a36Sopenharmony_ci	struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1];
80462306a36Sopenharmony_ci	struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1];
80562306a36Sopenharmony_ci	int ret;
80662306a36Sopenharmony_ci	int i;
80762306a36Sopenharmony_ci	u8 pgid;
80862306a36Sopenharmony_ci	u8 up_map;
80962306a36Sopenharmony_ci	u8 prio;
81062306a36Sopenharmony_ci	u8 tc_pct;
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci	if (!tb[DCB_ATTR_PG_CFG])
81362306a36Sopenharmony_ci		return -EINVAL;
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci	if (!netdev->dcbnl_ops->setpgtccfgtx ||
81662306a36Sopenharmony_ci	    !netdev->dcbnl_ops->setpgtccfgrx ||
81762306a36Sopenharmony_ci	    !netdev->dcbnl_ops->setpgbwgcfgtx ||
81862306a36Sopenharmony_ci	    !netdev->dcbnl_ops->setpgbwgcfgrx)
81962306a36Sopenharmony_ci		return -EOPNOTSUPP;
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci	ret = nla_parse_nested_deprecated(pg_tb, DCB_PG_ATTR_MAX,
82262306a36Sopenharmony_ci					  tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest,
82362306a36Sopenharmony_ci					  NULL);
82462306a36Sopenharmony_ci	if (ret)
82562306a36Sopenharmony_ci		return ret;
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) {
82862306a36Sopenharmony_ci		if (!pg_tb[i])
82962306a36Sopenharmony_ci			continue;
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci		ret = nla_parse_nested_deprecated(param_tb,
83262306a36Sopenharmony_ci						  DCB_TC_ATTR_PARAM_MAX,
83362306a36Sopenharmony_ci						  pg_tb[i],
83462306a36Sopenharmony_ci						  dcbnl_tc_param_nest, NULL);
83562306a36Sopenharmony_ci		if (ret)
83662306a36Sopenharmony_ci			return ret;
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci		pgid = DCB_ATTR_VALUE_UNDEFINED;
83962306a36Sopenharmony_ci		prio = DCB_ATTR_VALUE_UNDEFINED;
84062306a36Sopenharmony_ci		tc_pct = DCB_ATTR_VALUE_UNDEFINED;
84162306a36Sopenharmony_ci		up_map = DCB_ATTR_VALUE_UNDEFINED;
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci		if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO])
84462306a36Sopenharmony_ci			prio =
84562306a36Sopenharmony_ci			    nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO]);
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci		if (param_tb[DCB_TC_ATTR_PARAM_PGID])
84862306a36Sopenharmony_ci			pgid = nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_PGID]);
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci		if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT])
85162306a36Sopenharmony_ci			tc_pct = nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_BW_PCT]);
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci		if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING])
85462306a36Sopenharmony_ci			up_map =
85562306a36Sopenharmony_ci			     nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING]);
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci		/* dir: Tx = 0, Rx = 1 */
85862306a36Sopenharmony_ci		if (dir) {
85962306a36Sopenharmony_ci			/* Rx */
86062306a36Sopenharmony_ci			netdev->dcbnl_ops->setpgtccfgrx(netdev,
86162306a36Sopenharmony_ci				i - DCB_PG_ATTR_TC_0,
86262306a36Sopenharmony_ci				prio, pgid, tc_pct, up_map);
86362306a36Sopenharmony_ci		} else {
86462306a36Sopenharmony_ci			/* Tx */
86562306a36Sopenharmony_ci			netdev->dcbnl_ops->setpgtccfgtx(netdev,
86662306a36Sopenharmony_ci				i - DCB_PG_ATTR_TC_0,
86762306a36Sopenharmony_ci				prio, pgid, tc_pct, up_map);
86862306a36Sopenharmony_ci		}
86962306a36Sopenharmony_ci	}
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci	for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) {
87262306a36Sopenharmony_ci		if (!pg_tb[i])
87362306a36Sopenharmony_ci			continue;
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci		tc_pct = nla_get_u8(pg_tb[i]);
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci		/* dir: Tx = 0, Rx = 1 */
87862306a36Sopenharmony_ci		if (dir) {
87962306a36Sopenharmony_ci			/* Rx */
88062306a36Sopenharmony_ci			netdev->dcbnl_ops->setpgbwgcfgrx(netdev,
88162306a36Sopenharmony_ci					 i - DCB_PG_ATTR_BW_ID_0, tc_pct);
88262306a36Sopenharmony_ci		} else {
88362306a36Sopenharmony_ci			/* Tx */
88462306a36Sopenharmony_ci			netdev->dcbnl_ops->setpgbwgcfgtx(netdev,
88562306a36Sopenharmony_ci					 i - DCB_PG_ATTR_BW_ID_0, tc_pct);
88662306a36Sopenharmony_ci		}
88762306a36Sopenharmony_ci	}
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci	return nla_put_u8(skb, DCB_ATTR_PG_CFG, 0);
89062306a36Sopenharmony_ci}
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_cistatic int dcbnl_pgtx_setcfg(struct net_device *netdev, struct nlmsghdr *nlh,
89362306a36Sopenharmony_ci			     u32 seq, struct nlattr **tb, struct sk_buff *skb)
89462306a36Sopenharmony_ci{
89562306a36Sopenharmony_ci	return __dcbnl_pg_setcfg(netdev, nlh, seq, tb, skb, 0);
89662306a36Sopenharmony_ci}
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_cistatic int dcbnl_pgrx_setcfg(struct net_device *netdev, struct nlmsghdr *nlh,
89962306a36Sopenharmony_ci			     u32 seq, struct nlattr **tb, struct sk_buff *skb)
90062306a36Sopenharmony_ci{
90162306a36Sopenharmony_ci	return __dcbnl_pg_setcfg(netdev, nlh, seq, tb, skb, 1);
90262306a36Sopenharmony_ci}
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_cistatic int dcbnl_bcn_getcfg(struct net_device *netdev, struct nlmsghdr *nlh,
90562306a36Sopenharmony_ci			    u32 seq, struct nlattr **tb, struct sk_buff *skb)
90662306a36Sopenharmony_ci{
90762306a36Sopenharmony_ci	struct nlattr *bcn_nest;
90862306a36Sopenharmony_ci	struct nlattr *bcn_tb[DCB_BCN_ATTR_MAX + 1];
90962306a36Sopenharmony_ci	u8 value_byte;
91062306a36Sopenharmony_ci	u32 value_integer;
91162306a36Sopenharmony_ci	int ret;
91262306a36Sopenharmony_ci	bool getall = false;
91362306a36Sopenharmony_ci	int i;
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci	if (!tb[DCB_ATTR_BCN])
91662306a36Sopenharmony_ci		return -EINVAL;
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci	if (!netdev->dcbnl_ops->getbcnrp ||
91962306a36Sopenharmony_ci	    !netdev->dcbnl_ops->getbcncfg)
92062306a36Sopenharmony_ci		return -EOPNOTSUPP;
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci	ret = nla_parse_nested_deprecated(bcn_tb, DCB_BCN_ATTR_MAX,
92362306a36Sopenharmony_ci					  tb[DCB_ATTR_BCN], dcbnl_bcn_nest,
92462306a36Sopenharmony_ci					  NULL);
92562306a36Sopenharmony_ci	if (ret)
92662306a36Sopenharmony_ci		return ret;
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ci	bcn_nest = nla_nest_start_noflag(skb, DCB_ATTR_BCN);
92962306a36Sopenharmony_ci	if (!bcn_nest)
93062306a36Sopenharmony_ci		return -EMSGSIZE;
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci	if (bcn_tb[DCB_BCN_ATTR_ALL])
93362306a36Sopenharmony_ci		getall = true;
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	for (i = DCB_BCN_ATTR_RP_0; i <= DCB_BCN_ATTR_RP_7; i++) {
93662306a36Sopenharmony_ci		if (!getall && !bcn_tb[i])
93762306a36Sopenharmony_ci			continue;
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci		netdev->dcbnl_ops->getbcnrp(netdev, i - DCB_BCN_ATTR_RP_0,
94062306a36Sopenharmony_ci		                            &value_byte);
94162306a36Sopenharmony_ci		ret = nla_put_u8(skb, i, value_byte);
94262306a36Sopenharmony_ci		if (ret)
94362306a36Sopenharmony_ci			goto err_bcn;
94462306a36Sopenharmony_ci	}
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci	for (i = DCB_BCN_ATTR_BCNA_0; i <= DCB_BCN_ATTR_RI; i++) {
94762306a36Sopenharmony_ci		if (!getall && !bcn_tb[i])
94862306a36Sopenharmony_ci			continue;
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci		netdev->dcbnl_ops->getbcncfg(netdev, i,
95162306a36Sopenharmony_ci		                             &value_integer);
95262306a36Sopenharmony_ci		ret = nla_put_u32(skb, i, value_integer);
95362306a36Sopenharmony_ci		if (ret)
95462306a36Sopenharmony_ci			goto err_bcn;
95562306a36Sopenharmony_ci	}
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci	nla_nest_end(skb, bcn_nest);
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ci	return 0;
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_cierr_bcn:
96262306a36Sopenharmony_ci	nla_nest_cancel(skb, bcn_nest);
96362306a36Sopenharmony_ci	return ret;
96462306a36Sopenharmony_ci}
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_cistatic int dcbnl_bcn_setcfg(struct net_device *netdev, struct nlmsghdr *nlh,
96762306a36Sopenharmony_ci			    u32 seq, struct nlattr **tb, struct sk_buff *skb)
96862306a36Sopenharmony_ci{
96962306a36Sopenharmony_ci	struct nlattr *data[DCB_BCN_ATTR_MAX + 1];
97062306a36Sopenharmony_ci	int i;
97162306a36Sopenharmony_ci	int ret;
97262306a36Sopenharmony_ci	u8 value_byte;
97362306a36Sopenharmony_ci	u32 value_int;
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	if (!tb[DCB_ATTR_BCN])
97662306a36Sopenharmony_ci		return -EINVAL;
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci	if (!netdev->dcbnl_ops->setbcncfg ||
97962306a36Sopenharmony_ci	    !netdev->dcbnl_ops->setbcnrp)
98062306a36Sopenharmony_ci		return -EOPNOTSUPP;
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci	ret = nla_parse_nested_deprecated(data, DCB_BCN_ATTR_MAX,
98362306a36Sopenharmony_ci					  tb[DCB_ATTR_BCN], dcbnl_bcn_nest,
98462306a36Sopenharmony_ci					  NULL);
98562306a36Sopenharmony_ci	if (ret)
98662306a36Sopenharmony_ci		return ret;
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci	for (i = DCB_BCN_ATTR_RP_0; i <= DCB_BCN_ATTR_RP_7; i++) {
98962306a36Sopenharmony_ci		if (data[i] == NULL)
99062306a36Sopenharmony_ci			continue;
99162306a36Sopenharmony_ci		value_byte = nla_get_u8(data[i]);
99262306a36Sopenharmony_ci		netdev->dcbnl_ops->setbcnrp(netdev,
99362306a36Sopenharmony_ci			data[i]->nla_type - DCB_BCN_ATTR_RP_0, value_byte);
99462306a36Sopenharmony_ci	}
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_ci	for (i = DCB_BCN_ATTR_BCNA_0; i <= DCB_BCN_ATTR_RI; i++) {
99762306a36Sopenharmony_ci		if (data[i] == NULL)
99862306a36Sopenharmony_ci			continue;
99962306a36Sopenharmony_ci		value_int = nla_get_u32(data[i]);
100062306a36Sopenharmony_ci		netdev->dcbnl_ops->setbcncfg(netdev,
100162306a36Sopenharmony_ci	                                     i, value_int);
100262306a36Sopenharmony_ci	}
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci	return nla_put_u8(skb, DCB_ATTR_BCN, 0);
100562306a36Sopenharmony_ci}
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_cistatic int dcbnl_build_peer_app(struct net_device *netdev, struct sk_buff* skb,
100862306a36Sopenharmony_ci				int app_nested_type, int app_info_type,
100962306a36Sopenharmony_ci				int app_entry_type)
101062306a36Sopenharmony_ci{
101162306a36Sopenharmony_ci	struct dcb_peer_app_info info;
101262306a36Sopenharmony_ci	struct dcb_app *table = NULL;
101362306a36Sopenharmony_ci	const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
101462306a36Sopenharmony_ci	u16 app_count;
101562306a36Sopenharmony_ci	int err;
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci	/**
101962306a36Sopenharmony_ci	 * retrieve the peer app configuration form the driver. If the driver
102062306a36Sopenharmony_ci	 * handlers fail exit without doing anything
102162306a36Sopenharmony_ci	 */
102262306a36Sopenharmony_ci	err = ops->peer_getappinfo(netdev, &info, &app_count);
102362306a36Sopenharmony_ci	if (!err && app_count) {
102462306a36Sopenharmony_ci		table = kmalloc_array(app_count, sizeof(struct dcb_app),
102562306a36Sopenharmony_ci				      GFP_KERNEL);
102662306a36Sopenharmony_ci		if (!table)
102762306a36Sopenharmony_ci			return -ENOMEM;
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_ci		err = ops->peer_getapptable(netdev, table);
103062306a36Sopenharmony_ci	}
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci	if (!err) {
103362306a36Sopenharmony_ci		u16 i;
103462306a36Sopenharmony_ci		struct nlattr *app;
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_ci		/**
103762306a36Sopenharmony_ci		 * build the message, from here on the only possible failure
103862306a36Sopenharmony_ci		 * is due to the skb size
103962306a36Sopenharmony_ci		 */
104062306a36Sopenharmony_ci		err = -EMSGSIZE;
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci		app = nla_nest_start_noflag(skb, app_nested_type);
104362306a36Sopenharmony_ci		if (!app)
104462306a36Sopenharmony_ci			goto nla_put_failure;
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci		if (app_info_type &&
104762306a36Sopenharmony_ci		    nla_put(skb, app_info_type, sizeof(info), &info))
104862306a36Sopenharmony_ci			goto nla_put_failure;
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_ci		for (i = 0; i < app_count; i++) {
105162306a36Sopenharmony_ci			if (nla_put(skb, app_entry_type, sizeof(struct dcb_app),
105262306a36Sopenharmony_ci				    &table[i]))
105362306a36Sopenharmony_ci				goto nla_put_failure;
105462306a36Sopenharmony_ci		}
105562306a36Sopenharmony_ci		nla_nest_end(skb, app);
105662306a36Sopenharmony_ci	}
105762306a36Sopenharmony_ci	err = 0;
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_cinla_put_failure:
106062306a36Sopenharmony_ci	kfree(table);
106162306a36Sopenharmony_ci	return err;
106262306a36Sopenharmony_ci}
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_cistatic int dcbnl_getapptrust(struct net_device *netdev, struct sk_buff *skb)
106562306a36Sopenharmony_ci{
106662306a36Sopenharmony_ci	const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
106762306a36Sopenharmony_ci	enum ieee_attrs_app type;
106862306a36Sopenharmony_ci	struct nlattr *apptrust;
106962306a36Sopenharmony_ci	int nselectors, err, i;
107062306a36Sopenharmony_ci	u8 *selectors;
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci	selectors = kzalloc(IEEE_8021QAZ_APP_SEL_MAX + 1, GFP_KERNEL);
107362306a36Sopenharmony_ci	if (!selectors)
107462306a36Sopenharmony_ci		return -ENOMEM;
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci	err = ops->dcbnl_getapptrust(netdev, selectors, &nselectors);
107762306a36Sopenharmony_ci	if (err) {
107862306a36Sopenharmony_ci		err = 0;
107962306a36Sopenharmony_ci		goto out;
108062306a36Sopenharmony_ci	}
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci	apptrust = nla_nest_start(skb, DCB_ATTR_DCB_APP_TRUST_TABLE);
108362306a36Sopenharmony_ci	if (!apptrust) {
108462306a36Sopenharmony_ci		err = -EMSGSIZE;
108562306a36Sopenharmony_ci		goto out;
108662306a36Sopenharmony_ci	}
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci	for (i = 0; i < nselectors; i++) {
108962306a36Sopenharmony_ci		type = dcbnl_app_attr_type_get(selectors[i]);
109062306a36Sopenharmony_ci		err = nla_put_u8(skb, type, selectors[i]);
109162306a36Sopenharmony_ci		if (err) {
109262306a36Sopenharmony_ci			nla_nest_cancel(skb, apptrust);
109362306a36Sopenharmony_ci			goto out;
109462306a36Sopenharmony_ci		}
109562306a36Sopenharmony_ci	}
109662306a36Sopenharmony_ci	nla_nest_end(skb, apptrust);
109762306a36Sopenharmony_ci
109862306a36Sopenharmony_ciout:
109962306a36Sopenharmony_ci	kfree(selectors);
110062306a36Sopenharmony_ci	return err;
110162306a36Sopenharmony_ci}
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_ci/* Set or delete APP table or rewrite table entries. The APP struct is validated
110462306a36Sopenharmony_ci * and the appropriate callback function is called.
110562306a36Sopenharmony_ci */
110662306a36Sopenharmony_cistatic int dcbnl_app_table_setdel(struct nlattr *attr,
110762306a36Sopenharmony_ci				  struct net_device *netdev,
110862306a36Sopenharmony_ci				  int (*setdel)(struct net_device *dev,
110962306a36Sopenharmony_ci						struct dcb_app *app))
111062306a36Sopenharmony_ci{
111162306a36Sopenharmony_ci	struct dcb_app *app_data;
111262306a36Sopenharmony_ci	enum ieee_attrs_app type;
111362306a36Sopenharmony_ci	struct nlattr *attr_itr;
111462306a36Sopenharmony_ci	int rem, err;
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci	nla_for_each_nested(attr_itr, attr, rem) {
111762306a36Sopenharmony_ci		type = nla_type(attr_itr);
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_ci		if (!dcbnl_app_attr_type_validate(type))
112062306a36Sopenharmony_ci			continue;
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ci		if (nla_len(attr_itr) < sizeof(struct dcb_app))
112362306a36Sopenharmony_ci			return -ERANGE;
112462306a36Sopenharmony_ci
112562306a36Sopenharmony_ci		app_data = nla_data(attr_itr);
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_ci		if (!dcbnl_app_selector_validate(type, app_data->selector))
112862306a36Sopenharmony_ci			return -EINVAL;
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci		err = setdel(netdev, app_data);
113162306a36Sopenharmony_ci		if (err)
113262306a36Sopenharmony_ci			return err;
113362306a36Sopenharmony_ci	}
113462306a36Sopenharmony_ci
113562306a36Sopenharmony_ci	return 0;
113662306a36Sopenharmony_ci}
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci/* Handle IEEE 802.1Qaz/802.1Qau/802.1Qbb GET commands. */
113962306a36Sopenharmony_cistatic int dcbnl_ieee_fill(struct sk_buff *skb, struct net_device *netdev)
114062306a36Sopenharmony_ci{
114162306a36Sopenharmony_ci	const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
114262306a36Sopenharmony_ci	struct nlattr *ieee, *app, *rewr;
114362306a36Sopenharmony_ci	struct dcb_app_type *itr;
114462306a36Sopenharmony_ci	int dcbx;
114562306a36Sopenharmony_ci	int err;
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_ci	if (nla_put_string(skb, DCB_ATTR_IFNAME, netdev->name))
114862306a36Sopenharmony_ci		return -EMSGSIZE;
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_ci	ieee = nla_nest_start_noflag(skb, DCB_ATTR_IEEE);
115162306a36Sopenharmony_ci	if (!ieee)
115262306a36Sopenharmony_ci		return -EMSGSIZE;
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ci	if (ops->ieee_getets) {
115562306a36Sopenharmony_ci		struct ieee_ets ets;
115662306a36Sopenharmony_ci		memset(&ets, 0, sizeof(ets));
115762306a36Sopenharmony_ci		err = ops->ieee_getets(netdev, &ets);
115862306a36Sopenharmony_ci		if (!err &&
115962306a36Sopenharmony_ci		    nla_put(skb, DCB_ATTR_IEEE_ETS, sizeof(ets), &ets))
116062306a36Sopenharmony_ci			return -EMSGSIZE;
116162306a36Sopenharmony_ci	}
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_ci	if (ops->ieee_getmaxrate) {
116462306a36Sopenharmony_ci		struct ieee_maxrate maxrate;
116562306a36Sopenharmony_ci		memset(&maxrate, 0, sizeof(maxrate));
116662306a36Sopenharmony_ci		err = ops->ieee_getmaxrate(netdev, &maxrate);
116762306a36Sopenharmony_ci		if (!err) {
116862306a36Sopenharmony_ci			err = nla_put(skb, DCB_ATTR_IEEE_MAXRATE,
116962306a36Sopenharmony_ci				      sizeof(maxrate), &maxrate);
117062306a36Sopenharmony_ci			if (err)
117162306a36Sopenharmony_ci				return -EMSGSIZE;
117262306a36Sopenharmony_ci		}
117362306a36Sopenharmony_ci	}
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_ci	if (ops->ieee_getqcn) {
117662306a36Sopenharmony_ci		struct ieee_qcn qcn;
117762306a36Sopenharmony_ci
117862306a36Sopenharmony_ci		memset(&qcn, 0, sizeof(qcn));
117962306a36Sopenharmony_ci		err = ops->ieee_getqcn(netdev, &qcn);
118062306a36Sopenharmony_ci		if (!err) {
118162306a36Sopenharmony_ci			err = nla_put(skb, DCB_ATTR_IEEE_QCN,
118262306a36Sopenharmony_ci				      sizeof(qcn), &qcn);
118362306a36Sopenharmony_ci			if (err)
118462306a36Sopenharmony_ci				return -EMSGSIZE;
118562306a36Sopenharmony_ci		}
118662306a36Sopenharmony_ci	}
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_ci	if (ops->ieee_getqcnstats) {
118962306a36Sopenharmony_ci		struct ieee_qcn_stats qcn_stats;
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_ci		memset(&qcn_stats, 0, sizeof(qcn_stats));
119262306a36Sopenharmony_ci		err = ops->ieee_getqcnstats(netdev, &qcn_stats);
119362306a36Sopenharmony_ci		if (!err) {
119462306a36Sopenharmony_ci			err = nla_put(skb, DCB_ATTR_IEEE_QCN_STATS,
119562306a36Sopenharmony_ci				      sizeof(qcn_stats), &qcn_stats);
119662306a36Sopenharmony_ci			if (err)
119762306a36Sopenharmony_ci				return -EMSGSIZE;
119862306a36Sopenharmony_ci		}
119962306a36Sopenharmony_ci	}
120062306a36Sopenharmony_ci
120162306a36Sopenharmony_ci	if (ops->ieee_getpfc) {
120262306a36Sopenharmony_ci		struct ieee_pfc pfc;
120362306a36Sopenharmony_ci		memset(&pfc, 0, sizeof(pfc));
120462306a36Sopenharmony_ci		err = ops->ieee_getpfc(netdev, &pfc);
120562306a36Sopenharmony_ci		if (!err &&
120662306a36Sopenharmony_ci		    nla_put(skb, DCB_ATTR_IEEE_PFC, sizeof(pfc), &pfc))
120762306a36Sopenharmony_ci			return -EMSGSIZE;
120862306a36Sopenharmony_ci	}
120962306a36Sopenharmony_ci
121062306a36Sopenharmony_ci	if (ops->dcbnl_getbuffer) {
121162306a36Sopenharmony_ci		struct dcbnl_buffer buffer;
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_ci		memset(&buffer, 0, sizeof(buffer));
121462306a36Sopenharmony_ci		err = ops->dcbnl_getbuffer(netdev, &buffer);
121562306a36Sopenharmony_ci		if (!err &&
121662306a36Sopenharmony_ci		    nla_put(skb, DCB_ATTR_DCB_BUFFER, sizeof(buffer), &buffer))
121762306a36Sopenharmony_ci			return -EMSGSIZE;
121862306a36Sopenharmony_ci	}
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_ci	app = nla_nest_start_noflag(skb, DCB_ATTR_IEEE_APP_TABLE);
122162306a36Sopenharmony_ci	if (!app)
122262306a36Sopenharmony_ci		return -EMSGSIZE;
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci	spin_lock_bh(&dcb_lock);
122562306a36Sopenharmony_ci	list_for_each_entry(itr, &dcb_app_list, list) {
122662306a36Sopenharmony_ci		if (itr->ifindex == netdev->ifindex) {
122762306a36Sopenharmony_ci			enum ieee_attrs_app type =
122862306a36Sopenharmony_ci				dcbnl_app_attr_type_get(itr->app.selector);
122962306a36Sopenharmony_ci			err = nla_put(skb, type, sizeof(itr->app), &itr->app);
123062306a36Sopenharmony_ci			if (err) {
123162306a36Sopenharmony_ci				spin_unlock_bh(&dcb_lock);
123262306a36Sopenharmony_ci				return -EMSGSIZE;
123362306a36Sopenharmony_ci			}
123462306a36Sopenharmony_ci		}
123562306a36Sopenharmony_ci	}
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_ci	if (netdev->dcbnl_ops->getdcbx)
123862306a36Sopenharmony_ci		dcbx = netdev->dcbnl_ops->getdcbx(netdev);
123962306a36Sopenharmony_ci	else
124062306a36Sopenharmony_ci		dcbx = -EOPNOTSUPP;
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_ci	spin_unlock_bh(&dcb_lock);
124362306a36Sopenharmony_ci	nla_nest_end(skb, app);
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci	rewr = nla_nest_start(skb, DCB_ATTR_DCB_REWR_TABLE);
124662306a36Sopenharmony_ci	if (!rewr)
124762306a36Sopenharmony_ci		return -EMSGSIZE;
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_ci	spin_lock_bh(&dcb_lock);
125062306a36Sopenharmony_ci	list_for_each_entry(itr, &dcb_rewr_list, list) {
125162306a36Sopenharmony_ci		if (itr->ifindex == netdev->ifindex) {
125262306a36Sopenharmony_ci			enum ieee_attrs_app type =
125362306a36Sopenharmony_ci				dcbnl_app_attr_type_get(itr->app.selector);
125462306a36Sopenharmony_ci			err = nla_put(skb, type, sizeof(itr->app), &itr->app);
125562306a36Sopenharmony_ci			if (err) {
125662306a36Sopenharmony_ci				spin_unlock_bh(&dcb_lock);
125762306a36Sopenharmony_ci				nla_nest_cancel(skb, rewr);
125862306a36Sopenharmony_ci				return -EMSGSIZE;
125962306a36Sopenharmony_ci			}
126062306a36Sopenharmony_ci		}
126162306a36Sopenharmony_ci	}
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_ci	spin_unlock_bh(&dcb_lock);
126462306a36Sopenharmony_ci	nla_nest_end(skb, rewr);
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci	if (ops->dcbnl_getapptrust) {
126762306a36Sopenharmony_ci		err = dcbnl_getapptrust(netdev, skb);
126862306a36Sopenharmony_ci		if (err)
126962306a36Sopenharmony_ci			return err;
127062306a36Sopenharmony_ci	}
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_ci	/* get peer info if available */
127362306a36Sopenharmony_ci	if (ops->ieee_peer_getets) {
127462306a36Sopenharmony_ci		struct ieee_ets ets;
127562306a36Sopenharmony_ci		memset(&ets, 0, sizeof(ets));
127662306a36Sopenharmony_ci		err = ops->ieee_peer_getets(netdev, &ets);
127762306a36Sopenharmony_ci		if (!err &&
127862306a36Sopenharmony_ci		    nla_put(skb, DCB_ATTR_IEEE_PEER_ETS, sizeof(ets), &ets))
127962306a36Sopenharmony_ci			return -EMSGSIZE;
128062306a36Sopenharmony_ci	}
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_ci	if (ops->ieee_peer_getpfc) {
128362306a36Sopenharmony_ci		struct ieee_pfc pfc;
128462306a36Sopenharmony_ci		memset(&pfc, 0, sizeof(pfc));
128562306a36Sopenharmony_ci		err = ops->ieee_peer_getpfc(netdev, &pfc);
128662306a36Sopenharmony_ci		if (!err &&
128762306a36Sopenharmony_ci		    nla_put(skb, DCB_ATTR_IEEE_PEER_PFC, sizeof(pfc), &pfc))
128862306a36Sopenharmony_ci			return -EMSGSIZE;
128962306a36Sopenharmony_ci	}
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ci	if (ops->peer_getappinfo && ops->peer_getapptable) {
129262306a36Sopenharmony_ci		err = dcbnl_build_peer_app(netdev, skb,
129362306a36Sopenharmony_ci					   DCB_ATTR_IEEE_PEER_APP,
129462306a36Sopenharmony_ci					   DCB_ATTR_IEEE_APP_UNSPEC,
129562306a36Sopenharmony_ci					   DCB_ATTR_IEEE_APP);
129662306a36Sopenharmony_ci		if (err)
129762306a36Sopenharmony_ci			return -EMSGSIZE;
129862306a36Sopenharmony_ci	}
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_ci	nla_nest_end(skb, ieee);
130162306a36Sopenharmony_ci	if (dcbx >= 0) {
130262306a36Sopenharmony_ci		err = nla_put_u8(skb, DCB_ATTR_DCBX, dcbx);
130362306a36Sopenharmony_ci		if (err)
130462306a36Sopenharmony_ci			return -EMSGSIZE;
130562306a36Sopenharmony_ci	}
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_ci	return 0;
130862306a36Sopenharmony_ci}
130962306a36Sopenharmony_ci
131062306a36Sopenharmony_cistatic int dcbnl_cee_pg_fill(struct sk_buff *skb, struct net_device *dev,
131162306a36Sopenharmony_ci			     int dir)
131262306a36Sopenharmony_ci{
131362306a36Sopenharmony_ci	u8 pgid, up_map, prio, tc_pct;
131462306a36Sopenharmony_ci	const struct dcbnl_rtnl_ops *ops = dev->dcbnl_ops;
131562306a36Sopenharmony_ci	int i = dir ? DCB_ATTR_CEE_TX_PG : DCB_ATTR_CEE_RX_PG;
131662306a36Sopenharmony_ci	struct nlattr *pg = nla_nest_start_noflag(skb, i);
131762306a36Sopenharmony_ci
131862306a36Sopenharmony_ci	if (!pg)
131962306a36Sopenharmony_ci		return -EMSGSIZE;
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_ci	for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) {
132262306a36Sopenharmony_ci		struct nlattr *tc_nest = nla_nest_start_noflag(skb, i);
132362306a36Sopenharmony_ci
132462306a36Sopenharmony_ci		if (!tc_nest)
132562306a36Sopenharmony_ci			return -EMSGSIZE;
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_ci		pgid = DCB_ATTR_VALUE_UNDEFINED;
132862306a36Sopenharmony_ci		prio = DCB_ATTR_VALUE_UNDEFINED;
132962306a36Sopenharmony_ci		tc_pct = DCB_ATTR_VALUE_UNDEFINED;
133062306a36Sopenharmony_ci		up_map = DCB_ATTR_VALUE_UNDEFINED;
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_ci		if (!dir)
133362306a36Sopenharmony_ci			ops->getpgtccfgrx(dev, i - DCB_PG_ATTR_TC_0,
133462306a36Sopenharmony_ci					  &prio, &pgid, &tc_pct, &up_map);
133562306a36Sopenharmony_ci		else
133662306a36Sopenharmony_ci			ops->getpgtccfgtx(dev, i - DCB_PG_ATTR_TC_0,
133762306a36Sopenharmony_ci					  &prio, &pgid, &tc_pct, &up_map);
133862306a36Sopenharmony_ci
133962306a36Sopenharmony_ci		if (nla_put_u8(skb, DCB_TC_ATTR_PARAM_PGID, pgid) ||
134062306a36Sopenharmony_ci		    nla_put_u8(skb, DCB_TC_ATTR_PARAM_UP_MAPPING, up_map) ||
134162306a36Sopenharmony_ci		    nla_put_u8(skb, DCB_TC_ATTR_PARAM_STRICT_PRIO, prio) ||
134262306a36Sopenharmony_ci		    nla_put_u8(skb, DCB_TC_ATTR_PARAM_BW_PCT, tc_pct))
134362306a36Sopenharmony_ci			return -EMSGSIZE;
134462306a36Sopenharmony_ci		nla_nest_end(skb, tc_nest);
134562306a36Sopenharmony_ci	}
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci	for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) {
134862306a36Sopenharmony_ci		tc_pct = DCB_ATTR_VALUE_UNDEFINED;
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_ci		if (!dir)
135162306a36Sopenharmony_ci			ops->getpgbwgcfgrx(dev, i - DCB_PG_ATTR_BW_ID_0,
135262306a36Sopenharmony_ci					   &tc_pct);
135362306a36Sopenharmony_ci		else
135462306a36Sopenharmony_ci			ops->getpgbwgcfgtx(dev, i - DCB_PG_ATTR_BW_ID_0,
135562306a36Sopenharmony_ci					   &tc_pct);
135662306a36Sopenharmony_ci		if (nla_put_u8(skb, i, tc_pct))
135762306a36Sopenharmony_ci			return -EMSGSIZE;
135862306a36Sopenharmony_ci	}
135962306a36Sopenharmony_ci	nla_nest_end(skb, pg);
136062306a36Sopenharmony_ci	return 0;
136162306a36Sopenharmony_ci}
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_cistatic int dcbnl_cee_fill(struct sk_buff *skb, struct net_device *netdev)
136462306a36Sopenharmony_ci{
136562306a36Sopenharmony_ci	struct nlattr *cee, *app;
136662306a36Sopenharmony_ci	struct dcb_app_type *itr;
136762306a36Sopenharmony_ci	const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
136862306a36Sopenharmony_ci	int dcbx, i, err = -EMSGSIZE;
136962306a36Sopenharmony_ci	u8 value;
137062306a36Sopenharmony_ci
137162306a36Sopenharmony_ci	if (nla_put_string(skb, DCB_ATTR_IFNAME, netdev->name))
137262306a36Sopenharmony_ci		goto nla_put_failure;
137362306a36Sopenharmony_ci	cee = nla_nest_start_noflag(skb, DCB_ATTR_CEE);
137462306a36Sopenharmony_ci	if (!cee)
137562306a36Sopenharmony_ci		goto nla_put_failure;
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_ci	/* local pg */
137862306a36Sopenharmony_ci	if (ops->getpgtccfgtx && ops->getpgbwgcfgtx) {
137962306a36Sopenharmony_ci		err = dcbnl_cee_pg_fill(skb, netdev, 1);
138062306a36Sopenharmony_ci		if (err)
138162306a36Sopenharmony_ci			goto nla_put_failure;
138262306a36Sopenharmony_ci	}
138362306a36Sopenharmony_ci
138462306a36Sopenharmony_ci	if (ops->getpgtccfgrx && ops->getpgbwgcfgrx) {
138562306a36Sopenharmony_ci		err = dcbnl_cee_pg_fill(skb, netdev, 0);
138662306a36Sopenharmony_ci		if (err)
138762306a36Sopenharmony_ci			goto nla_put_failure;
138862306a36Sopenharmony_ci	}
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_ci	/* local pfc */
139162306a36Sopenharmony_ci	if (ops->getpfccfg) {
139262306a36Sopenharmony_ci		struct nlattr *pfc_nest = nla_nest_start_noflag(skb,
139362306a36Sopenharmony_ci								DCB_ATTR_CEE_PFC);
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci		if (!pfc_nest)
139662306a36Sopenharmony_ci			goto nla_put_failure;
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_ci		for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) {
139962306a36Sopenharmony_ci			ops->getpfccfg(netdev, i - DCB_PFC_UP_ATTR_0, &value);
140062306a36Sopenharmony_ci			if (nla_put_u8(skb, i, value))
140162306a36Sopenharmony_ci				goto nla_put_failure;
140262306a36Sopenharmony_ci		}
140362306a36Sopenharmony_ci		nla_nest_end(skb, pfc_nest);
140462306a36Sopenharmony_ci	}
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_ci	/* local app */
140762306a36Sopenharmony_ci	spin_lock_bh(&dcb_lock);
140862306a36Sopenharmony_ci	app = nla_nest_start_noflag(skb, DCB_ATTR_CEE_APP_TABLE);
140962306a36Sopenharmony_ci	if (!app)
141062306a36Sopenharmony_ci		goto dcb_unlock;
141162306a36Sopenharmony_ci
141262306a36Sopenharmony_ci	list_for_each_entry(itr, &dcb_app_list, list) {
141362306a36Sopenharmony_ci		if (itr->ifindex == netdev->ifindex) {
141462306a36Sopenharmony_ci			struct nlattr *app_nest = nla_nest_start_noflag(skb,
141562306a36Sopenharmony_ci									DCB_ATTR_APP);
141662306a36Sopenharmony_ci			if (!app_nest)
141762306a36Sopenharmony_ci				goto dcb_unlock;
141862306a36Sopenharmony_ci
141962306a36Sopenharmony_ci			err = nla_put_u8(skb, DCB_APP_ATTR_IDTYPE,
142062306a36Sopenharmony_ci					 itr->app.selector);
142162306a36Sopenharmony_ci			if (err)
142262306a36Sopenharmony_ci				goto dcb_unlock;
142362306a36Sopenharmony_ci
142462306a36Sopenharmony_ci			err = nla_put_u16(skb, DCB_APP_ATTR_ID,
142562306a36Sopenharmony_ci					  itr->app.protocol);
142662306a36Sopenharmony_ci			if (err)
142762306a36Sopenharmony_ci				goto dcb_unlock;
142862306a36Sopenharmony_ci
142962306a36Sopenharmony_ci			err = nla_put_u8(skb, DCB_APP_ATTR_PRIORITY,
143062306a36Sopenharmony_ci					 itr->app.priority);
143162306a36Sopenharmony_ci			if (err)
143262306a36Sopenharmony_ci				goto dcb_unlock;
143362306a36Sopenharmony_ci
143462306a36Sopenharmony_ci			nla_nest_end(skb, app_nest);
143562306a36Sopenharmony_ci		}
143662306a36Sopenharmony_ci	}
143762306a36Sopenharmony_ci	nla_nest_end(skb, app);
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_ci	if (netdev->dcbnl_ops->getdcbx)
144062306a36Sopenharmony_ci		dcbx = netdev->dcbnl_ops->getdcbx(netdev);
144162306a36Sopenharmony_ci	else
144262306a36Sopenharmony_ci		dcbx = -EOPNOTSUPP;
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci	spin_unlock_bh(&dcb_lock);
144562306a36Sopenharmony_ci
144662306a36Sopenharmony_ci	/* features flags */
144762306a36Sopenharmony_ci	if (ops->getfeatcfg) {
144862306a36Sopenharmony_ci		struct nlattr *feat = nla_nest_start_noflag(skb,
144962306a36Sopenharmony_ci							    DCB_ATTR_CEE_FEAT);
145062306a36Sopenharmony_ci		if (!feat)
145162306a36Sopenharmony_ci			goto nla_put_failure;
145262306a36Sopenharmony_ci
145362306a36Sopenharmony_ci		for (i = DCB_FEATCFG_ATTR_ALL + 1; i <= DCB_FEATCFG_ATTR_MAX;
145462306a36Sopenharmony_ci		     i++)
145562306a36Sopenharmony_ci			if (!ops->getfeatcfg(netdev, i, &value) &&
145662306a36Sopenharmony_ci			    nla_put_u8(skb, i, value))
145762306a36Sopenharmony_ci				goto nla_put_failure;
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_ci		nla_nest_end(skb, feat);
146062306a36Sopenharmony_ci	}
146162306a36Sopenharmony_ci
146262306a36Sopenharmony_ci	/* peer info if available */
146362306a36Sopenharmony_ci	if (ops->cee_peer_getpg) {
146462306a36Sopenharmony_ci		struct cee_pg pg;
146562306a36Sopenharmony_ci		memset(&pg, 0, sizeof(pg));
146662306a36Sopenharmony_ci		err = ops->cee_peer_getpg(netdev, &pg);
146762306a36Sopenharmony_ci		if (!err &&
146862306a36Sopenharmony_ci		    nla_put(skb, DCB_ATTR_CEE_PEER_PG, sizeof(pg), &pg))
146962306a36Sopenharmony_ci			goto nla_put_failure;
147062306a36Sopenharmony_ci	}
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_ci	if (ops->cee_peer_getpfc) {
147362306a36Sopenharmony_ci		struct cee_pfc pfc;
147462306a36Sopenharmony_ci		memset(&pfc, 0, sizeof(pfc));
147562306a36Sopenharmony_ci		err = ops->cee_peer_getpfc(netdev, &pfc);
147662306a36Sopenharmony_ci		if (!err &&
147762306a36Sopenharmony_ci		    nla_put(skb, DCB_ATTR_CEE_PEER_PFC, sizeof(pfc), &pfc))
147862306a36Sopenharmony_ci			goto nla_put_failure;
147962306a36Sopenharmony_ci	}
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_ci	if (ops->peer_getappinfo && ops->peer_getapptable) {
148262306a36Sopenharmony_ci		err = dcbnl_build_peer_app(netdev, skb,
148362306a36Sopenharmony_ci					   DCB_ATTR_CEE_PEER_APP_TABLE,
148462306a36Sopenharmony_ci					   DCB_ATTR_CEE_PEER_APP_INFO,
148562306a36Sopenharmony_ci					   DCB_ATTR_CEE_PEER_APP);
148662306a36Sopenharmony_ci		if (err)
148762306a36Sopenharmony_ci			goto nla_put_failure;
148862306a36Sopenharmony_ci	}
148962306a36Sopenharmony_ci	nla_nest_end(skb, cee);
149062306a36Sopenharmony_ci
149162306a36Sopenharmony_ci	/* DCBX state */
149262306a36Sopenharmony_ci	if (dcbx >= 0) {
149362306a36Sopenharmony_ci		err = nla_put_u8(skb, DCB_ATTR_DCBX, dcbx);
149462306a36Sopenharmony_ci		if (err)
149562306a36Sopenharmony_ci			goto nla_put_failure;
149662306a36Sopenharmony_ci	}
149762306a36Sopenharmony_ci	return 0;
149862306a36Sopenharmony_ci
149962306a36Sopenharmony_cidcb_unlock:
150062306a36Sopenharmony_ci	spin_unlock_bh(&dcb_lock);
150162306a36Sopenharmony_cinla_put_failure:
150262306a36Sopenharmony_ci	err = -EMSGSIZE;
150362306a36Sopenharmony_ci	return err;
150462306a36Sopenharmony_ci}
150562306a36Sopenharmony_ci
150662306a36Sopenharmony_cistatic int dcbnl_notify(struct net_device *dev, int event, int cmd,
150762306a36Sopenharmony_ci			u32 seq, u32 portid, int dcbx_ver)
150862306a36Sopenharmony_ci{
150962306a36Sopenharmony_ci	struct net *net = dev_net(dev);
151062306a36Sopenharmony_ci	struct sk_buff *skb;
151162306a36Sopenharmony_ci	struct nlmsghdr *nlh;
151262306a36Sopenharmony_ci	const struct dcbnl_rtnl_ops *ops = dev->dcbnl_ops;
151362306a36Sopenharmony_ci	int err;
151462306a36Sopenharmony_ci
151562306a36Sopenharmony_ci	if (!ops)
151662306a36Sopenharmony_ci		return -EOPNOTSUPP;
151762306a36Sopenharmony_ci
151862306a36Sopenharmony_ci	skb = dcbnl_newmsg(event, cmd, portid, seq, 0, &nlh);
151962306a36Sopenharmony_ci	if (!skb)
152062306a36Sopenharmony_ci		return -ENOMEM;
152162306a36Sopenharmony_ci
152262306a36Sopenharmony_ci	if (dcbx_ver == DCB_CAP_DCBX_VER_IEEE)
152362306a36Sopenharmony_ci		err = dcbnl_ieee_fill(skb, dev);
152462306a36Sopenharmony_ci	else
152562306a36Sopenharmony_ci		err = dcbnl_cee_fill(skb, dev);
152662306a36Sopenharmony_ci
152762306a36Sopenharmony_ci	if (err < 0) {
152862306a36Sopenharmony_ci		/* Report error to broadcast listeners */
152962306a36Sopenharmony_ci		nlmsg_free(skb);
153062306a36Sopenharmony_ci		rtnl_set_sk_err(net, RTNLGRP_DCB, err);
153162306a36Sopenharmony_ci	} else {
153262306a36Sopenharmony_ci		/* End nlmsg and notify broadcast listeners */
153362306a36Sopenharmony_ci		nlmsg_end(skb, nlh);
153462306a36Sopenharmony_ci		rtnl_notify(skb, net, 0, RTNLGRP_DCB, NULL, GFP_KERNEL);
153562306a36Sopenharmony_ci	}
153662306a36Sopenharmony_ci
153762306a36Sopenharmony_ci	return err;
153862306a36Sopenharmony_ci}
153962306a36Sopenharmony_ci
154062306a36Sopenharmony_ciint dcbnl_ieee_notify(struct net_device *dev, int event, int cmd,
154162306a36Sopenharmony_ci		      u32 seq, u32 portid)
154262306a36Sopenharmony_ci{
154362306a36Sopenharmony_ci	return dcbnl_notify(dev, event, cmd, seq, portid, DCB_CAP_DCBX_VER_IEEE);
154462306a36Sopenharmony_ci}
154562306a36Sopenharmony_ciEXPORT_SYMBOL(dcbnl_ieee_notify);
154662306a36Sopenharmony_ci
154762306a36Sopenharmony_ciint dcbnl_cee_notify(struct net_device *dev, int event, int cmd,
154862306a36Sopenharmony_ci		     u32 seq, u32 portid)
154962306a36Sopenharmony_ci{
155062306a36Sopenharmony_ci	return dcbnl_notify(dev, event, cmd, seq, portid, DCB_CAP_DCBX_VER_CEE);
155162306a36Sopenharmony_ci}
155262306a36Sopenharmony_ciEXPORT_SYMBOL(dcbnl_cee_notify);
155362306a36Sopenharmony_ci
155462306a36Sopenharmony_ci/* Handle IEEE 802.1Qaz/802.1Qau/802.1Qbb SET commands.
155562306a36Sopenharmony_ci * If any requested operation can not be completed
155662306a36Sopenharmony_ci * the entire msg is aborted and error value is returned.
155762306a36Sopenharmony_ci * No attempt is made to reconcile the case where only part of the
155862306a36Sopenharmony_ci * cmd can be completed.
155962306a36Sopenharmony_ci */
156062306a36Sopenharmony_cistatic int dcbnl_ieee_set(struct net_device *netdev, struct nlmsghdr *nlh,
156162306a36Sopenharmony_ci			  u32 seq, struct nlattr **tb, struct sk_buff *skb)
156262306a36Sopenharmony_ci{
156362306a36Sopenharmony_ci	const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
156462306a36Sopenharmony_ci	struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1];
156562306a36Sopenharmony_ci	int prio;
156662306a36Sopenharmony_ci	int err;
156762306a36Sopenharmony_ci
156862306a36Sopenharmony_ci	if (!ops)
156962306a36Sopenharmony_ci		return -EOPNOTSUPP;
157062306a36Sopenharmony_ci
157162306a36Sopenharmony_ci	if (!tb[DCB_ATTR_IEEE])
157262306a36Sopenharmony_ci		return -EINVAL;
157362306a36Sopenharmony_ci
157462306a36Sopenharmony_ci	err = nla_parse_nested_deprecated(ieee, DCB_ATTR_IEEE_MAX,
157562306a36Sopenharmony_ci					  tb[DCB_ATTR_IEEE],
157662306a36Sopenharmony_ci					  dcbnl_ieee_policy, NULL);
157762306a36Sopenharmony_ci	if (err)
157862306a36Sopenharmony_ci		return err;
157962306a36Sopenharmony_ci
158062306a36Sopenharmony_ci	if (ieee[DCB_ATTR_IEEE_ETS] && ops->ieee_setets) {
158162306a36Sopenharmony_ci		struct ieee_ets *ets = nla_data(ieee[DCB_ATTR_IEEE_ETS]);
158262306a36Sopenharmony_ci		err = ops->ieee_setets(netdev, ets);
158362306a36Sopenharmony_ci		if (err)
158462306a36Sopenharmony_ci			goto err;
158562306a36Sopenharmony_ci	}
158662306a36Sopenharmony_ci
158762306a36Sopenharmony_ci	if (ieee[DCB_ATTR_IEEE_MAXRATE] && ops->ieee_setmaxrate) {
158862306a36Sopenharmony_ci		struct ieee_maxrate *maxrate =
158962306a36Sopenharmony_ci			nla_data(ieee[DCB_ATTR_IEEE_MAXRATE]);
159062306a36Sopenharmony_ci		err = ops->ieee_setmaxrate(netdev, maxrate);
159162306a36Sopenharmony_ci		if (err)
159262306a36Sopenharmony_ci			goto err;
159362306a36Sopenharmony_ci	}
159462306a36Sopenharmony_ci
159562306a36Sopenharmony_ci	if (ieee[DCB_ATTR_IEEE_QCN] && ops->ieee_setqcn) {
159662306a36Sopenharmony_ci		struct ieee_qcn *qcn =
159762306a36Sopenharmony_ci			nla_data(ieee[DCB_ATTR_IEEE_QCN]);
159862306a36Sopenharmony_ci
159962306a36Sopenharmony_ci		err = ops->ieee_setqcn(netdev, qcn);
160062306a36Sopenharmony_ci		if (err)
160162306a36Sopenharmony_ci			goto err;
160262306a36Sopenharmony_ci	}
160362306a36Sopenharmony_ci
160462306a36Sopenharmony_ci	if (ieee[DCB_ATTR_IEEE_PFC] && ops->ieee_setpfc) {
160562306a36Sopenharmony_ci		struct ieee_pfc *pfc = nla_data(ieee[DCB_ATTR_IEEE_PFC]);
160662306a36Sopenharmony_ci		err = ops->ieee_setpfc(netdev, pfc);
160762306a36Sopenharmony_ci		if (err)
160862306a36Sopenharmony_ci			goto err;
160962306a36Sopenharmony_ci	}
161062306a36Sopenharmony_ci
161162306a36Sopenharmony_ci	if (ieee[DCB_ATTR_DCB_BUFFER] && ops->dcbnl_setbuffer) {
161262306a36Sopenharmony_ci		struct dcbnl_buffer *buffer =
161362306a36Sopenharmony_ci			nla_data(ieee[DCB_ATTR_DCB_BUFFER]);
161462306a36Sopenharmony_ci
161562306a36Sopenharmony_ci		for (prio = 0; prio < ARRAY_SIZE(buffer->prio2buffer); prio++) {
161662306a36Sopenharmony_ci			if (buffer->prio2buffer[prio] >= DCBX_MAX_BUFFERS) {
161762306a36Sopenharmony_ci				err = -EINVAL;
161862306a36Sopenharmony_ci				goto err;
161962306a36Sopenharmony_ci			}
162062306a36Sopenharmony_ci		}
162162306a36Sopenharmony_ci
162262306a36Sopenharmony_ci		err = ops->dcbnl_setbuffer(netdev, buffer);
162362306a36Sopenharmony_ci		if (err)
162462306a36Sopenharmony_ci			goto err;
162562306a36Sopenharmony_ci	}
162662306a36Sopenharmony_ci
162762306a36Sopenharmony_ci	if (ieee[DCB_ATTR_DCB_REWR_TABLE]) {
162862306a36Sopenharmony_ci		err = dcbnl_app_table_setdel(ieee[DCB_ATTR_DCB_REWR_TABLE],
162962306a36Sopenharmony_ci					     netdev,
163062306a36Sopenharmony_ci					     ops->dcbnl_setrewr ?: dcb_setrewr);
163162306a36Sopenharmony_ci		if (err)
163262306a36Sopenharmony_ci			goto err;
163362306a36Sopenharmony_ci	}
163462306a36Sopenharmony_ci
163562306a36Sopenharmony_ci	if (ieee[DCB_ATTR_IEEE_APP_TABLE]) {
163662306a36Sopenharmony_ci		err = dcbnl_app_table_setdel(ieee[DCB_ATTR_IEEE_APP_TABLE],
163762306a36Sopenharmony_ci					     netdev, ops->ieee_setapp ?:
163862306a36Sopenharmony_ci					     dcb_ieee_setapp);
163962306a36Sopenharmony_ci		if (err)
164062306a36Sopenharmony_ci			goto err;
164162306a36Sopenharmony_ci	}
164262306a36Sopenharmony_ci
164362306a36Sopenharmony_ci	if (ieee[DCB_ATTR_DCB_APP_TRUST_TABLE]) {
164462306a36Sopenharmony_ci		u8 selectors[IEEE_8021QAZ_APP_SEL_MAX + 1] = {0};
164562306a36Sopenharmony_ci		struct nlattr *attr;
164662306a36Sopenharmony_ci		int nselectors = 0;
164762306a36Sopenharmony_ci		int rem;
164862306a36Sopenharmony_ci
164962306a36Sopenharmony_ci		if (!ops->dcbnl_setapptrust) {
165062306a36Sopenharmony_ci			err = -EOPNOTSUPP;
165162306a36Sopenharmony_ci			goto err;
165262306a36Sopenharmony_ci		}
165362306a36Sopenharmony_ci
165462306a36Sopenharmony_ci		nla_for_each_nested(attr, ieee[DCB_ATTR_DCB_APP_TRUST_TABLE],
165562306a36Sopenharmony_ci				    rem) {
165662306a36Sopenharmony_ci			enum ieee_attrs_app type = nla_type(attr);
165762306a36Sopenharmony_ci			u8 selector;
165862306a36Sopenharmony_ci			int i;
165962306a36Sopenharmony_ci
166062306a36Sopenharmony_ci			if (!dcbnl_app_attr_type_validate(type) ||
166162306a36Sopenharmony_ci			    nla_len(attr) != 1 ||
166262306a36Sopenharmony_ci			    nselectors >= sizeof(selectors)) {
166362306a36Sopenharmony_ci				err = -EINVAL;
166462306a36Sopenharmony_ci				goto err;
166562306a36Sopenharmony_ci			}
166662306a36Sopenharmony_ci
166762306a36Sopenharmony_ci			selector = nla_get_u8(attr);
166862306a36Sopenharmony_ci
166962306a36Sopenharmony_ci			if (!dcbnl_app_selector_validate(type, selector)) {
167062306a36Sopenharmony_ci				err = -EINVAL;
167162306a36Sopenharmony_ci				goto err;
167262306a36Sopenharmony_ci			}
167362306a36Sopenharmony_ci
167462306a36Sopenharmony_ci			/* Duplicate selector ? */
167562306a36Sopenharmony_ci			for (i = 0; i < nselectors; i++) {
167662306a36Sopenharmony_ci				if (selectors[i] == selector) {
167762306a36Sopenharmony_ci					err = -EINVAL;
167862306a36Sopenharmony_ci					goto err;
167962306a36Sopenharmony_ci				}
168062306a36Sopenharmony_ci			}
168162306a36Sopenharmony_ci
168262306a36Sopenharmony_ci			selectors[nselectors++] = selector;
168362306a36Sopenharmony_ci		}
168462306a36Sopenharmony_ci
168562306a36Sopenharmony_ci		err = ops->dcbnl_setapptrust(netdev, selectors, nselectors);
168662306a36Sopenharmony_ci		if (err)
168762306a36Sopenharmony_ci			goto err;
168862306a36Sopenharmony_ci	}
168962306a36Sopenharmony_ci
169062306a36Sopenharmony_cierr:
169162306a36Sopenharmony_ci	err = nla_put_u8(skb, DCB_ATTR_IEEE, err);
169262306a36Sopenharmony_ci	dcbnl_ieee_notify(netdev, RTM_SETDCB, DCB_CMD_IEEE_SET, seq, 0);
169362306a36Sopenharmony_ci	return err;
169462306a36Sopenharmony_ci}
169562306a36Sopenharmony_ci
169662306a36Sopenharmony_cistatic int dcbnl_ieee_get(struct net_device *netdev, struct nlmsghdr *nlh,
169762306a36Sopenharmony_ci			  u32 seq, struct nlattr **tb, struct sk_buff *skb)
169862306a36Sopenharmony_ci{
169962306a36Sopenharmony_ci	const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
170062306a36Sopenharmony_ci
170162306a36Sopenharmony_ci	if (!ops)
170262306a36Sopenharmony_ci		return -EOPNOTSUPP;
170362306a36Sopenharmony_ci
170462306a36Sopenharmony_ci	return dcbnl_ieee_fill(skb, netdev);
170562306a36Sopenharmony_ci}
170662306a36Sopenharmony_ci
170762306a36Sopenharmony_cistatic int dcbnl_ieee_del(struct net_device *netdev, struct nlmsghdr *nlh,
170862306a36Sopenharmony_ci			  u32 seq, struct nlattr **tb, struct sk_buff *skb)
170962306a36Sopenharmony_ci{
171062306a36Sopenharmony_ci	const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
171162306a36Sopenharmony_ci	struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1];
171262306a36Sopenharmony_ci	int err;
171362306a36Sopenharmony_ci
171462306a36Sopenharmony_ci	if (!ops)
171562306a36Sopenharmony_ci		return -EOPNOTSUPP;
171662306a36Sopenharmony_ci
171762306a36Sopenharmony_ci	if (!tb[DCB_ATTR_IEEE])
171862306a36Sopenharmony_ci		return -EINVAL;
171962306a36Sopenharmony_ci
172062306a36Sopenharmony_ci	err = nla_parse_nested_deprecated(ieee, DCB_ATTR_IEEE_MAX,
172162306a36Sopenharmony_ci					  tb[DCB_ATTR_IEEE],
172262306a36Sopenharmony_ci					  dcbnl_ieee_policy, NULL);
172362306a36Sopenharmony_ci	if (err)
172462306a36Sopenharmony_ci		return err;
172562306a36Sopenharmony_ci
172662306a36Sopenharmony_ci	if (ieee[DCB_ATTR_IEEE_APP_TABLE]) {
172762306a36Sopenharmony_ci		err = dcbnl_app_table_setdel(ieee[DCB_ATTR_IEEE_APP_TABLE],
172862306a36Sopenharmony_ci					     netdev, ops->ieee_delapp ?:
172962306a36Sopenharmony_ci					     dcb_ieee_delapp);
173062306a36Sopenharmony_ci		if (err)
173162306a36Sopenharmony_ci			goto err;
173262306a36Sopenharmony_ci	}
173362306a36Sopenharmony_ci
173462306a36Sopenharmony_ci	if (ieee[DCB_ATTR_DCB_REWR_TABLE]) {
173562306a36Sopenharmony_ci		err = dcbnl_app_table_setdel(ieee[DCB_ATTR_DCB_REWR_TABLE],
173662306a36Sopenharmony_ci					     netdev,
173762306a36Sopenharmony_ci					     ops->dcbnl_delrewr ?: dcb_delrewr);
173862306a36Sopenharmony_ci		if (err)
173962306a36Sopenharmony_ci			goto err;
174062306a36Sopenharmony_ci	}
174162306a36Sopenharmony_ci
174262306a36Sopenharmony_cierr:
174362306a36Sopenharmony_ci	err = nla_put_u8(skb, DCB_ATTR_IEEE, err);
174462306a36Sopenharmony_ci	dcbnl_ieee_notify(netdev, RTM_SETDCB, DCB_CMD_IEEE_DEL, seq, 0);
174562306a36Sopenharmony_ci	return err;
174662306a36Sopenharmony_ci}
174762306a36Sopenharmony_ci
174862306a36Sopenharmony_ci
174962306a36Sopenharmony_ci/* DCBX configuration */
175062306a36Sopenharmony_cistatic int dcbnl_getdcbx(struct net_device *netdev, struct nlmsghdr *nlh,
175162306a36Sopenharmony_ci			 u32 seq, struct nlattr **tb, struct sk_buff *skb)
175262306a36Sopenharmony_ci{
175362306a36Sopenharmony_ci	if (!netdev->dcbnl_ops->getdcbx)
175462306a36Sopenharmony_ci		return -EOPNOTSUPP;
175562306a36Sopenharmony_ci
175662306a36Sopenharmony_ci	return nla_put_u8(skb, DCB_ATTR_DCBX,
175762306a36Sopenharmony_ci			  netdev->dcbnl_ops->getdcbx(netdev));
175862306a36Sopenharmony_ci}
175962306a36Sopenharmony_ci
176062306a36Sopenharmony_cistatic int dcbnl_setdcbx(struct net_device *netdev, struct nlmsghdr *nlh,
176162306a36Sopenharmony_ci			 u32 seq, struct nlattr **tb, struct sk_buff *skb)
176262306a36Sopenharmony_ci{
176362306a36Sopenharmony_ci	u8 value;
176462306a36Sopenharmony_ci
176562306a36Sopenharmony_ci	if (!netdev->dcbnl_ops->setdcbx)
176662306a36Sopenharmony_ci		return -EOPNOTSUPP;
176762306a36Sopenharmony_ci
176862306a36Sopenharmony_ci	if (!tb[DCB_ATTR_DCBX])
176962306a36Sopenharmony_ci		return -EINVAL;
177062306a36Sopenharmony_ci
177162306a36Sopenharmony_ci	value = nla_get_u8(tb[DCB_ATTR_DCBX]);
177262306a36Sopenharmony_ci
177362306a36Sopenharmony_ci	return nla_put_u8(skb, DCB_ATTR_DCBX,
177462306a36Sopenharmony_ci			  netdev->dcbnl_ops->setdcbx(netdev, value));
177562306a36Sopenharmony_ci}
177662306a36Sopenharmony_ci
177762306a36Sopenharmony_cistatic int dcbnl_getfeatcfg(struct net_device *netdev, struct nlmsghdr *nlh,
177862306a36Sopenharmony_ci			    u32 seq, struct nlattr **tb, struct sk_buff *skb)
177962306a36Sopenharmony_ci{
178062306a36Sopenharmony_ci	struct nlattr *data[DCB_FEATCFG_ATTR_MAX + 1], *nest;
178162306a36Sopenharmony_ci	u8 value;
178262306a36Sopenharmony_ci	int ret, i;
178362306a36Sopenharmony_ci	int getall = 0;
178462306a36Sopenharmony_ci
178562306a36Sopenharmony_ci	if (!netdev->dcbnl_ops->getfeatcfg)
178662306a36Sopenharmony_ci		return -EOPNOTSUPP;
178762306a36Sopenharmony_ci
178862306a36Sopenharmony_ci	if (!tb[DCB_ATTR_FEATCFG])
178962306a36Sopenharmony_ci		return -EINVAL;
179062306a36Sopenharmony_ci
179162306a36Sopenharmony_ci	ret = nla_parse_nested_deprecated(data, DCB_FEATCFG_ATTR_MAX,
179262306a36Sopenharmony_ci					  tb[DCB_ATTR_FEATCFG],
179362306a36Sopenharmony_ci					  dcbnl_featcfg_nest, NULL);
179462306a36Sopenharmony_ci	if (ret)
179562306a36Sopenharmony_ci		return ret;
179662306a36Sopenharmony_ci
179762306a36Sopenharmony_ci	nest = nla_nest_start_noflag(skb, DCB_ATTR_FEATCFG);
179862306a36Sopenharmony_ci	if (!nest)
179962306a36Sopenharmony_ci		return -EMSGSIZE;
180062306a36Sopenharmony_ci
180162306a36Sopenharmony_ci	if (data[DCB_FEATCFG_ATTR_ALL])
180262306a36Sopenharmony_ci		getall = 1;
180362306a36Sopenharmony_ci
180462306a36Sopenharmony_ci	for (i = DCB_FEATCFG_ATTR_ALL+1; i <= DCB_FEATCFG_ATTR_MAX; i++) {
180562306a36Sopenharmony_ci		if (!getall && !data[i])
180662306a36Sopenharmony_ci			continue;
180762306a36Sopenharmony_ci
180862306a36Sopenharmony_ci		ret = netdev->dcbnl_ops->getfeatcfg(netdev, i, &value);
180962306a36Sopenharmony_ci		if (!ret)
181062306a36Sopenharmony_ci			ret = nla_put_u8(skb, i, value);
181162306a36Sopenharmony_ci
181262306a36Sopenharmony_ci		if (ret) {
181362306a36Sopenharmony_ci			nla_nest_cancel(skb, nest);
181462306a36Sopenharmony_ci			goto nla_put_failure;
181562306a36Sopenharmony_ci		}
181662306a36Sopenharmony_ci	}
181762306a36Sopenharmony_ci	nla_nest_end(skb, nest);
181862306a36Sopenharmony_ci
181962306a36Sopenharmony_cinla_put_failure:
182062306a36Sopenharmony_ci	return ret;
182162306a36Sopenharmony_ci}
182262306a36Sopenharmony_ci
182362306a36Sopenharmony_cistatic int dcbnl_setfeatcfg(struct net_device *netdev, struct nlmsghdr *nlh,
182462306a36Sopenharmony_ci			    u32 seq, struct nlattr **tb, struct sk_buff *skb)
182562306a36Sopenharmony_ci{
182662306a36Sopenharmony_ci	struct nlattr *data[DCB_FEATCFG_ATTR_MAX + 1];
182762306a36Sopenharmony_ci	int ret, i;
182862306a36Sopenharmony_ci	u8 value;
182962306a36Sopenharmony_ci
183062306a36Sopenharmony_ci	if (!netdev->dcbnl_ops->setfeatcfg)
183162306a36Sopenharmony_ci		return -ENOTSUPP;
183262306a36Sopenharmony_ci
183362306a36Sopenharmony_ci	if (!tb[DCB_ATTR_FEATCFG])
183462306a36Sopenharmony_ci		return -EINVAL;
183562306a36Sopenharmony_ci
183662306a36Sopenharmony_ci	ret = nla_parse_nested_deprecated(data, DCB_FEATCFG_ATTR_MAX,
183762306a36Sopenharmony_ci					  tb[DCB_ATTR_FEATCFG],
183862306a36Sopenharmony_ci					  dcbnl_featcfg_nest, NULL);
183962306a36Sopenharmony_ci
184062306a36Sopenharmony_ci	if (ret)
184162306a36Sopenharmony_ci		goto err;
184262306a36Sopenharmony_ci
184362306a36Sopenharmony_ci	for (i = DCB_FEATCFG_ATTR_ALL+1; i <= DCB_FEATCFG_ATTR_MAX; i++) {
184462306a36Sopenharmony_ci		if (data[i] == NULL)
184562306a36Sopenharmony_ci			continue;
184662306a36Sopenharmony_ci
184762306a36Sopenharmony_ci		value = nla_get_u8(data[i]);
184862306a36Sopenharmony_ci
184962306a36Sopenharmony_ci		ret = netdev->dcbnl_ops->setfeatcfg(netdev, i, value);
185062306a36Sopenharmony_ci
185162306a36Sopenharmony_ci		if (ret)
185262306a36Sopenharmony_ci			goto err;
185362306a36Sopenharmony_ci	}
185462306a36Sopenharmony_cierr:
185562306a36Sopenharmony_ci	ret = nla_put_u8(skb, DCB_ATTR_FEATCFG, ret);
185662306a36Sopenharmony_ci
185762306a36Sopenharmony_ci	return ret;
185862306a36Sopenharmony_ci}
185962306a36Sopenharmony_ci
186062306a36Sopenharmony_ci/* Handle CEE DCBX GET commands. */
186162306a36Sopenharmony_cistatic int dcbnl_cee_get(struct net_device *netdev, struct nlmsghdr *nlh,
186262306a36Sopenharmony_ci			 u32 seq, struct nlattr **tb, struct sk_buff *skb)
186362306a36Sopenharmony_ci{
186462306a36Sopenharmony_ci	const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
186562306a36Sopenharmony_ci
186662306a36Sopenharmony_ci	if (!ops)
186762306a36Sopenharmony_ci		return -EOPNOTSUPP;
186862306a36Sopenharmony_ci
186962306a36Sopenharmony_ci	return dcbnl_cee_fill(skb, netdev);
187062306a36Sopenharmony_ci}
187162306a36Sopenharmony_ci
187262306a36Sopenharmony_cistruct reply_func {
187362306a36Sopenharmony_ci	/* reply netlink message type */
187462306a36Sopenharmony_ci	int	type;
187562306a36Sopenharmony_ci
187662306a36Sopenharmony_ci	/* function to fill message contents */
187762306a36Sopenharmony_ci	int   (*cb)(struct net_device *, struct nlmsghdr *, u32,
187862306a36Sopenharmony_ci		    struct nlattr **, struct sk_buff *);
187962306a36Sopenharmony_ci};
188062306a36Sopenharmony_ci
188162306a36Sopenharmony_cistatic const struct reply_func reply_funcs[DCB_CMD_MAX+1] = {
188262306a36Sopenharmony_ci	[DCB_CMD_GSTATE]	= { RTM_GETDCB, dcbnl_getstate },
188362306a36Sopenharmony_ci	[DCB_CMD_SSTATE]	= { RTM_SETDCB, dcbnl_setstate },
188462306a36Sopenharmony_ci	[DCB_CMD_PFC_GCFG]	= { RTM_GETDCB, dcbnl_getpfccfg },
188562306a36Sopenharmony_ci	[DCB_CMD_PFC_SCFG]	= { RTM_SETDCB, dcbnl_setpfccfg },
188662306a36Sopenharmony_ci	[DCB_CMD_GPERM_HWADDR]	= { RTM_GETDCB, dcbnl_getperm_hwaddr },
188762306a36Sopenharmony_ci	[DCB_CMD_GCAP]		= { RTM_GETDCB, dcbnl_getcap },
188862306a36Sopenharmony_ci	[DCB_CMD_GNUMTCS]	= { RTM_GETDCB, dcbnl_getnumtcs },
188962306a36Sopenharmony_ci	[DCB_CMD_SNUMTCS]	= { RTM_SETDCB, dcbnl_setnumtcs },
189062306a36Sopenharmony_ci	[DCB_CMD_PFC_GSTATE]	= { RTM_GETDCB, dcbnl_getpfcstate },
189162306a36Sopenharmony_ci	[DCB_CMD_PFC_SSTATE]	= { RTM_SETDCB, dcbnl_setpfcstate },
189262306a36Sopenharmony_ci	[DCB_CMD_GAPP]		= { RTM_GETDCB, dcbnl_getapp },
189362306a36Sopenharmony_ci	[DCB_CMD_SAPP]		= { RTM_SETDCB, dcbnl_setapp },
189462306a36Sopenharmony_ci	[DCB_CMD_PGTX_GCFG]	= { RTM_GETDCB, dcbnl_pgtx_getcfg },
189562306a36Sopenharmony_ci	[DCB_CMD_PGTX_SCFG]	= { RTM_SETDCB, dcbnl_pgtx_setcfg },
189662306a36Sopenharmony_ci	[DCB_CMD_PGRX_GCFG]	= { RTM_GETDCB, dcbnl_pgrx_getcfg },
189762306a36Sopenharmony_ci	[DCB_CMD_PGRX_SCFG]	= { RTM_SETDCB, dcbnl_pgrx_setcfg },
189862306a36Sopenharmony_ci	[DCB_CMD_SET_ALL]	= { RTM_SETDCB, dcbnl_setall },
189962306a36Sopenharmony_ci	[DCB_CMD_BCN_GCFG]	= { RTM_GETDCB, dcbnl_bcn_getcfg },
190062306a36Sopenharmony_ci	[DCB_CMD_BCN_SCFG]	= { RTM_SETDCB, dcbnl_bcn_setcfg },
190162306a36Sopenharmony_ci	[DCB_CMD_IEEE_GET]	= { RTM_GETDCB, dcbnl_ieee_get },
190262306a36Sopenharmony_ci	[DCB_CMD_IEEE_SET]	= { RTM_SETDCB, dcbnl_ieee_set },
190362306a36Sopenharmony_ci	[DCB_CMD_IEEE_DEL]	= { RTM_SETDCB, dcbnl_ieee_del },
190462306a36Sopenharmony_ci	[DCB_CMD_GDCBX]		= { RTM_GETDCB, dcbnl_getdcbx },
190562306a36Sopenharmony_ci	[DCB_CMD_SDCBX]		= { RTM_SETDCB, dcbnl_setdcbx },
190662306a36Sopenharmony_ci	[DCB_CMD_GFEATCFG]	= { RTM_GETDCB, dcbnl_getfeatcfg },
190762306a36Sopenharmony_ci	[DCB_CMD_SFEATCFG]	= { RTM_SETDCB, dcbnl_setfeatcfg },
190862306a36Sopenharmony_ci	[DCB_CMD_CEE_GET]	= { RTM_GETDCB, dcbnl_cee_get },
190962306a36Sopenharmony_ci};
191062306a36Sopenharmony_ci
191162306a36Sopenharmony_cistatic int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
191262306a36Sopenharmony_ci		    struct netlink_ext_ack *extack)
191362306a36Sopenharmony_ci{
191462306a36Sopenharmony_ci	struct net *net = sock_net(skb->sk);
191562306a36Sopenharmony_ci	struct net_device *netdev;
191662306a36Sopenharmony_ci	struct dcbmsg *dcb = nlmsg_data(nlh);
191762306a36Sopenharmony_ci	struct nlattr *tb[DCB_ATTR_MAX + 1];
191862306a36Sopenharmony_ci	u32 portid = NETLINK_CB(skb).portid;
191962306a36Sopenharmony_ci	int ret = -EINVAL;
192062306a36Sopenharmony_ci	struct sk_buff *reply_skb;
192162306a36Sopenharmony_ci	struct nlmsghdr *reply_nlh = NULL;
192262306a36Sopenharmony_ci	const struct reply_func *fn;
192362306a36Sopenharmony_ci
192462306a36Sopenharmony_ci	if ((nlh->nlmsg_type == RTM_SETDCB) && !netlink_capable(skb, CAP_NET_ADMIN))
192562306a36Sopenharmony_ci		return -EPERM;
192662306a36Sopenharmony_ci
192762306a36Sopenharmony_ci	ret = nlmsg_parse_deprecated(nlh, sizeof(*dcb), tb, DCB_ATTR_MAX,
192862306a36Sopenharmony_ci				     dcbnl_rtnl_policy, extack);
192962306a36Sopenharmony_ci	if (ret < 0)
193062306a36Sopenharmony_ci		return ret;
193162306a36Sopenharmony_ci
193262306a36Sopenharmony_ci	if (dcb->cmd > DCB_CMD_MAX)
193362306a36Sopenharmony_ci		return -EINVAL;
193462306a36Sopenharmony_ci
193562306a36Sopenharmony_ci	/* check if a reply function has been defined for the command */
193662306a36Sopenharmony_ci	fn = &reply_funcs[dcb->cmd];
193762306a36Sopenharmony_ci	if (!fn->cb)
193862306a36Sopenharmony_ci		return -EOPNOTSUPP;
193962306a36Sopenharmony_ci	if (fn->type == RTM_SETDCB && !netlink_capable(skb, CAP_NET_ADMIN))
194062306a36Sopenharmony_ci		return -EPERM;
194162306a36Sopenharmony_ci
194262306a36Sopenharmony_ci	if (!tb[DCB_ATTR_IFNAME])
194362306a36Sopenharmony_ci		return -EINVAL;
194462306a36Sopenharmony_ci
194562306a36Sopenharmony_ci	netdev = __dev_get_by_name(net, nla_data(tb[DCB_ATTR_IFNAME]));
194662306a36Sopenharmony_ci	if (!netdev)
194762306a36Sopenharmony_ci		return -ENODEV;
194862306a36Sopenharmony_ci
194962306a36Sopenharmony_ci	if (!netdev->dcbnl_ops)
195062306a36Sopenharmony_ci		return -EOPNOTSUPP;
195162306a36Sopenharmony_ci
195262306a36Sopenharmony_ci	reply_skb = dcbnl_newmsg(fn->type, dcb->cmd, portid, nlh->nlmsg_seq,
195362306a36Sopenharmony_ci				 nlh->nlmsg_flags, &reply_nlh);
195462306a36Sopenharmony_ci	if (!reply_skb)
195562306a36Sopenharmony_ci		return -ENOMEM;
195662306a36Sopenharmony_ci
195762306a36Sopenharmony_ci	ret = fn->cb(netdev, nlh, nlh->nlmsg_seq, tb, reply_skb);
195862306a36Sopenharmony_ci	if (ret < 0) {
195962306a36Sopenharmony_ci		nlmsg_free(reply_skb);
196062306a36Sopenharmony_ci		goto out;
196162306a36Sopenharmony_ci	}
196262306a36Sopenharmony_ci
196362306a36Sopenharmony_ci	nlmsg_end(reply_skb, reply_nlh);
196462306a36Sopenharmony_ci
196562306a36Sopenharmony_ci	ret = rtnl_unicast(reply_skb, net, portid);
196662306a36Sopenharmony_ciout:
196762306a36Sopenharmony_ci	return ret;
196862306a36Sopenharmony_ci}
196962306a36Sopenharmony_ci
197062306a36Sopenharmony_cistatic struct dcb_app_type *dcb_rewr_lookup(const struct dcb_app *app,
197162306a36Sopenharmony_ci					    int ifindex, int proto)
197262306a36Sopenharmony_ci{
197362306a36Sopenharmony_ci	struct dcb_app_type *itr;
197462306a36Sopenharmony_ci
197562306a36Sopenharmony_ci	list_for_each_entry(itr, &dcb_rewr_list, list) {
197662306a36Sopenharmony_ci		if (itr->app.selector == app->selector &&
197762306a36Sopenharmony_ci		    itr->app.priority == app->priority &&
197862306a36Sopenharmony_ci		    itr->ifindex == ifindex &&
197962306a36Sopenharmony_ci		    ((proto == -1) || itr->app.protocol == proto))
198062306a36Sopenharmony_ci			return itr;
198162306a36Sopenharmony_ci	}
198262306a36Sopenharmony_ci
198362306a36Sopenharmony_ci	return NULL;
198462306a36Sopenharmony_ci}
198562306a36Sopenharmony_ci
198662306a36Sopenharmony_cistatic struct dcb_app_type *dcb_app_lookup(const struct dcb_app *app,
198762306a36Sopenharmony_ci					   int ifindex, int prio)
198862306a36Sopenharmony_ci{
198962306a36Sopenharmony_ci	struct dcb_app_type *itr;
199062306a36Sopenharmony_ci
199162306a36Sopenharmony_ci	list_for_each_entry(itr, &dcb_app_list, list) {
199262306a36Sopenharmony_ci		if (itr->app.selector == app->selector &&
199362306a36Sopenharmony_ci		    itr->app.protocol == app->protocol &&
199462306a36Sopenharmony_ci		    itr->ifindex == ifindex &&
199562306a36Sopenharmony_ci		    ((prio == -1) || itr->app.priority == prio))
199662306a36Sopenharmony_ci			return itr;
199762306a36Sopenharmony_ci	}
199862306a36Sopenharmony_ci
199962306a36Sopenharmony_ci	return NULL;
200062306a36Sopenharmony_ci}
200162306a36Sopenharmony_ci
200262306a36Sopenharmony_cistatic int dcb_app_add(struct list_head *list, const struct dcb_app *app,
200362306a36Sopenharmony_ci		       int ifindex)
200462306a36Sopenharmony_ci{
200562306a36Sopenharmony_ci	struct dcb_app_type *entry;
200662306a36Sopenharmony_ci
200762306a36Sopenharmony_ci	entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
200862306a36Sopenharmony_ci	if (!entry)
200962306a36Sopenharmony_ci		return -ENOMEM;
201062306a36Sopenharmony_ci
201162306a36Sopenharmony_ci	memcpy(&entry->app, app, sizeof(*app));
201262306a36Sopenharmony_ci	entry->ifindex = ifindex;
201362306a36Sopenharmony_ci	list_add(&entry->list, list);
201462306a36Sopenharmony_ci
201562306a36Sopenharmony_ci	return 0;
201662306a36Sopenharmony_ci}
201762306a36Sopenharmony_ci
201862306a36Sopenharmony_ci/**
201962306a36Sopenharmony_ci * dcb_getapp - retrieve the DCBX application user priority
202062306a36Sopenharmony_ci * @dev: network interface
202162306a36Sopenharmony_ci * @app: application to get user priority of
202262306a36Sopenharmony_ci *
202362306a36Sopenharmony_ci * On success returns a non-zero 802.1p user priority bitmap
202462306a36Sopenharmony_ci * otherwise returns 0 as the invalid user priority bitmap to
202562306a36Sopenharmony_ci * indicate an error.
202662306a36Sopenharmony_ci */
202762306a36Sopenharmony_ciu8 dcb_getapp(struct net_device *dev, struct dcb_app *app)
202862306a36Sopenharmony_ci{
202962306a36Sopenharmony_ci	struct dcb_app_type *itr;
203062306a36Sopenharmony_ci	u8 prio = 0;
203162306a36Sopenharmony_ci
203262306a36Sopenharmony_ci	spin_lock_bh(&dcb_lock);
203362306a36Sopenharmony_ci	itr = dcb_app_lookup(app, dev->ifindex, -1);
203462306a36Sopenharmony_ci	if (itr)
203562306a36Sopenharmony_ci		prio = itr->app.priority;
203662306a36Sopenharmony_ci	spin_unlock_bh(&dcb_lock);
203762306a36Sopenharmony_ci
203862306a36Sopenharmony_ci	return prio;
203962306a36Sopenharmony_ci}
204062306a36Sopenharmony_ciEXPORT_SYMBOL(dcb_getapp);
204162306a36Sopenharmony_ci
204262306a36Sopenharmony_ci/**
204362306a36Sopenharmony_ci * dcb_setapp - add CEE dcb application data to app list
204462306a36Sopenharmony_ci * @dev: network interface
204562306a36Sopenharmony_ci * @new: application data to add
204662306a36Sopenharmony_ci *
204762306a36Sopenharmony_ci * Priority 0 is an invalid priority in CEE spec. This routine
204862306a36Sopenharmony_ci * removes applications from the app list if the priority is
204962306a36Sopenharmony_ci * set to zero. Priority is expected to be 8-bit 802.1p user priority bitmap
205062306a36Sopenharmony_ci */
205162306a36Sopenharmony_ciint dcb_setapp(struct net_device *dev, struct dcb_app *new)
205262306a36Sopenharmony_ci{
205362306a36Sopenharmony_ci	struct dcb_app_type *itr;
205462306a36Sopenharmony_ci	struct dcb_app_type event;
205562306a36Sopenharmony_ci	int err = 0;
205662306a36Sopenharmony_ci
205762306a36Sopenharmony_ci	event.ifindex = dev->ifindex;
205862306a36Sopenharmony_ci	memcpy(&event.app, new, sizeof(event.app));
205962306a36Sopenharmony_ci	if (dev->dcbnl_ops->getdcbx)
206062306a36Sopenharmony_ci		event.dcbx = dev->dcbnl_ops->getdcbx(dev);
206162306a36Sopenharmony_ci
206262306a36Sopenharmony_ci	spin_lock_bh(&dcb_lock);
206362306a36Sopenharmony_ci	/* Search for existing match and replace */
206462306a36Sopenharmony_ci	itr = dcb_app_lookup(new, dev->ifindex, -1);
206562306a36Sopenharmony_ci	if (itr) {
206662306a36Sopenharmony_ci		if (new->priority)
206762306a36Sopenharmony_ci			itr->app.priority = new->priority;
206862306a36Sopenharmony_ci		else {
206962306a36Sopenharmony_ci			list_del(&itr->list);
207062306a36Sopenharmony_ci			kfree(itr);
207162306a36Sopenharmony_ci		}
207262306a36Sopenharmony_ci		goto out;
207362306a36Sopenharmony_ci	}
207462306a36Sopenharmony_ci	/* App type does not exist add new application type */
207562306a36Sopenharmony_ci	if (new->priority)
207662306a36Sopenharmony_ci		err = dcb_app_add(&dcb_app_list, new, dev->ifindex);
207762306a36Sopenharmony_ciout:
207862306a36Sopenharmony_ci	spin_unlock_bh(&dcb_lock);
207962306a36Sopenharmony_ci	if (!err)
208062306a36Sopenharmony_ci		call_dcbevent_notifiers(DCB_APP_EVENT, &event);
208162306a36Sopenharmony_ci	return err;
208262306a36Sopenharmony_ci}
208362306a36Sopenharmony_ciEXPORT_SYMBOL(dcb_setapp);
208462306a36Sopenharmony_ci
208562306a36Sopenharmony_ci/**
208662306a36Sopenharmony_ci * dcb_ieee_getapp_mask - retrieve the IEEE DCB application priority
208762306a36Sopenharmony_ci * @dev: network interface
208862306a36Sopenharmony_ci * @app: where to store the retrieve application data
208962306a36Sopenharmony_ci *
209062306a36Sopenharmony_ci * Helper routine which on success returns a non-zero 802.1Qaz user
209162306a36Sopenharmony_ci * priority bitmap otherwise returns 0 to indicate the dcb_app was
209262306a36Sopenharmony_ci * not found in APP list.
209362306a36Sopenharmony_ci */
209462306a36Sopenharmony_ciu8 dcb_ieee_getapp_mask(struct net_device *dev, struct dcb_app *app)
209562306a36Sopenharmony_ci{
209662306a36Sopenharmony_ci	struct dcb_app_type *itr;
209762306a36Sopenharmony_ci	u8 prio = 0;
209862306a36Sopenharmony_ci
209962306a36Sopenharmony_ci	spin_lock_bh(&dcb_lock);
210062306a36Sopenharmony_ci	itr = dcb_app_lookup(app, dev->ifindex, -1);
210162306a36Sopenharmony_ci	if (itr)
210262306a36Sopenharmony_ci		prio |= 1 << itr->app.priority;
210362306a36Sopenharmony_ci	spin_unlock_bh(&dcb_lock);
210462306a36Sopenharmony_ci
210562306a36Sopenharmony_ci	return prio;
210662306a36Sopenharmony_ci}
210762306a36Sopenharmony_ciEXPORT_SYMBOL(dcb_ieee_getapp_mask);
210862306a36Sopenharmony_ci
210962306a36Sopenharmony_ci/* Get protocol value from rewrite entry. */
211062306a36Sopenharmony_ciu16 dcb_getrewr(struct net_device *dev, struct dcb_app *app)
211162306a36Sopenharmony_ci{
211262306a36Sopenharmony_ci	struct dcb_app_type *itr;
211362306a36Sopenharmony_ci	u16 proto = 0;
211462306a36Sopenharmony_ci
211562306a36Sopenharmony_ci	spin_lock_bh(&dcb_lock);
211662306a36Sopenharmony_ci	itr = dcb_rewr_lookup(app, dev->ifindex, -1);
211762306a36Sopenharmony_ci	if (itr)
211862306a36Sopenharmony_ci		proto = itr->app.protocol;
211962306a36Sopenharmony_ci	spin_unlock_bh(&dcb_lock);
212062306a36Sopenharmony_ci
212162306a36Sopenharmony_ci	return proto;
212262306a36Sopenharmony_ci}
212362306a36Sopenharmony_ciEXPORT_SYMBOL(dcb_getrewr);
212462306a36Sopenharmony_ci
212562306a36Sopenharmony_ci /* Add rewrite entry to the rewrite list. */
212662306a36Sopenharmony_ciint dcb_setrewr(struct net_device *dev, struct dcb_app *new)
212762306a36Sopenharmony_ci{
212862306a36Sopenharmony_ci	int err;
212962306a36Sopenharmony_ci
213062306a36Sopenharmony_ci	spin_lock_bh(&dcb_lock);
213162306a36Sopenharmony_ci	/* Search for existing match and abort if found. */
213262306a36Sopenharmony_ci	if (dcb_rewr_lookup(new, dev->ifindex, new->protocol)) {
213362306a36Sopenharmony_ci		err = -EEXIST;
213462306a36Sopenharmony_ci		goto out;
213562306a36Sopenharmony_ci	}
213662306a36Sopenharmony_ci
213762306a36Sopenharmony_ci	err = dcb_app_add(&dcb_rewr_list, new, dev->ifindex);
213862306a36Sopenharmony_ciout:
213962306a36Sopenharmony_ci	spin_unlock_bh(&dcb_lock);
214062306a36Sopenharmony_ci
214162306a36Sopenharmony_ci	return err;
214262306a36Sopenharmony_ci}
214362306a36Sopenharmony_ciEXPORT_SYMBOL(dcb_setrewr);
214462306a36Sopenharmony_ci
214562306a36Sopenharmony_ci/* Delete rewrite entry from the rewrite list. */
214662306a36Sopenharmony_ciint dcb_delrewr(struct net_device *dev, struct dcb_app *del)
214762306a36Sopenharmony_ci{
214862306a36Sopenharmony_ci	struct dcb_app_type *itr;
214962306a36Sopenharmony_ci	int err = -ENOENT;
215062306a36Sopenharmony_ci
215162306a36Sopenharmony_ci	spin_lock_bh(&dcb_lock);
215262306a36Sopenharmony_ci	/* Search for existing match and remove it. */
215362306a36Sopenharmony_ci	itr = dcb_rewr_lookup(del, dev->ifindex, del->protocol);
215462306a36Sopenharmony_ci	if (itr) {
215562306a36Sopenharmony_ci		list_del(&itr->list);
215662306a36Sopenharmony_ci		kfree(itr);
215762306a36Sopenharmony_ci		err = 0;
215862306a36Sopenharmony_ci	}
215962306a36Sopenharmony_ci
216062306a36Sopenharmony_ci	spin_unlock_bh(&dcb_lock);
216162306a36Sopenharmony_ci
216262306a36Sopenharmony_ci	return err;
216362306a36Sopenharmony_ci}
216462306a36Sopenharmony_ciEXPORT_SYMBOL(dcb_delrewr);
216562306a36Sopenharmony_ci
216662306a36Sopenharmony_ci/**
216762306a36Sopenharmony_ci * dcb_ieee_setapp - add IEEE dcb application data to app list
216862306a36Sopenharmony_ci * @dev: network interface
216962306a36Sopenharmony_ci * @new: application data to add
217062306a36Sopenharmony_ci *
217162306a36Sopenharmony_ci * This adds Application data to the list. Multiple application
217262306a36Sopenharmony_ci * entries may exists for the same selector and protocol as long
217362306a36Sopenharmony_ci * as the priorities are different. Priority is expected to be a
217462306a36Sopenharmony_ci * 3-bit unsigned integer
217562306a36Sopenharmony_ci */
217662306a36Sopenharmony_ciint dcb_ieee_setapp(struct net_device *dev, struct dcb_app *new)
217762306a36Sopenharmony_ci{
217862306a36Sopenharmony_ci	struct dcb_app_type event;
217962306a36Sopenharmony_ci	int err = 0;
218062306a36Sopenharmony_ci
218162306a36Sopenharmony_ci	event.ifindex = dev->ifindex;
218262306a36Sopenharmony_ci	memcpy(&event.app, new, sizeof(event.app));
218362306a36Sopenharmony_ci	if (dev->dcbnl_ops->getdcbx)
218462306a36Sopenharmony_ci		event.dcbx = dev->dcbnl_ops->getdcbx(dev);
218562306a36Sopenharmony_ci
218662306a36Sopenharmony_ci	spin_lock_bh(&dcb_lock);
218762306a36Sopenharmony_ci	/* Search for existing match and abort if found */
218862306a36Sopenharmony_ci	if (dcb_app_lookup(new, dev->ifindex, new->priority)) {
218962306a36Sopenharmony_ci		err = -EEXIST;
219062306a36Sopenharmony_ci		goto out;
219162306a36Sopenharmony_ci	}
219262306a36Sopenharmony_ci
219362306a36Sopenharmony_ci	err = dcb_app_add(&dcb_app_list, new, dev->ifindex);
219462306a36Sopenharmony_ciout:
219562306a36Sopenharmony_ci	spin_unlock_bh(&dcb_lock);
219662306a36Sopenharmony_ci	if (!err)
219762306a36Sopenharmony_ci		call_dcbevent_notifiers(DCB_APP_EVENT, &event);
219862306a36Sopenharmony_ci	return err;
219962306a36Sopenharmony_ci}
220062306a36Sopenharmony_ciEXPORT_SYMBOL(dcb_ieee_setapp);
220162306a36Sopenharmony_ci
220262306a36Sopenharmony_ci/**
220362306a36Sopenharmony_ci * dcb_ieee_delapp - delete IEEE dcb application data from list
220462306a36Sopenharmony_ci * @dev: network interface
220562306a36Sopenharmony_ci * @del: application data to delete
220662306a36Sopenharmony_ci *
220762306a36Sopenharmony_ci * This removes a matching APP data from the APP list
220862306a36Sopenharmony_ci */
220962306a36Sopenharmony_ciint dcb_ieee_delapp(struct net_device *dev, struct dcb_app *del)
221062306a36Sopenharmony_ci{
221162306a36Sopenharmony_ci	struct dcb_app_type *itr;
221262306a36Sopenharmony_ci	struct dcb_app_type event;
221362306a36Sopenharmony_ci	int err = -ENOENT;
221462306a36Sopenharmony_ci
221562306a36Sopenharmony_ci	event.ifindex = dev->ifindex;
221662306a36Sopenharmony_ci	memcpy(&event.app, del, sizeof(event.app));
221762306a36Sopenharmony_ci	if (dev->dcbnl_ops->getdcbx)
221862306a36Sopenharmony_ci		event.dcbx = dev->dcbnl_ops->getdcbx(dev);
221962306a36Sopenharmony_ci
222062306a36Sopenharmony_ci	spin_lock_bh(&dcb_lock);
222162306a36Sopenharmony_ci	/* Search for existing match and remove it. */
222262306a36Sopenharmony_ci	if ((itr = dcb_app_lookup(del, dev->ifindex, del->priority))) {
222362306a36Sopenharmony_ci		list_del(&itr->list);
222462306a36Sopenharmony_ci		kfree(itr);
222562306a36Sopenharmony_ci		err = 0;
222662306a36Sopenharmony_ci	}
222762306a36Sopenharmony_ci
222862306a36Sopenharmony_ci	spin_unlock_bh(&dcb_lock);
222962306a36Sopenharmony_ci	if (!err)
223062306a36Sopenharmony_ci		call_dcbevent_notifiers(DCB_APP_EVENT, &event);
223162306a36Sopenharmony_ci	return err;
223262306a36Sopenharmony_ci}
223362306a36Sopenharmony_ciEXPORT_SYMBOL(dcb_ieee_delapp);
223462306a36Sopenharmony_ci
223562306a36Sopenharmony_ci/* dcb_getrewr_prio_pcp_mask_map - For a given device, find mapping from
223662306a36Sopenharmony_ci * priorities to the PCP and DEI values assigned to that priority.
223762306a36Sopenharmony_ci */
223862306a36Sopenharmony_civoid dcb_getrewr_prio_pcp_mask_map(const struct net_device *dev,
223962306a36Sopenharmony_ci				   struct dcb_rewr_prio_pcp_map *p_map)
224062306a36Sopenharmony_ci{
224162306a36Sopenharmony_ci	int ifindex = dev->ifindex;
224262306a36Sopenharmony_ci	struct dcb_app_type *itr;
224362306a36Sopenharmony_ci	u8 prio;
224462306a36Sopenharmony_ci
224562306a36Sopenharmony_ci	memset(p_map->map, 0, sizeof(p_map->map));
224662306a36Sopenharmony_ci
224762306a36Sopenharmony_ci	spin_lock_bh(&dcb_lock);
224862306a36Sopenharmony_ci	list_for_each_entry(itr, &dcb_rewr_list, list) {
224962306a36Sopenharmony_ci		if (itr->ifindex == ifindex &&
225062306a36Sopenharmony_ci		    itr->app.selector == DCB_APP_SEL_PCP &&
225162306a36Sopenharmony_ci		    itr->app.protocol < 16 &&
225262306a36Sopenharmony_ci		    itr->app.priority < IEEE_8021QAZ_MAX_TCS) {
225362306a36Sopenharmony_ci			prio = itr->app.priority;
225462306a36Sopenharmony_ci			p_map->map[prio] |= 1 << itr->app.protocol;
225562306a36Sopenharmony_ci		}
225662306a36Sopenharmony_ci	}
225762306a36Sopenharmony_ci	spin_unlock_bh(&dcb_lock);
225862306a36Sopenharmony_ci}
225962306a36Sopenharmony_ciEXPORT_SYMBOL(dcb_getrewr_prio_pcp_mask_map);
226062306a36Sopenharmony_ci
226162306a36Sopenharmony_ci/* dcb_getrewr_prio_dscp_mask_map - For a given device, find mapping from
226262306a36Sopenharmony_ci * priorities to the DSCP values assigned to that priority.
226362306a36Sopenharmony_ci */
226462306a36Sopenharmony_civoid dcb_getrewr_prio_dscp_mask_map(const struct net_device *dev,
226562306a36Sopenharmony_ci				    struct dcb_ieee_app_prio_map *p_map)
226662306a36Sopenharmony_ci{
226762306a36Sopenharmony_ci	int ifindex = dev->ifindex;
226862306a36Sopenharmony_ci	struct dcb_app_type *itr;
226962306a36Sopenharmony_ci	u8 prio;
227062306a36Sopenharmony_ci
227162306a36Sopenharmony_ci	memset(p_map->map, 0, sizeof(p_map->map));
227262306a36Sopenharmony_ci
227362306a36Sopenharmony_ci	spin_lock_bh(&dcb_lock);
227462306a36Sopenharmony_ci	list_for_each_entry(itr, &dcb_rewr_list, list) {
227562306a36Sopenharmony_ci		if (itr->ifindex == ifindex &&
227662306a36Sopenharmony_ci		    itr->app.selector == IEEE_8021QAZ_APP_SEL_DSCP &&
227762306a36Sopenharmony_ci		    itr->app.protocol < 64 &&
227862306a36Sopenharmony_ci		    itr->app.priority < IEEE_8021QAZ_MAX_TCS) {
227962306a36Sopenharmony_ci			prio = itr->app.priority;
228062306a36Sopenharmony_ci			p_map->map[prio] |= 1ULL << itr->app.protocol;
228162306a36Sopenharmony_ci		}
228262306a36Sopenharmony_ci	}
228362306a36Sopenharmony_ci	spin_unlock_bh(&dcb_lock);
228462306a36Sopenharmony_ci}
228562306a36Sopenharmony_ciEXPORT_SYMBOL(dcb_getrewr_prio_dscp_mask_map);
228662306a36Sopenharmony_ci
228762306a36Sopenharmony_ci/*
228862306a36Sopenharmony_ci * dcb_ieee_getapp_prio_dscp_mask_map - For a given device, find mapping from
228962306a36Sopenharmony_ci * priorities to the DSCP values assigned to that priority. Initialize p_map
229062306a36Sopenharmony_ci * such that each map element holds a bit mask of DSCP values configured for
229162306a36Sopenharmony_ci * that priority by APP entries.
229262306a36Sopenharmony_ci */
229362306a36Sopenharmony_civoid dcb_ieee_getapp_prio_dscp_mask_map(const struct net_device *dev,
229462306a36Sopenharmony_ci					struct dcb_ieee_app_prio_map *p_map)
229562306a36Sopenharmony_ci{
229662306a36Sopenharmony_ci	int ifindex = dev->ifindex;
229762306a36Sopenharmony_ci	struct dcb_app_type *itr;
229862306a36Sopenharmony_ci	u8 prio;
229962306a36Sopenharmony_ci
230062306a36Sopenharmony_ci	memset(p_map->map, 0, sizeof(p_map->map));
230162306a36Sopenharmony_ci
230262306a36Sopenharmony_ci	spin_lock_bh(&dcb_lock);
230362306a36Sopenharmony_ci	list_for_each_entry(itr, &dcb_app_list, list) {
230462306a36Sopenharmony_ci		if (itr->ifindex == ifindex &&
230562306a36Sopenharmony_ci		    itr->app.selector == IEEE_8021QAZ_APP_SEL_DSCP &&
230662306a36Sopenharmony_ci		    itr->app.protocol < 64 &&
230762306a36Sopenharmony_ci		    itr->app.priority < IEEE_8021QAZ_MAX_TCS) {
230862306a36Sopenharmony_ci			prio = itr->app.priority;
230962306a36Sopenharmony_ci			p_map->map[prio] |= 1ULL << itr->app.protocol;
231062306a36Sopenharmony_ci		}
231162306a36Sopenharmony_ci	}
231262306a36Sopenharmony_ci	spin_unlock_bh(&dcb_lock);
231362306a36Sopenharmony_ci}
231462306a36Sopenharmony_ciEXPORT_SYMBOL(dcb_ieee_getapp_prio_dscp_mask_map);
231562306a36Sopenharmony_ci
231662306a36Sopenharmony_ci/*
231762306a36Sopenharmony_ci * dcb_ieee_getapp_dscp_prio_mask_map - For a given device, find mapping from
231862306a36Sopenharmony_ci * DSCP values to the priorities assigned to that DSCP value. Initialize p_map
231962306a36Sopenharmony_ci * such that each map element holds a bit mask of priorities configured for a
232062306a36Sopenharmony_ci * given DSCP value by APP entries.
232162306a36Sopenharmony_ci */
232262306a36Sopenharmony_civoid
232362306a36Sopenharmony_cidcb_ieee_getapp_dscp_prio_mask_map(const struct net_device *dev,
232462306a36Sopenharmony_ci				   struct dcb_ieee_app_dscp_map *p_map)
232562306a36Sopenharmony_ci{
232662306a36Sopenharmony_ci	int ifindex = dev->ifindex;
232762306a36Sopenharmony_ci	struct dcb_app_type *itr;
232862306a36Sopenharmony_ci
232962306a36Sopenharmony_ci	memset(p_map->map, 0, sizeof(p_map->map));
233062306a36Sopenharmony_ci
233162306a36Sopenharmony_ci	spin_lock_bh(&dcb_lock);
233262306a36Sopenharmony_ci	list_for_each_entry(itr, &dcb_app_list, list) {
233362306a36Sopenharmony_ci		if (itr->ifindex == ifindex &&
233462306a36Sopenharmony_ci		    itr->app.selector == IEEE_8021QAZ_APP_SEL_DSCP &&
233562306a36Sopenharmony_ci		    itr->app.protocol < 64 &&
233662306a36Sopenharmony_ci		    itr->app.priority < IEEE_8021QAZ_MAX_TCS)
233762306a36Sopenharmony_ci			p_map->map[itr->app.protocol] |= 1 << itr->app.priority;
233862306a36Sopenharmony_ci	}
233962306a36Sopenharmony_ci	spin_unlock_bh(&dcb_lock);
234062306a36Sopenharmony_ci}
234162306a36Sopenharmony_ciEXPORT_SYMBOL(dcb_ieee_getapp_dscp_prio_mask_map);
234262306a36Sopenharmony_ci
234362306a36Sopenharmony_ci/*
234462306a36Sopenharmony_ci * Per 802.1Q-2014, the selector value of 1 is used for matching on Ethernet
234562306a36Sopenharmony_ci * type, with valid PID values >= 1536. A special meaning is then assigned to
234662306a36Sopenharmony_ci * protocol value of 0: "default priority. For use when priority is not
234762306a36Sopenharmony_ci * otherwise specified".
234862306a36Sopenharmony_ci *
234962306a36Sopenharmony_ci * dcb_ieee_getapp_default_prio_mask - For a given device, find all APP entries
235062306a36Sopenharmony_ci * of the form {$PRIO, ETHERTYPE, 0} and construct a bit mask of all default
235162306a36Sopenharmony_ci * priorities set by these entries.
235262306a36Sopenharmony_ci */
235362306a36Sopenharmony_ciu8 dcb_ieee_getapp_default_prio_mask(const struct net_device *dev)
235462306a36Sopenharmony_ci{
235562306a36Sopenharmony_ci	int ifindex = dev->ifindex;
235662306a36Sopenharmony_ci	struct dcb_app_type *itr;
235762306a36Sopenharmony_ci	u8 mask = 0;
235862306a36Sopenharmony_ci
235962306a36Sopenharmony_ci	spin_lock_bh(&dcb_lock);
236062306a36Sopenharmony_ci	list_for_each_entry(itr, &dcb_app_list, list) {
236162306a36Sopenharmony_ci		if (itr->ifindex == ifindex &&
236262306a36Sopenharmony_ci		    itr->app.selector == IEEE_8021QAZ_APP_SEL_ETHERTYPE &&
236362306a36Sopenharmony_ci		    itr->app.protocol == 0 &&
236462306a36Sopenharmony_ci		    itr->app.priority < IEEE_8021QAZ_MAX_TCS)
236562306a36Sopenharmony_ci			mask |= 1 << itr->app.priority;
236662306a36Sopenharmony_ci	}
236762306a36Sopenharmony_ci	spin_unlock_bh(&dcb_lock);
236862306a36Sopenharmony_ci
236962306a36Sopenharmony_ci	return mask;
237062306a36Sopenharmony_ci}
237162306a36Sopenharmony_ciEXPORT_SYMBOL(dcb_ieee_getapp_default_prio_mask);
237262306a36Sopenharmony_ci
237362306a36Sopenharmony_cistatic void dcbnl_flush_dev(struct net_device *dev)
237462306a36Sopenharmony_ci{
237562306a36Sopenharmony_ci	struct dcb_app_type *itr, *tmp;
237662306a36Sopenharmony_ci
237762306a36Sopenharmony_ci	spin_lock_bh(&dcb_lock);
237862306a36Sopenharmony_ci
237962306a36Sopenharmony_ci	list_for_each_entry_safe(itr, tmp, &dcb_app_list, list) {
238062306a36Sopenharmony_ci		if (itr->ifindex == dev->ifindex) {
238162306a36Sopenharmony_ci			list_del(&itr->list);
238262306a36Sopenharmony_ci			kfree(itr);
238362306a36Sopenharmony_ci		}
238462306a36Sopenharmony_ci	}
238562306a36Sopenharmony_ci
238662306a36Sopenharmony_ci	spin_unlock_bh(&dcb_lock);
238762306a36Sopenharmony_ci}
238862306a36Sopenharmony_ci
238962306a36Sopenharmony_cistatic int dcbnl_netdevice_event(struct notifier_block *nb,
239062306a36Sopenharmony_ci				 unsigned long event, void *ptr)
239162306a36Sopenharmony_ci{
239262306a36Sopenharmony_ci	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
239362306a36Sopenharmony_ci
239462306a36Sopenharmony_ci	switch (event) {
239562306a36Sopenharmony_ci	case NETDEV_UNREGISTER:
239662306a36Sopenharmony_ci		if (!dev->dcbnl_ops)
239762306a36Sopenharmony_ci			return NOTIFY_DONE;
239862306a36Sopenharmony_ci
239962306a36Sopenharmony_ci		dcbnl_flush_dev(dev);
240062306a36Sopenharmony_ci
240162306a36Sopenharmony_ci		return NOTIFY_OK;
240262306a36Sopenharmony_ci	default:
240362306a36Sopenharmony_ci		return NOTIFY_DONE;
240462306a36Sopenharmony_ci	}
240562306a36Sopenharmony_ci}
240662306a36Sopenharmony_ci
240762306a36Sopenharmony_cistatic struct notifier_block dcbnl_nb __read_mostly = {
240862306a36Sopenharmony_ci	.notifier_call  = dcbnl_netdevice_event,
240962306a36Sopenharmony_ci};
241062306a36Sopenharmony_ci
241162306a36Sopenharmony_cistatic int __init dcbnl_init(void)
241262306a36Sopenharmony_ci{
241362306a36Sopenharmony_ci	int err;
241462306a36Sopenharmony_ci
241562306a36Sopenharmony_ci	err = register_netdevice_notifier(&dcbnl_nb);
241662306a36Sopenharmony_ci	if (err)
241762306a36Sopenharmony_ci		return err;
241862306a36Sopenharmony_ci
241962306a36Sopenharmony_ci	rtnl_register(PF_UNSPEC, RTM_GETDCB, dcb_doit, NULL, 0);
242062306a36Sopenharmony_ci	rtnl_register(PF_UNSPEC, RTM_SETDCB, dcb_doit, NULL, 0);
242162306a36Sopenharmony_ci
242262306a36Sopenharmony_ci	return 0;
242362306a36Sopenharmony_ci}
242462306a36Sopenharmony_cidevice_initcall(dcbnl_init);
2425