xref: /openbmc/linux/net/dcb/dcbnl.c (revision 31d49ba0)
19952f691SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
22f90b865SAlexander Duyck /*
3698e1d23SMark Rustad  * Copyright (c) 2008-2011, Intel Corporation.
42f90b865SAlexander Duyck  *
536b9ad80SPaul Gortmaker  * Description: Data Center Bridging netlink interface
62f90b865SAlexander Duyck  * Author: Lucy Liu <lucy.liu@intel.com>
72f90b865SAlexander Duyck  */
82f90b865SAlexander Duyck 
92f90b865SAlexander Duyck #include <linux/netdevice.h>
102f90b865SAlexander Duyck #include <linux/netlink.h>
115a0e3ad6STejun Heo #include <linux/slab.h>
122f90b865SAlexander Duyck #include <net/netlink.h>
132f90b865SAlexander Duyck #include <net/rtnetlink.h>
142f90b865SAlexander Duyck #include <linux/dcbnl.h>
1596b99684SJohn Fastabend #include <net/dcbevent.h>
162f90b865SAlexander Duyck #include <linux/rtnetlink.h>
1736b9ad80SPaul Gortmaker #include <linux/init.h>
182f90b865SAlexander Duyck #include <net/sock.h>
192f90b865SAlexander Duyck 
20ae86b9e3SBen Hutchings /* Data Center Bridging (DCB) is a collection of Ethernet enhancements
212f90b865SAlexander Duyck  * intended to allow network traffic with differing requirements
222f90b865SAlexander Duyck  * (highly reliable, no drops vs. best effort vs. low latency) to operate
232f90b865SAlexander Duyck  * and co-exist on Ethernet.  Current DCB features are:
242f90b865SAlexander Duyck  *
252f90b865SAlexander Duyck  * Enhanced Transmission Selection (aka Priority Grouping [PG]) - provides a
262f90b865SAlexander Duyck  *   framework for assigning bandwidth guarantees to traffic classes.
272f90b865SAlexander Duyck  *
282f90b865SAlexander Duyck  * Priority-based Flow Control (PFC) - provides a flow control mechanism which
292f90b865SAlexander Duyck  *   can work independently for each 802.1p priority.
302f90b865SAlexander Duyck  *
312f90b865SAlexander Duyck  * Congestion Notification - provides a mechanism for end-to-end congestion
322f90b865SAlexander Duyck  *   control for protocols which do not have built-in congestion management.
332f90b865SAlexander Duyck  *
342f90b865SAlexander Duyck  * More information about the emerging standards for these Ethernet features
352f90b865SAlexander Duyck  * can be found at: http://www.ieee802.org/1/pages/dcbridges.html
362f90b865SAlexander Duyck  *
372f90b865SAlexander Duyck  * This file implements an rtnetlink interface to allow configuration of DCB
382f90b865SAlexander Duyck  * features for capable devices.
392f90b865SAlexander Duyck  */
402f90b865SAlexander Duyck 
412f90b865SAlexander Duyck /**************** DCB attribute policies *************************************/
422f90b865SAlexander Duyck 
432f90b865SAlexander Duyck /* DCB netlink attributes policy */
44b54452b0SAlexey Dobriyan static const struct nla_policy dcbnl_rtnl_policy[DCB_ATTR_MAX + 1] = {
45859ee3c4SAlexander Duyck 	[DCB_ATTR_IFNAME]      = {.type = NLA_NUL_STRING, .len = IFNAMSIZ - 1},
462f90b865SAlexander Duyck 	[DCB_ATTR_STATE]       = {.type = NLA_U8},
472f90b865SAlexander Duyck 	[DCB_ATTR_PFC_CFG]     = {.type = NLA_NESTED},
482f90b865SAlexander Duyck 	[DCB_ATTR_PG_CFG]      = {.type = NLA_NESTED},
492f90b865SAlexander Duyck 	[DCB_ATTR_SET_ALL]     = {.type = NLA_U8},
502f90b865SAlexander Duyck 	[DCB_ATTR_PERM_HWADDR] = {.type = NLA_FLAG},
5146132188SAlexander Duyck 	[DCB_ATTR_CAP]         = {.type = NLA_NESTED},
520eb3aa9bSAlexander Duyck 	[DCB_ATTR_PFC_STATE]   = {.type = NLA_U8},
53859ee3c4SAlexander Duyck 	[DCB_ATTR_BCN]         = {.type = NLA_NESTED},
546fa382afSYi Zou 	[DCB_ATTR_APP]         = {.type = NLA_NESTED},
553e29027aSJohn Fastabend 	[DCB_ATTR_IEEE]	       = {.type = NLA_NESTED},
566241b625SShmulik Ravid 	[DCB_ATTR_DCBX]        = {.type = NLA_U8},
57ea45fe4eSShmulik Ravid 	[DCB_ATTR_FEATCFG]     = {.type = NLA_NESTED},
582f90b865SAlexander Duyck };
592f90b865SAlexander Duyck 
602f90b865SAlexander Duyck /* DCB priority flow control to User Priority nested attributes */
61b54452b0SAlexey Dobriyan static const struct nla_policy dcbnl_pfc_up_nest[DCB_PFC_UP_ATTR_MAX + 1] = {
622f90b865SAlexander Duyck 	[DCB_PFC_UP_ATTR_0]   = {.type = NLA_U8},
632f90b865SAlexander Duyck 	[DCB_PFC_UP_ATTR_1]   = {.type = NLA_U8},
642f90b865SAlexander Duyck 	[DCB_PFC_UP_ATTR_2]   = {.type = NLA_U8},
652f90b865SAlexander Duyck 	[DCB_PFC_UP_ATTR_3]   = {.type = NLA_U8},
662f90b865SAlexander Duyck 	[DCB_PFC_UP_ATTR_4]   = {.type = NLA_U8},
672f90b865SAlexander Duyck 	[DCB_PFC_UP_ATTR_5]   = {.type = NLA_U8},
682f90b865SAlexander Duyck 	[DCB_PFC_UP_ATTR_6]   = {.type = NLA_U8},
692f90b865SAlexander Duyck 	[DCB_PFC_UP_ATTR_7]   = {.type = NLA_U8},
702f90b865SAlexander Duyck 	[DCB_PFC_UP_ATTR_ALL] = {.type = NLA_FLAG},
712f90b865SAlexander Duyck };
722f90b865SAlexander Duyck 
732f90b865SAlexander Duyck /* DCB priority grouping nested attributes */
74b54452b0SAlexey Dobriyan static const struct nla_policy dcbnl_pg_nest[DCB_PG_ATTR_MAX + 1] = {
752f90b865SAlexander Duyck 	[DCB_PG_ATTR_TC_0]      = {.type = NLA_NESTED},
762f90b865SAlexander Duyck 	[DCB_PG_ATTR_TC_1]      = {.type = NLA_NESTED},
772f90b865SAlexander Duyck 	[DCB_PG_ATTR_TC_2]      = {.type = NLA_NESTED},
782f90b865SAlexander Duyck 	[DCB_PG_ATTR_TC_3]      = {.type = NLA_NESTED},
792f90b865SAlexander Duyck 	[DCB_PG_ATTR_TC_4]      = {.type = NLA_NESTED},
802f90b865SAlexander Duyck 	[DCB_PG_ATTR_TC_5]      = {.type = NLA_NESTED},
812f90b865SAlexander Duyck 	[DCB_PG_ATTR_TC_6]      = {.type = NLA_NESTED},
822f90b865SAlexander Duyck 	[DCB_PG_ATTR_TC_7]      = {.type = NLA_NESTED},
832f90b865SAlexander Duyck 	[DCB_PG_ATTR_TC_ALL]    = {.type = NLA_NESTED},
842f90b865SAlexander Duyck 	[DCB_PG_ATTR_BW_ID_0]   = {.type = NLA_U8},
852f90b865SAlexander Duyck 	[DCB_PG_ATTR_BW_ID_1]   = {.type = NLA_U8},
862f90b865SAlexander Duyck 	[DCB_PG_ATTR_BW_ID_2]   = {.type = NLA_U8},
872f90b865SAlexander Duyck 	[DCB_PG_ATTR_BW_ID_3]   = {.type = NLA_U8},
882f90b865SAlexander Duyck 	[DCB_PG_ATTR_BW_ID_4]   = {.type = NLA_U8},
892f90b865SAlexander Duyck 	[DCB_PG_ATTR_BW_ID_5]   = {.type = NLA_U8},
902f90b865SAlexander Duyck 	[DCB_PG_ATTR_BW_ID_6]   = {.type = NLA_U8},
912f90b865SAlexander Duyck 	[DCB_PG_ATTR_BW_ID_7]   = {.type = NLA_U8},
922f90b865SAlexander Duyck 	[DCB_PG_ATTR_BW_ID_ALL] = {.type = NLA_FLAG},
932f90b865SAlexander Duyck };
942f90b865SAlexander Duyck 
952f90b865SAlexander Duyck /* DCB traffic class nested attributes. */
96b54452b0SAlexey Dobriyan static const struct nla_policy dcbnl_tc_param_nest[DCB_TC_ATTR_PARAM_MAX + 1] = {
972f90b865SAlexander Duyck 	[DCB_TC_ATTR_PARAM_PGID]            = {.type = NLA_U8},
982f90b865SAlexander Duyck 	[DCB_TC_ATTR_PARAM_UP_MAPPING]      = {.type = NLA_U8},
992f90b865SAlexander Duyck 	[DCB_TC_ATTR_PARAM_STRICT_PRIO]     = {.type = NLA_U8},
1002f90b865SAlexander Duyck 	[DCB_TC_ATTR_PARAM_BW_PCT]          = {.type = NLA_U8},
1012f90b865SAlexander Duyck 	[DCB_TC_ATTR_PARAM_ALL]             = {.type = NLA_FLAG},
1022f90b865SAlexander Duyck };
1032f90b865SAlexander Duyck 
10446132188SAlexander Duyck /* DCB capabilities nested attributes. */
105b54452b0SAlexey Dobriyan static const struct nla_policy dcbnl_cap_nest[DCB_CAP_ATTR_MAX + 1] = {
10646132188SAlexander Duyck 	[DCB_CAP_ATTR_ALL]     = {.type = NLA_FLAG},
10746132188SAlexander Duyck 	[DCB_CAP_ATTR_PG]      = {.type = NLA_U8},
10846132188SAlexander Duyck 	[DCB_CAP_ATTR_PFC]     = {.type = NLA_U8},
10946132188SAlexander Duyck 	[DCB_CAP_ATTR_UP2TC]   = {.type = NLA_U8},
11046132188SAlexander Duyck 	[DCB_CAP_ATTR_PG_TCS]  = {.type = NLA_U8},
11146132188SAlexander Duyck 	[DCB_CAP_ATTR_PFC_TCS] = {.type = NLA_U8},
11246132188SAlexander Duyck 	[DCB_CAP_ATTR_GSP]     = {.type = NLA_U8},
11346132188SAlexander Duyck 	[DCB_CAP_ATTR_BCN]     = {.type = NLA_U8},
1146241b625SShmulik Ravid 	[DCB_CAP_ATTR_DCBX]    = {.type = NLA_U8},
11546132188SAlexander Duyck };
1162f90b865SAlexander Duyck 
11733dbabc4SAlexander Duyck /* DCB capabilities nested attributes. */
118b54452b0SAlexey Dobriyan static const struct nla_policy dcbnl_numtcs_nest[DCB_NUMTCS_ATTR_MAX + 1] = {
11933dbabc4SAlexander Duyck 	[DCB_NUMTCS_ATTR_ALL]     = {.type = NLA_FLAG},
12033dbabc4SAlexander Duyck 	[DCB_NUMTCS_ATTR_PG]      = {.type = NLA_U8},
12133dbabc4SAlexander Duyck 	[DCB_NUMTCS_ATTR_PFC]     = {.type = NLA_U8},
12233dbabc4SAlexander Duyck };
12333dbabc4SAlexander Duyck 
124859ee3c4SAlexander Duyck /* DCB BCN nested attributes. */
125b54452b0SAlexey Dobriyan static const struct nla_policy dcbnl_bcn_nest[DCB_BCN_ATTR_MAX + 1] = {
126859ee3c4SAlexander Duyck 	[DCB_BCN_ATTR_RP_0]         = {.type = NLA_U8},
127859ee3c4SAlexander Duyck 	[DCB_BCN_ATTR_RP_1]         = {.type = NLA_U8},
128859ee3c4SAlexander Duyck 	[DCB_BCN_ATTR_RP_2]         = {.type = NLA_U8},
129859ee3c4SAlexander Duyck 	[DCB_BCN_ATTR_RP_3]         = {.type = NLA_U8},
130859ee3c4SAlexander Duyck 	[DCB_BCN_ATTR_RP_4]         = {.type = NLA_U8},
131859ee3c4SAlexander Duyck 	[DCB_BCN_ATTR_RP_5]         = {.type = NLA_U8},
132859ee3c4SAlexander Duyck 	[DCB_BCN_ATTR_RP_6]         = {.type = NLA_U8},
133859ee3c4SAlexander Duyck 	[DCB_BCN_ATTR_RP_7]         = {.type = NLA_U8},
134859ee3c4SAlexander Duyck 	[DCB_BCN_ATTR_RP_ALL]       = {.type = NLA_FLAG},
135f4314e81SDon Skidmore 	[DCB_BCN_ATTR_BCNA_0]       = {.type = NLA_U32},
136f4314e81SDon Skidmore 	[DCB_BCN_ATTR_BCNA_1]       = {.type = NLA_U32},
137859ee3c4SAlexander Duyck 	[DCB_BCN_ATTR_ALPHA]        = {.type = NLA_U32},
138859ee3c4SAlexander Duyck 	[DCB_BCN_ATTR_BETA]         = {.type = NLA_U32},
139859ee3c4SAlexander Duyck 	[DCB_BCN_ATTR_GD]           = {.type = NLA_U32},
140859ee3c4SAlexander Duyck 	[DCB_BCN_ATTR_GI]           = {.type = NLA_U32},
141859ee3c4SAlexander Duyck 	[DCB_BCN_ATTR_TMAX]         = {.type = NLA_U32},
142859ee3c4SAlexander Duyck 	[DCB_BCN_ATTR_TD]           = {.type = NLA_U32},
143859ee3c4SAlexander Duyck 	[DCB_BCN_ATTR_RMIN]         = {.type = NLA_U32},
144859ee3c4SAlexander Duyck 	[DCB_BCN_ATTR_W]            = {.type = NLA_U32},
145859ee3c4SAlexander Duyck 	[DCB_BCN_ATTR_RD]           = {.type = NLA_U32},
146859ee3c4SAlexander Duyck 	[DCB_BCN_ATTR_RU]           = {.type = NLA_U32},
147859ee3c4SAlexander Duyck 	[DCB_BCN_ATTR_WRTT]         = {.type = NLA_U32},
148859ee3c4SAlexander Duyck 	[DCB_BCN_ATTR_RI]           = {.type = NLA_U32},
149859ee3c4SAlexander Duyck 	[DCB_BCN_ATTR_C]            = {.type = NLA_U32},
150859ee3c4SAlexander Duyck 	[DCB_BCN_ATTR_ALL]          = {.type = NLA_FLAG},
151859ee3c4SAlexander Duyck };
152859ee3c4SAlexander Duyck 
1536fa382afSYi Zou /* DCB APP nested attributes. */
154b54452b0SAlexey Dobriyan static const struct nla_policy dcbnl_app_nest[DCB_APP_ATTR_MAX + 1] = {
1556fa382afSYi Zou 	[DCB_APP_ATTR_IDTYPE]       = {.type = NLA_U8},
1566fa382afSYi Zou 	[DCB_APP_ATTR_ID]           = {.type = NLA_U16},
1576fa382afSYi Zou 	[DCB_APP_ATTR_PRIORITY]     = {.type = NLA_U8},
1586fa382afSYi Zou };
1596fa382afSYi Zou 
1603e29027aSJohn Fastabend /* IEEE 802.1Qaz nested attributes. */
1613e29027aSJohn Fastabend static const struct nla_policy dcbnl_ieee_policy[DCB_ATTR_IEEE_MAX + 1] = {
1623e29027aSJohn Fastabend 	[DCB_ATTR_IEEE_ETS]	    = {.len = sizeof(struct ieee_ets)},
1633e29027aSJohn Fastabend 	[DCB_ATTR_IEEE_PFC]	    = {.len = sizeof(struct ieee_pfc)},
1643e29027aSJohn Fastabend 	[DCB_ATTR_IEEE_APP_TABLE]   = {.type = NLA_NESTED},
16508f10affSAmir Vadai 	[DCB_ATTR_IEEE_MAXRATE]   = {.len = sizeof(struct ieee_maxrate)},
166c9368247SShani Michaeli 	[DCB_ATTR_IEEE_QCN]         = {.len = sizeof(struct ieee_qcn)},
167c9368247SShani Michaeli 	[DCB_ATTR_IEEE_QCN_STATS]   = {.len = sizeof(struct ieee_qcn_stats)},
168e549f6f9SHuy Nguyen 	[DCB_ATTR_DCB_BUFFER]       = {.len = sizeof(struct dcbnl_buffer)},
1696182d587SDaniel Machon 	[DCB_ATTR_DCB_APP_TRUST_TABLE] = {.type = NLA_NESTED},
1703e29027aSJohn Fastabend };
1713e29027aSJohn Fastabend 
172ea45fe4eSShmulik Ravid /* DCB number of traffic classes nested attributes. */
173ea45fe4eSShmulik Ravid static const struct nla_policy dcbnl_featcfg_nest[DCB_FEATCFG_ATTR_MAX + 1] = {
174ea45fe4eSShmulik Ravid 	[DCB_FEATCFG_ATTR_ALL]      = {.type = NLA_FLAG},
175ea45fe4eSShmulik Ravid 	[DCB_FEATCFG_ATTR_PG]       = {.type = NLA_U8},
176ea45fe4eSShmulik Ravid 	[DCB_FEATCFG_ATTR_PFC]      = {.type = NLA_U8},
177ea45fe4eSShmulik Ravid 	[DCB_FEATCFG_ATTR_APP]      = {.type = NLA_U8},
178ea45fe4eSShmulik Ravid };
179ea45fe4eSShmulik Ravid 
1809ab933abSJohn Fastabend static LIST_HEAD(dcb_app_list);
181622f1b2fSDaniel Machon static LIST_HEAD(dcb_rewr_list);
1829ab933abSJohn Fastabend static DEFINE_SPINLOCK(dcb_lock);
1839ab933abSJohn Fastabend 
dcbnl_app_attr_type_get(u8 selector)184ec32c0c4SDaniel Machon static enum ieee_attrs_app dcbnl_app_attr_type_get(u8 selector)
185ec32c0c4SDaniel Machon {
186ec32c0c4SDaniel Machon 	switch (selector) {
187ec32c0c4SDaniel Machon 	case IEEE_8021QAZ_APP_SEL_ETHERTYPE:
188ec32c0c4SDaniel Machon 	case IEEE_8021QAZ_APP_SEL_STREAM:
189ec32c0c4SDaniel Machon 	case IEEE_8021QAZ_APP_SEL_DGRAM:
190ec32c0c4SDaniel Machon 	case IEEE_8021QAZ_APP_SEL_ANY:
191ec32c0c4SDaniel Machon 	case IEEE_8021QAZ_APP_SEL_DSCP:
192ec32c0c4SDaniel Machon 		return DCB_ATTR_IEEE_APP;
193ec32c0c4SDaniel Machon 	case DCB_APP_SEL_PCP:
194ec32c0c4SDaniel Machon 		return DCB_ATTR_DCB_APP;
195ec32c0c4SDaniel Machon 	default:
196ec32c0c4SDaniel Machon 		return DCB_ATTR_IEEE_APP_UNSPEC;
197ec32c0c4SDaniel Machon 	}
198ec32c0c4SDaniel Machon }
199ec32c0c4SDaniel Machon 
dcbnl_app_attr_type_validate(enum ieee_attrs_app type)200ec32c0c4SDaniel Machon static bool dcbnl_app_attr_type_validate(enum ieee_attrs_app type)
201ec32c0c4SDaniel Machon {
202ec32c0c4SDaniel Machon 	switch (type) {
203ec32c0c4SDaniel Machon 	case DCB_ATTR_IEEE_APP:
204ec32c0c4SDaniel Machon 	case DCB_ATTR_DCB_APP:
205ec32c0c4SDaniel Machon 		return true;
206ec32c0c4SDaniel Machon 	default:
207ec32c0c4SDaniel Machon 		return false;
208ec32c0c4SDaniel Machon 	}
209ec32c0c4SDaniel Machon }
210ec32c0c4SDaniel Machon 
dcbnl_app_selector_validate(enum ieee_attrs_app type,u8 selector)211ec32c0c4SDaniel Machon static bool dcbnl_app_selector_validate(enum ieee_attrs_app type, u8 selector)
212ec32c0c4SDaniel Machon {
213ec32c0c4SDaniel Machon 	return dcbnl_app_attr_type_get(selector) == type;
214ec32c0c4SDaniel Machon }
215ec32c0c4SDaniel Machon 
dcbnl_newmsg(int type,u8 cmd,u32 port,u32 seq,u32 flags,struct nlmsghdr ** nlhp)21633a03aadSThomas Graf static struct sk_buff *dcbnl_newmsg(int type, u8 cmd, u32 port, u32 seq,
21733a03aadSThomas Graf 				    u32 flags, struct nlmsghdr **nlhp)
21833a03aadSThomas Graf {
21933a03aadSThomas Graf 	struct sk_buff *skb;
22033a03aadSThomas Graf 	struct dcbmsg *dcb;
22133a03aadSThomas Graf 	struct nlmsghdr *nlh;
22233a03aadSThomas Graf 
22333a03aadSThomas Graf 	skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
22433a03aadSThomas Graf 	if (!skb)
22533a03aadSThomas Graf 		return NULL;
22633a03aadSThomas Graf 
22733a03aadSThomas Graf 	nlh = nlmsg_put(skb, port, seq, type, sizeof(*dcb), flags);
228b3908e22SThomas Graf 	BUG_ON(!nlh);
22933a03aadSThomas Graf 
23033a03aadSThomas Graf 	dcb = nlmsg_data(nlh);
23133a03aadSThomas Graf 	dcb->dcb_family = AF_UNSPEC;
23233a03aadSThomas Graf 	dcb->cmd = cmd;
23333a03aadSThomas Graf 	dcb->dcb_pad = 0;
23433a03aadSThomas Graf 
23533a03aadSThomas Graf 	if (nlhp)
23633a03aadSThomas Graf 		*nlhp = nlh;
23733a03aadSThomas Graf 
23833a03aadSThomas Graf 	return skb;
23933a03aadSThomas Graf }
24033a03aadSThomas Graf 
dcbnl_getstate(struct net_device * netdev,struct nlmsghdr * nlh,u32 seq,struct nlattr ** tb,struct sk_buff * skb)2417be99413SThomas Graf static int dcbnl_getstate(struct net_device *netdev, struct nlmsghdr *nlh,
2427be99413SThomas Graf 			  u32 seq, struct nlattr **tb, struct sk_buff *skb)
2432f90b865SAlexander Duyck {
2442f90b865SAlexander Duyck 	/* if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->getstate) */
2452f90b865SAlexander Duyck 	if (!netdev->dcbnl_ops->getstate)
2463d1f4869SThomas Graf 		return -EOPNOTSUPP;
2472f90b865SAlexander Duyck 
2487be99413SThomas Graf 	return nla_put_u8(skb, DCB_ATTR_STATE,
2497be99413SThomas Graf 			  netdev->dcbnl_ops->getstate(netdev));
2502f90b865SAlexander Duyck }
2512f90b865SAlexander Duyck 
dcbnl_getpfccfg(struct net_device * netdev,struct nlmsghdr * nlh,u32 seq,struct nlattr ** tb,struct sk_buff * skb)2527be99413SThomas Graf static int dcbnl_getpfccfg(struct net_device *netdev, struct nlmsghdr *nlh,
2537be99413SThomas Graf 			   u32 seq, struct nlattr **tb, struct sk_buff *skb)
2542f90b865SAlexander Duyck {
2552f90b865SAlexander Duyck 	struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1], *nest;
2562f90b865SAlexander Duyck 	u8 value;
2573d1f4869SThomas Graf 	int ret;
2582f90b865SAlexander Duyck 	int i;
2592f90b865SAlexander Duyck 	int getall = 0;
2602f90b865SAlexander Duyck 
2613d1f4869SThomas Graf 	if (!tb[DCB_ATTR_PFC_CFG])
2623d1f4869SThomas Graf 		return -EINVAL;
2633d1f4869SThomas Graf 
2643d1f4869SThomas Graf 	if (!netdev->dcbnl_ops->getpfccfg)
2653d1f4869SThomas Graf 		return -EOPNOTSUPP;
2662f90b865SAlexander Duyck 
2678cb08174SJohannes Berg 	ret = nla_parse_nested_deprecated(data, DCB_PFC_UP_ATTR_MAX,
2688cb08174SJohannes Berg 					  tb[DCB_ATTR_PFC_CFG],
2698cb08174SJohannes Berg 					  dcbnl_pfc_up_nest, NULL);
2702f90b865SAlexander Duyck 	if (ret)
2713d1f4869SThomas Graf 		return ret;
2722f90b865SAlexander Duyck 
273ae0be8deSMichal Kubecek 	nest = nla_nest_start_noflag(skb, DCB_ATTR_PFC_CFG);
2742f90b865SAlexander Duyck 	if (!nest)
2753d1f4869SThomas Graf 		return -EMSGSIZE;
2762f90b865SAlexander Duyck 
2772f90b865SAlexander Duyck 	if (data[DCB_PFC_UP_ATTR_ALL])
2782f90b865SAlexander Duyck 		getall = 1;
2792f90b865SAlexander Duyck 
2802f90b865SAlexander Duyck 	for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) {
2812f90b865SAlexander Duyck 		if (!getall && !data[i])
2822f90b865SAlexander Duyck 			continue;
2832f90b865SAlexander Duyck 
2842f90b865SAlexander Duyck 		netdev->dcbnl_ops->getpfccfg(netdev, i - DCB_PFC_UP_ATTR_0,
2852f90b865SAlexander Duyck 		                             &value);
2867be99413SThomas Graf 		ret = nla_put_u8(skb, i, value);
2872f90b865SAlexander Duyck 		if (ret) {
2887be99413SThomas Graf 			nla_nest_cancel(skb, nest);
2893d1f4869SThomas Graf 			return ret;
2902f90b865SAlexander Duyck 		}
2912f90b865SAlexander Duyck 	}
2927be99413SThomas Graf 	nla_nest_end(skb, nest);
2932f90b865SAlexander Duyck 
2942f90b865SAlexander Duyck 	return 0;
2952f90b865SAlexander Duyck }
2962f90b865SAlexander Duyck 
dcbnl_getperm_hwaddr(struct net_device * netdev,struct nlmsghdr * nlh,u32 seq,struct nlattr ** tb,struct sk_buff * skb)2977be99413SThomas Graf static int dcbnl_getperm_hwaddr(struct net_device *netdev, struct nlmsghdr *nlh,
2987be99413SThomas Graf 				u32 seq, struct nlattr **tb, struct sk_buff *skb)
2992f90b865SAlexander Duyck {
3002f90b865SAlexander Duyck 	u8 perm_addr[MAX_ADDR_LEN];
3012f90b865SAlexander Duyck 
3022f90b865SAlexander Duyck 	if (!netdev->dcbnl_ops->getpermhwaddr)
3033d1f4869SThomas Graf 		return -EOPNOTSUPP;
3042f90b865SAlexander Duyck 
30529cd8ae0SMathias Krause 	memset(perm_addr, 0, sizeof(perm_addr));
3062f90b865SAlexander Duyck 	netdev->dcbnl_ops->getpermhwaddr(netdev, perm_addr);
3072f90b865SAlexander Duyck 
3087be99413SThomas Graf 	return nla_put(skb, DCB_ATTR_PERM_HWADDR, sizeof(perm_addr), perm_addr);
3092f90b865SAlexander Duyck }
3102f90b865SAlexander Duyck 
dcbnl_getcap(struct net_device * netdev,struct nlmsghdr * nlh,u32 seq,struct nlattr ** tb,struct sk_buff * skb)3117be99413SThomas Graf static int dcbnl_getcap(struct net_device *netdev, struct nlmsghdr *nlh,
3127be99413SThomas Graf 			u32 seq, struct nlattr **tb, struct sk_buff *skb)
31346132188SAlexander Duyck {
31446132188SAlexander Duyck 	struct nlattr *data[DCB_CAP_ATTR_MAX + 1], *nest;
31546132188SAlexander Duyck 	u8 value;
3163d1f4869SThomas Graf 	int ret;
31746132188SAlexander Duyck 	int i;
31846132188SAlexander Duyck 	int getall = 0;
31946132188SAlexander Duyck 
3203d1f4869SThomas Graf 	if (!tb[DCB_ATTR_CAP])
3213d1f4869SThomas Graf 		return -EINVAL;
3223d1f4869SThomas Graf 
3233d1f4869SThomas Graf 	if (!netdev->dcbnl_ops->getcap)
3243d1f4869SThomas Graf 		return -EOPNOTSUPP;
32546132188SAlexander Duyck 
3268cb08174SJohannes Berg 	ret = nla_parse_nested_deprecated(data, DCB_CAP_ATTR_MAX,
3278cb08174SJohannes Berg 					  tb[DCB_ATTR_CAP], dcbnl_cap_nest,
3288cb08174SJohannes Berg 					  NULL);
32946132188SAlexander Duyck 	if (ret)
3303d1f4869SThomas Graf 		return ret;
33146132188SAlexander Duyck 
332ae0be8deSMichal Kubecek 	nest = nla_nest_start_noflag(skb, DCB_ATTR_CAP);
33346132188SAlexander Duyck 	if (!nest)
3343d1f4869SThomas Graf 		return -EMSGSIZE;
33546132188SAlexander Duyck 
33646132188SAlexander Duyck 	if (data[DCB_CAP_ATTR_ALL])
33746132188SAlexander Duyck 		getall = 1;
33846132188SAlexander Duyck 
33946132188SAlexander Duyck 	for (i = DCB_CAP_ATTR_ALL+1; i <= DCB_CAP_ATTR_MAX; i++) {
34046132188SAlexander Duyck 		if (!getall && !data[i])
34146132188SAlexander Duyck 			continue;
34246132188SAlexander Duyck 
34346132188SAlexander Duyck 		if (!netdev->dcbnl_ops->getcap(netdev, i, &value)) {
3447be99413SThomas Graf 			ret = nla_put_u8(skb, i, value);
34546132188SAlexander Duyck 			if (ret) {
3467be99413SThomas Graf 				nla_nest_cancel(skb, nest);
3473d1f4869SThomas Graf 				return ret;
3487be99413SThomas Graf 			}
3497be99413SThomas Graf 		}
3507be99413SThomas Graf 	}
3517be99413SThomas Graf 	nla_nest_end(skb, nest);
35246132188SAlexander Duyck 
35346132188SAlexander Duyck 	return 0;
35446132188SAlexander Duyck }
35546132188SAlexander Duyck 
dcbnl_getnumtcs(struct net_device * netdev,struct nlmsghdr * nlh,u32 seq,struct nlattr ** tb,struct sk_buff * skb)3567be99413SThomas Graf static int dcbnl_getnumtcs(struct net_device *netdev, struct nlmsghdr *nlh,
3577be99413SThomas Graf 			   u32 seq, struct nlattr **tb, struct sk_buff *skb)
35833dbabc4SAlexander Duyck {
35933dbabc4SAlexander Duyck 	struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1], *nest;
36033dbabc4SAlexander Duyck 	u8 value;
3613d1f4869SThomas Graf 	int ret;
36233dbabc4SAlexander Duyck 	int i;
36333dbabc4SAlexander Duyck 	int getall = 0;
36433dbabc4SAlexander Duyck 
3653d1f4869SThomas Graf 	if (!tb[DCB_ATTR_NUMTCS])
3663d1f4869SThomas Graf 		return -EINVAL;
3673d1f4869SThomas Graf 
3683d1f4869SThomas Graf 	if (!netdev->dcbnl_ops->getnumtcs)
3693d1f4869SThomas Graf 		return -EOPNOTSUPP;
37033dbabc4SAlexander Duyck 
3718cb08174SJohannes Berg 	ret = nla_parse_nested_deprecated(data, DCB_NUMTCS_ATTR_MAX,
3728cb08174SJohannes Berg 					  tb[DCB_ATTR_NUMTCS],
373fceb6435SJohannes Berg 					  dcbnl_numtcs_nest, NULL);
3743d1f4869SThomas Graf 	if (ret)
3753d1f4869SThomas Graf 		return ret;
37633dbabc4SAlexander Duyck 
377ae0be8deSMichal Kubecek 	nest = nla_nest_start_noflag(skb, DCB_ATTR_NUMTCS);
3783d1f4869SThomas Graf 	if (!nest)
3793d1f4869SThomas Graf 		return -EMSGSIZE;
38033dbabc4SAlexander Duyck 
38133dbabc4SAlexander Duyck 	if (data[DCB_NUMTCS_ATTR_ALL])
38233dbabc4SAlexander Duyck 		getall = 1;
38333dbabc4SAlexander Duyck 
38433dbabc4SAlexander Duyck 	for (i = DCB_NUMTCS_ATTR_ALL+1; i <= DCB_NUMTCS_ATTR_MAX; i++) {
38533dbabc4SAlexander Duyck 		if (!getall && !data[i])
38633dbabc4SAlexander Duyck 			continue;
38733dbabc4SAlexander Duyck 
38833dbabc4SAlexander Duyck 		ret = netdev->dcbnl_ops->getnumtcs(netdev, i, &value);
38933dbabc4SAlexander Duyck 		if (!ret) {
3907be99413SThomas Graf 			ret = nla_put_u8(skb, i, value);
39133dbabc4SAlexander Duyck 			if (ret) {
3927be99413SThomas Graf 				nla_nest_cancel(skb, nest);
3933d1f4869SThomas Graf 				return ret;
39433dbabc4SAlexander Duyck 			}
3953d1f4869SThomas Graf 		} else
3963d1f4869SThomas Graf 			return -EINVAL;
3977be99413SThomas Graf 	}
3987be99413SThomas Graf 	nla_nest_end(skb, nest);
39933dbabc4SAlexander Duyck 
40033dbabc4SAlexander Duyck 	return 0;
40133dbabc4SAlexander Duyck }
40233dbabc4SAlexander Duyck 
dcbnl_setnumtcs(struct net_device * netdev,struct nlmsghdr * nlh,u32 seq,struct nlattr ** tb,struct sk_buff * skb)4037be99413SThomas Graf static int dcbnl_setnumtcs(struct net_device *netdev, struct nlmsghdr *nlh,
4047be99413SThomas Graf 			   u32 seq, struct nlattr **tb, struct sk_buff *skb)
40533dbabc4SAlexander Duyck {
40633dbabc4SAlexander Duyck 	struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1];
4073d1f4869SThomas Graf 	int ret;
40833dbabc4SAlexander Duyck 	u8 value;
40933dbabc4SAlexander Duyck 	int i;
41033dbabc4SAlexander Duyck 
4113d1f4869SThomas Graf 	if (!tb[DCB_ATTR_NUMTCS])
4123d1f4869SThomas Graf 		return -EINVAL;
4133d1f4869SThomas Graf 
4143d1f4869SThomas Graf 	if (!netdev->dcbnl_ops->setnumtcs)
4153d1f4869SThomas Graf 		return -EOPNOTSUPP;
41633dbabc4SAlexander Duyck 
4178cb08174SJohannes Berg 	ret = nla_parse_nested_deprecated(data, DCB_NUMTCS_ATTR_MAX,
4188cb08174SJohannes Berg 					  tb[DCB_ATTR_NUMTCS],
419fceb6435SJohannes Berg 					  dcbnl_numtcs_nest, NULL);
4207be99413SThomas Graf 	if (ret)
4213d1f4869SThomas Graf 		return ret;
42233dbabc4SAlexander Duyck 
42333dbabc4SAlexander Duyck 	for (i = DCB_NUMTCS_ATTR_ALL+1; i <= DCB_NUMTCS_ATTR_MAX; i++) {
42433dbabc4SAlexander Duyck 		if (data[i] == NULL)
42533dbabc4SAlexander Duyck 			continue;
42633dbabc4SAlexander Duyck 
42733dbabc4SAlexander Duyck 		value = nla_get_u8(data[i]);
42833dbabc4SAlexander Duyck 
42933dbabc4SAlexander Duyck 		ret = netdev->dcbnl_ops->setnumtcs(netdev, i, value);
43033dbabc4SAlexander Duyck 		if (ret)
4317be99413SThomas Graf 			break;
43233dbabc4SAlexander Duyck 	}
43333dbabc4SAlexander Duyck 
4347be99413SThomas Graf 	return nla_put_u8(skb, DCB_ATTR_NUMTCS, !!ret);
43533dbabc4SAlexander Duyck }
43633dbabc4SAlexander Duyck 
dcbnl_getpfcstate(struct net_device * netdev,struct nlmsghdr * nlh,u32 seq,struct nlattr ** tb,struct sk_buff * skb)4377be99413SThomas Graf static int dcbnl_getpfcstate(struct net_device *netdev, struct nlmsghdr *nlh,
4387be99413SThomas Graf 			     u32 seq, struct nlattr **tb, struct sk_buff *skb)
4390eb3aa9bSAlexander Duyck {
4400eb3aa9bSAlexander Duyck 	if (!netdev->dcbnl_ops->getpfcstate)
4413d1f4869SThomas Graf 		return -EOPNOTSUPP;
4420eb3aa9bSAlexander Duyck 
4437be99413SThomas Graf 	return nla_put_u8(skb, DCB_ATTR_PFC_STATE,
4447be99413SThomas Graf 			  netdev->dcbnl_ops->getpfcstate(netdev));
4450eb3aa9bSAlexander Duyck }
4460eb3aa9bSAlexander Duyck 
dcbnl_setpfcstate(struct net_device * netdev,struct nlmsghdr * nlh,u32 seq,struct nlattr ** tb,struct sk_buff * skb)4477be99413SThomas Graf static int dcbnl_setpfcstate(struct net_device *netdev, struct nlmsghdr *nlh,
4487be99413SThomas Graf 			     u32 seq, struct nlattr **tb, struct sk_buff *skb)
4490eb3aa9bSAlexander Duyck {
4500eb3aa9bSAlexander Duyck 	u8 value;
4510eb3aa9bSAlexander Duyck 
4523d1f4869SThomas Graf 	if (!tb[DCB_ATTR_PFC_STATE])
4537be99413SThomas Graf 		return -EINVAL;
4540eb3aa9bSAlexander Duyck 
4553d1f4869SThomas Graf 	if (!netdev->dcbnl_ops->setpfcstate)
4563d1f4869SThomas Graf 		return -EOPNOTSUPP;
4573d1f4869SThomas Graf 
4580eb3aa9bSAlexander Duyck 	value = nla_get_u8(tb[DCB_ATTR_PFC_STATE]);
4590eb3aa9bSAlexander Duyck 
4600eb3aa9bSAlexander Duyck 	netdev->dcbnl_ops->setpfcstate(netdev, value);
4610eb3aa9bSAlexander Duyck 
4627be99413SThomas Graf 	return nla_put_u8(skb, DCB_ATTR_PFC_STATE, 0);
4630eb3aa9bSAlexander Duyck }
4640eb3aa9bSAlexander Duyck 
dcbnl_getapp(struct net_device * netdev,struct nlmsghdr * nlh,u32 seq,struct nlattr ** tb,struct sk_buff * skb)4657be99413SThomas Graf static int dcbnl_getapp(struct net_device *netdev, struct nlmsghdr *nlh,
4667be99413SThomas Graf 			u32 seq, struct nlattr **tb, struct sk_buff *skb)
46757949686SYi Zou {
46857949686SYi Zou 	struct nlattr *app_nest;
46957949686SYi Zou 	struct nlattr *app_tb[DCB_APP_ATTR_MAX + 1];
47057949686SYi Zou 	u16 id;
47157949686SYi Zou 	u8 up, idtype;
4723d1f4869SThomas Graf 	int ret;
47357949686SYi Zou 
4743dce38a0SJohn Fastabend 	if (!tb[DCB_ATTR_APP])
4753d1f4869SThomas Graf 		return -EINVAL;
47657949686SYi Zou 
4778cb08174SJohannes Berg 	ret = nla_parse_nested_deprecated(app_tb, DCB_APP_ATTR_MAX,
4788cb08174SJohannes Berg 					  tb[DCB_ATTR_APP], dcbnl_app_nest,
4798cb08174SJohannes Berg 					  NULL);
48057949686SYi Zou 	if (ret)
4813d1f4869SThomas Graf 		return ret;
48257949686SYi Zou 
48357949686SYi Zou 	/* all must be non-null */
48457949686SYi Zou 	if ((!app_tb[DCB_APP_ATTR_IDTYPE]) ||
48557949686SYi Zou 	    (!app_tb[DCB_APP_ATTR_ID]))
4863d1f4869SThomas Graf 		return -EINVAL;
48757949686SYi Zou 
48857949686SYi Zou 	/* either by eth type or by socket number */
48957949686SYi Zou 	idtype = nla_get_u8(app_tb[DCB_APP_ATTR_IDTYPE]);
49057949686SYi Zou 	if ((idtype != DCB_APP_IDTYPE_ETHTYPE) &&
49157949686SYi Zou 	    (idtype != DCB_APP_IDTYPE_PORTNUM))
4923d1f4869SThomas Graf 		return -EINVAL;
49357949686SYi Zou 
49457949686SYi Zou 	id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]);
4953dce38a0SJohn Fastabend 
4963dce38a0SJohn Fastabend 	if (netdev->dcbnl_ops->getapp) {
497c2659479SAnish Bhatt 		ret = netdev->dcbnl_ops->getapp(netdev, idtype, id);
498c2659479SAnish Bhatt 		if (ret < 0)
499c2659479SAnish Bhatt 			return ret;
500c2659479SAnish Bhatt 		else
501c2659479SAnish Bhatt 			up = ret;
5023dce38a0SJohn Fastabend 	} else {
5033dce38a0SJohn Fastabend 		struct dcb_app app = {
5043dce38a0SJohn Fastabend 					.selector = idtype,
5053dce38a0SJohn Fastabend 					.protocol = id,
5063dce38a0SJohn Fastabend 				     };
5073dce38a0SJohn Fastabend 		up = dcb_getapp(netdev, &app);
5083dce38a0SJohn Fastabend 	}
50957949686SYi Zou 
510ae0be8deSMichal Kubecek 	app_nest = nla_nest_start_noflag(skb, DCB_ATTR_APP);
5117be99413SThomas Graf 	if (!app_nest)
5123d1f4869SThomas Graf 		return -EMSGSIZE;
51357949686SYi Zou 
5147be99413SThomas Graf 	ret = nla_put_u8(skb, DCB_APP_ATTR_IDTYPE, idtype);
51557949686SYi Zou 	if (ret)
51657949686SYi Zou 		goto out_cancel;
51757949686SYi Zou 
5187be99413SThomas Graf 	ret = nla_put_u16(skb, DCB_APP_ATTR_ID, id);
51957949686SYi Zou 	if (ret)
52057949686SYi Zou 		goto out_cancel;
52157949686SYi Zou 
5227be99413SThomas Graf 	ret = nla_put_u8(skb, DCB_APP_ATTR_PRIORITY, up);
52357949686SYi Zou 	if (ret)
52457949686SYi Zou 		goto out_cancel;
52557949686SYi Zou 
5267be99413SThomas Graf 	nla_nest_end(skb, app_nest);
52757949686SYi Zou 
5283d1f4869SThomas Graf 	return 0;
52957949686SYi Zou 
53057949686SYi Zou out_cancel:
5317be99413SThomas Graf 	nla_nest_cancel(skb, app_nest);
53257949686SYi Zou 	return ret;
53357949686SYi Zou }
53457949686SYi Zou 
dcbnl_setapp(struct net_device * netdev,struct nlmsghdr * nlh,u32 seq,struct nlattr ** tb,struct sk_buff * skb)5357be99413SThomas Graf static int dcbnl_setapp(struct net_device *netdev, struct nlmsghdr *nlh,
5367be99413SThomas Graf 			u32 seq, struct nlattr **tb, struct sk_buff *skb)
53757949686SYi Zou {
5383d1f4869SThomas Graf 	int ret;
53957949686SYi Zou 	u16 id;
54057949686SYi Zou 	u8 up, idtype;
54157949686SYi Zou 	struct nlattr *app_tb[DCB_APP_ATTR_MAX + 1];
54257949686SYi Zou 
5439ab933abSJohn Fastabend 	if (!tb[DCB_ATTR_APP])
5443d1f4869SThomas Graf 		return -EINVAL;
54557949686SYi Zou 
5468cb08174SJohannes Berg 	ret = nla_parse_nested_deprecated(app_tb, DCB_APP_ATTR_MAX,
5478cb08174SJohannes Berg 					  tb[DCB_ATTR_APP], dcbnl_app_nest,
5488cb08174SJohannes Berg 					  NULL);
54957949686SYi Zou 	if (ret)
5503d1f4869SThomas Graf 		return ret;
55157949686SYi Zou 
55257949686SYi Zou 	/* all must be non-null */
55357949686SYi Zou 	if ((!app_tb[DCB_APP_ATTR_IDTYPE]) ||
55457949686SYi Zou 	    (!app_tb[DCB_APP_ATTR_ID]) ||
55557949686SYi Zou 	    (!app_tb[DCB_APP_ATTR_PRIORITY]))
5563d1f4869SThomas Graf 		return -EINVAL;
55757949686SYi Zou 
55857949686SYi Zou 	/* either by eth type or by socket number */
55957949686SYi Zou 	idtype = nla_get_u8(app_tb[DCB_APP_ATTR_IDTYPE]);
56057949686SYi Zou 	if ((idtype != DCB_APP_IDTYPE_ETHTYPE) &&
56157949686SYi Zou 	    (idtype != DCB_APP_IDTYPE_PORTNUM))
5623d1f4869SThomas Graf 		return -EINVAL;
56357949686SYi Zou 
56457949686SYi Zou 	id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]);
56557949686SYi Zou 	up = nla_get_u8(app_tb[DCB_APP_ATTR_PRIORITY]);
56657949686SYi Zou 
5679ab933abSJohn Fastabend 	if (netdev->dcbnl_ops->setapp) {
5683d1f4869SThomas Graf 		ret = netdev->dcbnl_ops->setapp(netdev, idtype, id, up);
569c2659479SAnish Bhatt 		if (ret < 0)
570c2659479SAnish Bhatt 			return ret;
5719ab933abSJohn Fastabend 	} else {
5729ab933abSJohn Fastabend 		struct dcb_app app;
5739ab933abSJohn Fastabend 		app.selector = idtype;
5749ab933abSJohn Fastabend 		app.protocol = id;
5759ab933abSJohn Fastabend 		app.priority = up;
5763d1f4869SThomas Graf 		ret = dcb_setapp(netdev, &app);
5779ab933abSJohn Fastabend 	}
5789ab933abSJohn Fastabend 
5797be99413SThomas Graf 	ret = nla_put_u8(skb, DCB_ATTR_APP, ret);
58008157984SJohn Fastabend 	dcbnl_cee_notify(netdev, RTM_SETDCB, DCB_CMD_SAPP, seq, 0);
5813d1f4869SThomas Graf 
58257949686SYi Zou 	return ret;
58357949686SYi Zou }
58457949686SYi Zou 
__dcbnl_pg_getcfg(struct net_device * netdev,struct nlmsghdr * nlh,struct nlattr ** tb,struct sk_buff * skb,int dir)5857be99413SThomas Graf static int __dcbnl_pg_getcfg(struct net_device *netdev, struct nlmsghdr *nlh,
5867be99413SThomas Graf 			     struct nlattr **tb, struct sk_buff *skb, int dir)
5872f90b865SAlexander Duyck {
5882f90b865SAlexander Duyck 	struct nlattr *pg_nest, *param_nest, *data;
5892f90b865SAlexander Duyck 	struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1];
5902f90b865SAlexander Duyck 	struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1];
5912f90b865SAlexander Duyck 	u8 prio, pgid, tc_pct, up_map;
5923d1f4869SThomas Graf 	int ret;
5932f90b865SAlexander Duyck 	int getall = 0;
5942f90b865SAlexander Duyck 	int i;
5952f90b865SAlexander Duyck 
5963d1f4869SThomas Graf 	if (!tb[DCB_ATTR_PG_CFG])
5973d1f4869SThomas Graf 		return -EINVAL;
5983d1f4869SThomas Graf 
5993d1f4869SThomas Graf 	if (!netdev->dcbnl_ops->getpgtccfgtx ||
6002f90b865SAlexander Duyck 	    !netdev->dcbnl_ops->getpgtccfgrx ||
6012f90b865SAlexander Duyck 	    !netdev->dcbnl_ops->getpgbwgcfgtx ||
6022f90b865SAlexander Duyck 	    !netdev->dcbnl_ops->getpgbwgcfgrx)
6033d1f4869SThomas Graf 		return -EOPNOTSUPP;
6042f90b865SAlexander Duyck 
6058cb08174SJohannes Berg 	ret = nla_parse_nested_deprecated(pg_tb, DCB_PG_ATTR_MAX,
6068cb08174SJohannes Berg 					  tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest,
6078cb08174SJohannes Berg 					  NULL);
6082f90b865SAlexander Duyck 	if (ret)
6093d1f4869SThomas Graf 		return ret;
6102f90b865SAlexander Duyck 
611ae0be8deSMichal Kubecek 	pg_nest = nla_nest_start_noflag(skb, DCB_ATTR_PG_CFG);
6122f90b865SAlexander Duyck 	if (!pg_nest)
6133d1f4869SThomas Graf 		return -EMSGSIZE;
6142f90b865SAlexander Duyck 
6152f90b865SAlexander Duyck 	if (pg_tb[DCB_PG_ATTR_TC_ALL])
6162f90b865SAlexander Duyck 		getall = 1;
6172f90b865SAlexander Duyck 
6182f90b865SAlexander Duyck 	for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) {
6192f90b865SAlexander Duyck 		if (!getall && !pg_tb[i])
6202f90b865SAlexander Duyck 			continue;
6212f90b865SAlexander Duyck 
6222f90b865SAlexander Duyck 		if (pg_tb[DCB_PG_ATTR_TC_ALL])
6232f90b865SAlexander Duyck 			data = pg_tb[DCB_PG_ATTR_TC_ALL];
6242f90b865SAlexander Duyck 		else
6252f90b865SAlexander Duyck 			data = pg_tb[i];
6268cb08174SJohannes Berg 		ret = nla_parse_nested_deprecated(param_tb,
6278cb08174SJohannes Berg 						  DCB_TC_ATTR_PARAM_MAX, data,
628fceb6435SJohannes Berg 						  dcbnl_tc_param_nest, NULL);
6292f90b865SAlexander Duyck 		if (ret)
6302f90b865SAlexander Duyck 			goto err_pg;
6312f90b865SAlexander Duyck 
632ae0be8deSMichal Kubecek 		param_nest = nla_nest_start_noflag(skb, i);
6332f90b865SAlexander Duyck 		if (!param_nest)
6342f90b865SAlexander Duyck 			goto err_pg;
6352f90b865SAlexander Duyck 
6362f90b865SAlexander Duyck 		pgid = DCB_ATTR_VALUE_UNDEFINED;
6372f90b865SAlexander Duyck 		prio = DCB_ATTR_VALUE_UNDEFINED;
6382f90b865SAlexander Duyck 		tc_pct = DCB_ATTR_VALUE_UNDEFINED;
6392f90b865SAlexander Duyck 		up_map = DCB_ATTR_VALUE_UNDEFINED;
6402f90b865SAlexander Duyck 
6412f90b865SAlexander Duyck 		if (dir) {
6422f90b865SAlexander Duyck 			/* Rx */
6432f90b865SAlexander Duyck 			netdev->dcbnl_ops->getpgtccfgrx(netdev,
6442f90b865SAlexander Duyck 						i - DCB_PG_ATTR_TC_0, &prio,
6452f90b865SAlexander Duyck 						&pgid, &tc_pct, &up_map);
6462f90b865SAlexander Duyck 		} else {
6472f90b865SAlexander Duyck 			/* Tx */
6482f90b865SAlexander Duyck 			netdev->dcbnl_ops->getpgtccfgtx(netdev,
6492f90b865SAlexander Duyck 						i - DCB_PG_ATTR_TC_0, &prio,
6502f90b865SAlexander Duyck 						&pgid, &tc_pct, &up_map);
6512f90b865SAlexander Duyck 		}
6522f90b865SAlexander Duyck 
6532f90b865SAlexander Duyck 		if (param_tb[DCB_TC_ATTR_PARAM_PGID] ||
6542f90b865SAlexander Duyck 		    param_tb[DCB_TC_ATTR_PARAM_ALL]) {
6557be99413SThomas Graf 			ret = nla_put_u8(skb,
6562f90b865SAlexander Duyck 			                 DCB_TC_ATTR_PARAM_PGID, pgid);
6572f90b865SAlexander Duyck 			if (ret)
6582f90b865SAlexander Duyck 				goto err_param;
6592f90b865SAlexander Duyck 		}
6602f90b865SAlexander Duyck 		if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING] ||
6612f90b865SAlexander Duyck 		    param_tb[DCB_TC_ATTR_PARAM_ALL]) {
6627be99413SThomas Graf 			ret = nla_put_u8(skb,
6632f90b865SAlexander Duyck 			                 DCB_TC_ATTR_PARAM_UP_MAPPING, up_map);
6642f90b865SAlexander Duyck 			if (ret)
6652f90b865SAlexander Duyck 				goto err_param;
6662f90b865SAlexander Duyck 		}
6672f90b865SAlexander Duyck 		if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO] ||
6682f90b865SAlexander Duyck 		    param_tb[DCB_TC_ATTR_PARAM_ALL]) {
6697be99413SThomas Graf 			ret = nla_put_u8(skb,
6702f90b865SAlexander Duyck 			                 DCB_TC_ATTR_PARAM_STRICT_PRIO, prio);
6712f90b865SAlexander Duyck 			if (ret)
6722f90b865SAlexander Duyck 				goto err_param;
6732f90b865SAlexander Duyck 		}
6742f90b865SAlexander Duyck 		if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT] ||
6752f90b865SAlexander Duyck 		    param_tb[DCB_TC_ATTR_PARAM_ALL]) {
6767be99413SThomas Graf 			ret = nla_put_u8(skb, DCB_TC_ATTR_PARAM_BW_PCT,
6772f90b865SAlexander Duyck 			                 tc_pct);
6782f90b865SAlexander Duyck 			if (ret)
6792f90b865SAlexander Duyck 				goto err_param;
6802f90b865SAlexander Duyck 		}
6817be99413SThomas Graf 		nla_nest_end(skb, param_nest);
6822f90b865SAlexander Duyck 	}
6832f90b865SAlexander Duyck 
6842f90b865SAlexander Duyck 	if (pg_tb[DCB_PG_ATTR_BW_ID_ALL])
6852f90b865SAlexander Duyck 		getall = 1;
6862f90b865SAlexander Duyck 	else
6872f90b865SAlexander Duyck 		getall = 0;
6882f90b865SAlexander Duyck 
6892f90b865SAlexander Duyck 	for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) {
6902f90b865SAlexander Duyck 		if (!getall && !pg_tb[i])
6912f90b865SAlexander Duyck 			continue;
6922f90b865SAlexander Duyck 
6932f90b865SAlexander Duyck 		tc_pct = DCB_ATTR_VALUE_UNDEFINED;
6942f90b865SAlexander Duyck 
6952f90b865SAlexander Duyck 		if (dir) {
6962f90b865SAlexander Duyck 			/* Rx */
6972f90b865SAlexander Duyck 			netdev->dcbnl_ops->getpgbwgcfgrx(netdev,
6982f90b865SAlexander Duyck 					i - DCB_PG_ATTR_BW_ID_0, &tc_pct);
6992f90b865SAlexander Duyck 		} else {
7002f90b865SAlexander Duyck 			/* Tx */
7012f90b865SAlexander Duyck 			netdev->dcbnl_ops->getpgbwgcfgtx(netdev,
7022f90b865SAlexander Duyck 					i - DCB_PG_ATTR_BW_ID_0, &tc_pct);
7032f90b865SAlexander Duyck 		}
7047be99413SThomas Graf 		ret = nla_put_u8(skb, i, tc_pct);
7052f90b865SAlexander Duyck 		if (ret)
7062f90b865SAlexander Duyck 			goto err_pg;
7072f90b865SAlexander Duyck 	}
7082f90b865SAlexander Duyck 
7097be99413SThomas Graf 	nla_nest_end(skb, pg_nest);
7102f90b865SAlexander Duyck 
7112f90b865SAlexander Duyck 	return 0;
7122f90b865SAlexander Duyck 
7132f90b865SAlexander Duyck err_param:
7147be99413SThomas Graf 	nla_nest_cancel(skb, param_nest);
7152f90b865SAlexander Duyck err_pg:
7167be99413SThomas Graf 	nla_nest_cancel(skb, pg_nest);
7173d1f4869SThomas Graf 
7183d1f4869SThomas Graf 	return -EMSGSIZE;
7192f90b865SAlexander Duyck }
7202f90b865SAlexander Duyck 
dcbnl_pgtx_getcfg(struct net_device * netdev,struct nlmsghdr * nlh,u32 seq,struct nlattr ** tb,struct sk_buff * skb)7217be99413SThomas Graf static int dcbnl_pgtx_getcfg(struct net_device *netdev, struct nlmsghdr *nlh,
7227be99413SThomas Graf 			     u32 seq, struct nlattr **tb, struct sk_buff *skb)
7232f90b865SAlexander Duyck {
7247be99413SThomas Graf 	return __dcbnl_pg_getcfg(netdev, nlh, tb, skb, 0);
7252f90b865SAlexander Duyck }
7262f90b865SAlexander Duyck 
dcbnl_pgrx_getcfg(struct net_device * netdev,struct nlmsghdr * nlh,u32 seq,struct nlattr ** tb,struct sk_buff * skb)7277be99413SThomas Graf static int dcbnl_pgrx_getcfg(struct net_device *netdev, struct nlmsghdr *nlh,
7287be99413SThomas Graf 			     u32 seq, struct nlattr **tb, struct sk_buff *skb)
7292f90b865SAlexander Duyck {
7307be99413SThomas Graf 	return __dcbnl_pg_getcfg(netdev, nlh, tb, skb, 1);
7312f90b865SAlexander Duyck }
7322f90b865SAlexander Duyck 
dcbnl_setstate(struct net_device * netdev,struct nlmsghdr * nlh,u32 seq,struct nlattr ** tb,struct sk_buff * skb)7337be99413SThomas Graf static int dcbnl_setstate(struct net_device *netdev, struct nlmsghdr *nlh,
7347be99413SThomas Graf 			  u32 seq, struct nlattr **tb, struct sk_buff *skb)
7352f90b865SAlexander Duyck {
7362f90b865SAlexander Duyck 	u8 value;
7372f90b865SAlexander Duyck 
7383d1f4869SThomas Graf 	if (!tb[DCB_ATTR_STATE])
7397be99413SThomas Graf 		return -EINVAL;
7402f90b865SAlexander Duyck 
7413d1f4869SThomas Graf 	if (!netdev->dcbnl_ops->setstate)
7423d1f4869SThomas Graf 		return -EOPNOTSUPP;
7433d1f4869SThomas Graf 
7442f90b865SAlexander Duyck 	value = nla_get_u8(tb[DCB_ATTR_STATE]);
7452f90b865SAlexander Duyck 
7467be99413SThomas Graf 	return nla_put_u8(skb, DCB_ATTR_STATE,
7477be99413SThomas Graf 			  netdev->dcbnl_ops->setstate(netdev, value));
7482f90b865SAlexander Duyck }
7492f90b865SAlexander Duyck 
dcbnl_setpfccfg(struct net_device * netdev,struct nlmsghdr * nlh,u32 seq,struct nlattr ** tb,struct sk_buff * skb)7507be99413SThomas Graf static int dcbnl_setpfccfg(struct net_device *netdev, struct nlmsghdr *nlh,
7517be99413SThomas Graf 			   u32 seq, struct nlattr **tb, struct sk_buff *skb)
7522f90b865SAlexander Duyck {
7532f90b865SAlexander Duyck 	struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1];
7542f90b865SAlexander Duyck 	int i;
7553d1f4869SThomas Graf 	int ret;
7562f90b865SAlexander Duyck 	u8 value;
7572f90b865SAlexander Duyck 
7583d1f4869SThomas Graf 	if (!tb[DCB_ATTR_PFC_CFG])
7593d1f4869SThomas Graf 		return -EINVAL;
7603d1f4869SThomas Graf 
7613d1f4869SThomas Graf 	if (!netdev->dcbnl_ops->setpfccfg)
7623d1f4869SThomas Graf 		return -EOPNOTSUPP;
7632f90b865SAlexander Duyck 
7648cb08174SJohannes Berg 	ret = nla_parse_nested_deprecated(data, DCB_PFC_UP_ATTR_MAX,
7658cb08174SJohannes Berg 					  tb[DCB_ATTR_PFC_CFG],
7668cb08174SJohannes Berg 					  dcbnl_pfc_up_nest, NULL);
7672f90b865SAlexander Duyck 	if (ret)
7683d1f4869SThomas Graf 		return ret;
7692f90b865SAlexander Duyck 
7702f90b865SAlexander Duyck 	for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) {
7712f90b865SAlexander Duyck 		if (data[i] == NULL)
7722f90b865SAlexander Duyck 			continue;
7732f90b865SAlexander Duyck 		value = nla_get_u8(data[i]);
7742f90b865SAlexander Duyck 		netdev->dcbnl_ops->setpfccfg(netdev,
7752f90b865SAlexander Duyck 			data[i]->nla_type - DCB_PFC_UP_ATTR_0, value);
7762f90b865SAlexander Duyck 	}
7772f90b865SAlexander Duyck 
7787be99413SThomas Graf 	return nla_put_u8(skb, DCB_ATTR_PFC_CFG, 0);
7792f90b865SAlexander Duyck }
7802f90b865SAlexander Duyck 
dcbnl_setall(struct net_device * netdev,struct nlmsghdr * nlh,u32 seq,struct nlattr ** tb,struct sk_buff * skb)7817be99413SThomas Graf static int dcbnl_setall(struct net_device *netdev, struct nlmsghdr *nlh,
7827be99413SThomas Graf 			u32 seq, struct nlattr **tb, struct sk_buff *skb)
7832f90b865SAlexander Duyck {
7843d1f4869SThomas Graf 	int ret;
7852f90b865SAlexander Duyck 
7863d1f4869SThomas Graf 	if (!tb[DCB_ATTR_SET_ALL])
7873d1f4869SThomas Graf 		return -EINVAL;
7883d1f4869SThomas Graf 
7893d1f4869SThomas Graf 	if (!netdev->dcbnl_ops->setall)
7903d1f4869SThomas Graf 		return -EOPNOTSUPP;
7912f90b865SAlexander Duyck 
7927be99413SThomas Graf 	ret = nla_put_u8(skb, DCB_ATTR_SET_ALL,
7937be99413SThomas Graf 			 netdev->dcbnl_ops->setall(netdev));
79408157984SJohn Fastabend 	dcbnl_cee_notify(netdev, RTM_SETDCB, DCB_CMD_SET_ALL, seq, 0);
7952f90b865SAlexander Duyck 
7962f90b865SAlexander Duyck 	return ret;
7972f90b865SAlexander Duyck }
7982f90b865SAlexander Duyck 
__dcbnl_pg_setcfg(struct net_device * netdev,struct nlmsghdr * nlh,u32 seq,struct nlattr ** tb,struct sk_buff * skb,int dir)7997be99413SThomas Graf static int __dcbnl_pg_setcfg(struct net_device *netdev, struct nlmsghdr *nlh,
8007be99413SThomas Graf 			     u32 seq, struct nlattr **tb, struct sk_buff *skb,
8017be99413SThomas Graf 			     int dir)
8022f90b865SAlexander Duyck {
8032f90b865SAlexander Duyck 	struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1];
8042f90b865SAlexander Duyck 	struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1];
8053d1f4869SThomas Graf 	int ret;
8062f90b865SAlexander Duyck 	int i;
8072f90b865SAlexander Duyck 	u8 pgid;
8082f90b865SAlexander Duyck 	u8 up_map;
8092f90b865SAlexander Duyck 	u8 prio;
8102f90b865SAlexander Duyck 	u8 tc_pct;
8112f90b865SAlexander Duyck 
8123d1f4869SThomas Graf 	if (!tb[DCB_ATTR_PG_CFG])
8133d1f4869SThomas Graf 		return -EINVAL;
8143d1f4869SThomas Graf 
8153d1f4869SThomas Graf 	if (!netdev->dcbnl_ops->setpgtccfgtx ||
8162f90b865SAlexander Duyck 	    !netdev->dcbnl_ops->setpgtccfgrx ||
8172f90b865SAlexander Duyck 	    !netdev->dcbnl_ops->setpgbwgcfgtx ||
8182f90b865SAlexander Duyck 	    !netdev->dcbnl_ops->setpgbwgcfgrx)
8193d1f4869SThomas Graf 		return -EOPNOTSUPP;
8202f90b865SAlexander Duyck 
8218cb08174SJohannes Berg 	ret = nla_parse_nested_deprecated(pg_tb, DCB_PG_ATTR_MAX,
8228cb08174SJohannes Berg 					  tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest,
8238cb08174SJohannes Berg 					  NULL);
8242f90b865SAlexander Duyck 	if (ret)
8253d1f4869SThomas Graf 		return ret;
8262f90b865SAlexander Duyck 
8272f90b865SAlexander Duyck 	for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) {
8282f90b865SAlexander Duyck 		if (!pg_tb[i])
8292f90b865SAlexander Duyck 			continue;
8302f90b865SAlexander Duyck 
8318cb08174SJohannes Berg 		ret = nla_parse_nested_deprecated(param_tb,
8328cb08174SJohannes Berg 						  DCB_TC_ATTR_PARAM_MAX,
8338cb08174SJohannes Berg 						  pg_tb[i],
8348cb08174SJohannes Berg 						  dcbnl_tc_param_nest, NULL);
8352f90b865SAlexander Duyck 		if (ret)
8363d1f4869SThomas Graf 			return ret;
8372f90b865SAlexander Duyck 
8382f90b865SAlexander Duyck 		pgid = DCB_ATTR_VALUE_UNDEFINED;
8392f90b865SAlexander Duyck 		prio = DCB_ATTR_VALUE_UNDEFINED;
8402f90b865SAlexander Duyck 		tc_pct = DCB_ATTR_VALUE_UNDEFINED;
8412f90b865SAlexander Duyck 		up_map = DCB_ATTR_VALUE_UNDEFINED;
8422f90b865SAlexander Duyck 
8432f90b865SAlexander Duyck 		if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO])
8442f90b865SAlexander Duyck 			prio =
8452f90b865SAlexander Duyck 			    nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO]);
8462f90b865SAlexander Duyck 
8472f90b865SAlexander Duyck 		if (param_tb[DCB_TC_ATTR_PARAM_PGID])
8482f90b865SAlexander Duyck 			pgid = nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_PGID]);
8492f90b865SAlexander Duyck 
8502f90b865SAlexander Duyck 		if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT])
8512f90b865SAlexander Duyck 			tc_pct = nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_BW_PCT]);
8522f90b865SAlexander Duyck 
8532f90b865SAlexander Duyck 		if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING])
8542f90b865SAlexander Duyck 			up_map =
8552f90b865SAlexander Duyck 			     nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING]);
8562f90b865SAlexander Duyck 
8572f90b865SAlexander Duyck 		/* dir: Tx = 0, Rx = 1 */
8582f90b865SAlexander Duyck 		if (dir) {
8592f90b865SAlexander Duyck 			/* Rx */
8602f90b865SAlexander Duyck 			netdev->dcbnl_ops->setpgtccfgrx(netdev,
8612f90b865SAlexander Duyck 				i - DCB_PG_ATTR_TC_0,
8622f90b865SAlexander Duyck 				prio, pgid, tc_pct, up_map);
8632f90b865SAlexander Duyck 		} else {
8642f90b865SAlexander Duyck 			/* Tx */
8652f90b865SAlexander Duyck 			netdev->dcbnl_ops->setpgtccfgtx(netdev,
8662f90b865SAlexander Duyck 				i - DCB_PG_ATTR_TC_0,
8672f90b865SAlexander Duyck 				prio, pgid, tc_pct, up_map);
8682f90b865SAlexander Duyck 		}
8692f90b865SAlexander Duyck 	}
8702f90b865SAlexander Duyck 
8712f90b865SAlexander Duyck 	for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) {
8722f90b865SAlexander Duyck 		if (!pg_tb[i])
8732f90b865SAlexander Duyck 			continue;
8742f90b865SAlexander Duyck 
8752f90b865SAlexander Duyck 		tc_pct = nla_get_u8(pg_tb[i]);
8762f90b865SAlexander Duyck 
8772f90b865SAlexander Duyck 		/* dir: Tx = 0, Rx = 1 */
8782f90b865SAlexander Duyck 		if (dir) {
8792f90b865SAlexander Duyck 			/* Rx */
8802f90b865SAlexander Duyck 			netdev->dcbnl_ops->setpgbwgcfgrx(netdev,
8812f90b865SAlexander Duyck 					 i - DCB_PG_ATTR_BW_ID_0, tc_pct);
8822f90b865SAlexander Duyck 		} else {
8832f90b865SAlexander Duyck 			/* Tx */
8842f90b865SAlexander Duyck 			netdev->dcbnl_ops->setpgbwgcfgtx(netdev,
8852f90b865SAlexander Duyck 					 i - DCB_PG_ATTR_BW_ID_0, tc_pct);
8862f90b865SAlexander Duyck 		}
8872f90b865SAlexander Duyck 	}
8882f90b865SAlexander Duyck 
889bb1dfefdSJohn Fastabend 	return nla_put_u8(skb, DCB_ATTR_PG_CFG, 0);
8902f90b865SAlexander Duyck }
8912f90b865SAlexander Duyck 
dcbnl_pgtx_setcfg(struct net_device * netdev,struct nlmsghdr * nlh,u32 seq,struct nlattr ** tb,struct sk_buff * skb)8927be99413SThomas Graf static int dcbnl_pgtx_setcfg(struct net_device *netdev, struct nlmsghdr *nlh,
8937be99413SThomas Graf 			     u32 seq, struct nlattr **tb, struct sk_buff *skb)
8942f90b865SAlexander Duyck {
8957be99413SThomas Graf 	return __dcbnl_pg_setcfg(netdev, nlh, seq, tb, skb, 0);
8962f90b865SAlexander Duyck }
8972f90b865SAlexander Duyck 
dcbnl_pgrx_setcfg(struct net_device * netdev,struct nlmsghdr * nlh,u32 seq,struct nlattr ** tb,struct sk_buff * skb)8987be99413SThomas Graf static int dcbnl_pgrx_setcfg(struct net_device *netdev, struct nlmsghdr *nlh,
8997be99413SThomas Graf 			     u32 seq, struct nlattr **tb, struct sk_buff *skb)
9002f90b865SAlexander Duyck {
9017be99413SThomas Graf 	return __dcbnl_pg_setcfg(netdev, nlh, seq, tb, skb, 1);
9022f90b865SAlexander Duyck }
9032f90b865SAlexander Duyck 
dcbnl_bcn_getcfg(struct net_device * netdev,struct nlmsghdr * nlh,u32 seq,struct nlattr ** tb,struct sk_buff * skb)9047be99413SThomas Graf static int dcbnl_bcn_getcfg(struct net_device *netdev, struct nlmsghdr *nlh,
9057be99413SThomas Graf 			    u32 seq, struct nlattr **tb, struct sk_buff *skb)
906859ee3c4SAlexander Duyck {
907859ee3c4SAlexander Duyck 	struct nlattr *bcn_nest;
908859ee3c4SAlexander Duyck 	struct nlattr *bcn_tb[DCB_BCN_ATTR_MAX + 1];
909859ee3c4SAlexander Duyck 	u8 value_byte;
910859ee3c4SAlexander Duyck 	u32 value_integer;
9113d1f4869SThomas Graf 	int ret;
912859ee3c4SAlexander Duyck 	bool getall = false;
913859ee3c4SAlexander Duyck 	int i;
914859ee3c4SAlexander Duyck 
9153d1f4869SThomas Graf 	if (!tb[DCB_ATTR_BCN])
9163d1f4869SThomas Graf 		return -EINVAL;
9173d1f4869SThomas Graf 
9183d1f4869SThomas Graf 	if (!netdev->dcbnl_ops->getbcnrp ||
919859ee3c4SAlexander Duyck 	    !netdev->dcbnl_ops->getbcncfg)
9203d1f4869SThomas Graf 		return -EOPNOTSUPP;
921859ee3c4SAlexander Duyck 
9228cb08174SJohannes Berg 	ret = nla_parse_nested_deprecated(bcn_tb, DCB_BCN_ATTR_MAX,
9238cb08174SJohannes Berg 					  tb[DCB_ATTR_BCN], dcbnl_bcn_nest,
9248cb08174SJohannes Berg 					  NULL);
925859ee3c4SAlexander Duyck 	if (ret)
9263d1f4869SThomas Graf 		return ret;
927859ee3c4SAlexander Duyck 
928ae0be8deSMichal Kubecek 	bcn_nest = nla_nest_start_noflag(skb, DCB_ATTR_BCN);
929859ee3c4SAlexander Duyck 	if (!bcn_nest)
9303d1f4869SThomas Graf 		return -EMSGSIZE;
931859ee3c4SAlexander Duyck 
932859ee3c4SAlexander Duyck 	if (bcn_tb[DCB_BCN_ATTR_ALL])
933859ee3c4SAlexander Duyck 		getall = true;
934859ee3c4SAlexander Duyck 
935859ee3c4SAlexander Duyck 	for (i = DCB_BCN_ATTR_RP_0; i <= DCB_BCN_ATTR_RP_7; i++) {
936859ee3c4SAlexander Duyck 		if (!getall && !bcn_tb[i])
937859ee3c4SAlexander Duyck 			continue;
938859ee3c4SAlexander Duyck 
939859ee3c4SAlexander Duyck 		netdev->dcbnl_ops->getbcnrp(netdev, i - DCB_BCN_ATTR_RP_0,
940859ee3c4SAlexander Duyck 		                            &value_byte);
9417be99413SThomas Graf 		ret = nla_put_u8(skb, i, value_byte);
942859ee3c4SAlexander Duyck 		if (ret)
943859ee3c4SAlexander Duyck 			goto err_bcn;
944859ee3c4SAlexander Duyck 	}
945859ee3c4SAlexander Duyck 
946f4314e81SDon Skidmore 	for (i = DCB_BCN_ATTR_BCNA_0; i <= DCB_BCN_ATTR_RI; i++) {
947859ee3c4SAlexander Duyck 		if (!getall && !bcn_tb[i])
948859ee3c4SAlexander Duyck 			continue;
949859ee3c4SAlexander Duyck 
950859ee3c4SAlexander Duyck 		netdev->dcbnl_ops->getbcncfg(netdev, i,
951859ee3c4SAlexander Duyck 		                             &value_integer);
9527be99413SThomas Graf 		ret = nla_put_u32(skb, i, value_integer);
953859ee3c4SAlexander Duyck 		if (ret)
954859ee3c4SAlexander Duyck 			goto err_bcn;
955859ee3c4SAlexander Duyck 	}
956859ee3c4SAlexander Duyck 
9577be99413SThomas Graf 	nla_nest_end(skb, bcn_nest);
958859ee3c4SAlexander Duyck 
959859ee3c4SAlexander Duyck 	return 0;
960859ee3c4SAlexander Duyck 
961859ee3c4SAlexander Duyck err_bcn:
9627be99413SThomas Graf 	nla_nest_cancel(skb, bcn_nest);
963859ee3c4SAlexander Duyck 	return ret;
964859ee3c4SAlexander Duyck }
965859ee3c4SAlexander Duyck 
dcbnl_bcn_setcfg(struct net_device * netdev,struct nlmsghdr * nlh,u32 seq,struct nlattr ** tb,struct sk_buff * skb)9667be99413SThomas Graf static int dcbnl_bcn_setcfg(struct net_device *netdev, struct nlmsghdr *nlh,
9677be99413SThomas Graf 			    u32 seq, struct nlattr **tb, struct sk_buff *skb)
968859ee3c4SAlexander Duyck {
969859ee3c4SAlexander Duyck 	struct nlattr *data[DCB_BCN_ATTR_MAX + 1];
970859ee3c4SAlexander Duyck 	int i;
9713d1f4869SThomas Graf 	int ret;
972859ee3c4SAlexander Duyck 	u8 value_byte;
973859ee3c4SAlexander Duyck 	u32 value_int;
974859ee3c4SAlexander Duyck 
9753d1f4869SThomas Graf 	if (!tb[DCB_ATTR_BCN])
9763d1f4869SThomas Graf 		return -EINVAL;
9773d1f4869SThomas Graf 
9783d1f4869SThomas Graf 	if (!netdev->dcbnl_ops->setbcncfg ||
979f64f9e71SJoe Perches 	    !netdev->dcbnl_ops->setbcnrp)
9803d1f4869SThomas Graf 		return -EOPNOTSUPP;
981859ee3c4SAlexander Duyck 
9828cb08174SJohannes Berg 	ret = nla_parse_nested_deprecated(data, DCB_BCN_ATTR_MAX,
983*31d49ba0SLin Ma 					  tb[DCB_ATTR_BCN], dcbnl_bcn_nest,
9848cb08174SJohannes Berg 					  NULL);
985859ee3c4SAlexander Duyck 	if (ret)
9863d1f4869SThomas Graf 		return ret;
987859ee3c4SAlexander Duyck 
988859ee3c4SAlexander Duyck 	for (i = DCB_BCN_ATTR_RP_0; i <= DCB_BCN_ATTR_RP_7; i++) {
989859ee3c4SAlexander Duyck 		if (data[i] == NULL)
990859ee3c4SAlexander Duyck 			continue;
991859ee3c4SAlexander Duyck 		value_byte = nla_get_u8(data[i]);
992859ee3c4SAlexander Duyck 		netdev->dcbnl_ops->setbcnrp(netdev,
993859ee3c4SAlexander Duyck 			data[i]->nla_type - DCB_BCN_ATTR_RP_0, value_byte);
994859ee3c4SAlexander Duyck 	}
995859ee3c4SAlexander Duyck 
996f4314e81SDon Skidmore 	for (i = DCB_BCN_ATTR_BCNA_0; i <= DCB_BCN_ATTR_RI; i++) {
997859ee3c4SAlexander Duyck 		if (data[i] == NULL)
998859ee3c4SAlexander Duyck 			continue;
999859ee3c4SAlexander Duyck 		value_int = nla_get_u32(data[i]);
1000859ee3c4SAlexander Duyck 		netdev->dcbnl_ops->setbcncfg(netdev,
1001859ee3c4SAlexander Duyck 	                                     i, value_int);
1002859ee3c4SAlexander Duyck 	}
1003859ee3c4SAlexander Duyck 
10043d1f4869SThomas Graf 	return nla_put_u8(skb, DCB_ATTR_BCN, 0);
1005859ee3c4SAlexander Duyck }
1006859ee3c4SAlexander Duyck 
dcbnl_build_peer_app(struct net_device * netdev,struct sk_buff * skb,int app_nested_type,int app_info_type,int app_entry_type)1007dc6ed1dfSShmulik Ravid static int dcbnl_build_peer_app(struct net_device *netdev, struct sk_buff* skb,
1008dc6ed1dfSShmulik Ravid 				int app_nested_type, int app_info_type,
1009dc6ed1dfSShmulik Ravid 				int app_entry_type)
1010eed84713SShmulik Ravid {
1011eed84713SShmulik Ravid 	struct dcb_peer_app_info info;
1012eed84713SShmulik Ravid 	struct dcb_app *table = NULL;
1013eed84713SShmulik Ravid 	const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
1014eed84713SShmulik Ravid 	u16 app_count;
1015eed84713SShmulik Ravid 	int err;
1016eed84713SShmulik Ravid 
1017eed84713SShmulik Ravid 
1018eed84713SShmulik Ravid 	/**
1019eed84713SShmulik Ravid 	 * retrieve the peer app configuration form the driver. If the driver
1020eed84713SShmulik Ravid 	 * handlers fail exit without doing anything
1021eed84713SShmulik Ravid 	 */
1022eed84713SShmulik Ravid 	err = ops->peer_getappinfo(netdev, &info, &app_count);
1023eed84713SShmulik Ravid 	if (!err && app_count) {
10246da2ec56SKees Cook 		table = kmalloc_array(app_count, sizeof(struct dcb_app),
10256da2ec56SKees Cook 				      GFP_KERNEL);
1026eed84713SShmulik Ravid 		if (!table)
1027eed84713SShmulik Ravid 			return -ENOMEM;
1028eed84713SShmulik Ravid 
1029eed84713SShmulik Ravid 		err = ops->peer_getapptable(netdev, table);
1030eed84713SShmulik Ravid 	}
1031eed84713SShmulik Ravid 
1032eed84713SShmulik Ravid 	if (!err) {
1033eed84713SShmulik Ravid 		u16 i;
1034eed84713SShmulik Ravid 		struct nlattr *app;
1035eed84713SShmulik Ravid 
1036eed84713SShmulik Ravid 		/**
1037eed84713SShmulik Ravid 		 * build the message, from here on the only possible failure
1038eed84713SShmulik Ravid 		 * is due to the skb size
1039eed84713SShmulik Ravid 		 */
1040eed84713SShmulik Ravid 		err = -EMSGSIZE;
1041eed84713SShmulik Ravid 
1042ae0be8deSMichal Kubecek 		app = nla_nest_start_noflag(skb, app_nested_type);
1043eed84713SShmulik Ravid 		if (!app)
1044eed84713SShmulik Ravid 			goto nla_put_failure;
1045eed84713SShmulik Ravid 
10461eb4c977SDavid S. Miller 		if (app_info_type &&
10471eb4c977SDavid S. Miller 		    nla_put(skb, app_info_type, sizeof(info), &info))
10481eb4c977SDavid S. Miller 			goto nla_put_failure;
1049dc6ed1dfSShmulik Ravid 
10501eb4c977SDavid S. Miller 		for (i = 0; i < app_count; i++) {
10511eb4c977SDavid S. Miller 			if (nla_put(skb, app_entry_type, sizeof(struct dcb_app),
10521eb4c977SDavid S. Miller 				    &table[i]))
10531eb4c977SDavid S. Miller 				goto nla_put_failure;
10541eb4c977SDavid S. Miller 		}
1055eed84713SShmulik Ravid 		nla_nest_end(skb, app);
1056eed84713SShmulik Ravid 	}
1057eed84713SShmulik Ravid 	err = 0;
1058eed84713SShmulik Ravid 
1059eed84713SShmulik Ravid nla_put_failure:
1060eed84713SShmulik Ravid 	kfree(table);
1061eed84713SShmulik Ravid 	return err;
1062eed84713SShmulik Ravid }
10633e29027aSJohn Fastabend 
dcbnl_getapptrust(struct net_device * netdev,struct sk_buff * skb)10647eba4505SDaniel Machon static int dcbnl_getapptrust(struct net_device *netdev, struct sk_buff *skb)
10657eba4505SDaniel Machon {
10667eba4505SDaniel Machon 	const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
10677eba4505SDaniel Machon 	enum ieee_attrs_app type;
10687eba4505SDaniel Machon 	struct nlattr *apptrust;
10697eba4505SDaniel Machon 	int nselectors, err, i;
10707eba4505SDaniel Machon 	u8 *selectors;
10717eba4505SDaniel Machon 
10727eba4505SDaniel Machon 	selectors = kzalloc(IEEE_8021QAZ_APP_SEL_MAX + 1, GFP_KERNEL);
10737eba4505SDaniel Machon 	if (!selectors)
10747eba4505SDaniel Machon 		return -ENOMEM;
10757eba4505SDaniel Machon 
10767eba4505SDaniel Machon 	err = ops->dcbnl_getapptrust(netdev, selectors, &nselectors);
10777eba4505SDaniel Machon 	if (err) {
10787eba4505SDaniel Machon 		err = 0;
10797eba4505SDaniel Machon 		goto out;
10807eba4505SDaniel Machon 	}
10817eba4505SDaniel Machon 
10827eba4505SDaniel Machon 	apptrust = nla_nest_start(skb, DCB_ATTR_DCB_APP_TRUST_TABLE);
10837eba4505SDaniel Machon 	if (!apptrust) {
10847eba4505SDaniel Machon 		err = -EMSGSIZE;
10857eba4505SDaniel Machon 		goto out;
10867eba4505SDaniel Machon 	}
10877eba4505SDaniel Machon 
10887eba4505SDaniel Machon 	for (i = 0; i < nselectors; i++) {
10897eba4505SDaniel Machon 		type = dcbnl_app_attr_type_get(selectors[i]);
10907eba4505SDaniel Machon 		err = nla_put_u8(skb, type, selectors[i]);
10917eba4505SDaniel Machon 		if (err) {
10927eba4505SDaniel Machon 			nla_nest_cancel(skb, apptrust);
10937eba4505SDaniel Machon 			goto out;
10947eba4505SDaniel Machon 		}
10957eba4505SDaniel Machon 	}
10967eba4505SDaniel Machon 	nla_nest_end(skb, apptrust);
10977eba4505SDaniel Machon 
10987eba4505SDaniel Machon out:
10997eba4505SDaniel Machon 	kfree(selectors);
11007eba4505SDaniel Machon 	return err;
11017eba4505SDaniel Machon }
11027eba4505SDaniel Machon 
110330568334SDaniel Machon /* Set or delete APP table or rewrite table entries. The APP struct is validated
110430568334SDaniel Machon  * and the appropriate callback function is called.
110530568334SDaniel Machon  */
dcbnl_app_table_setdel(struct nlattr * attr,struct net_device * netdev,int (* setdel)(struct net_device * dev,struct dcb_app * app))110630568334SDaniel Machon static int dcbnl_app_table_setdel(struct nlattr *attr,
110730568334SDaniel Machon 				  struct net_device *netdev,
110830568334SDaniel Machon 				  int (*setdel)(struct net_device *dev,
110930568334SDaniel Machon 						struct dcb_app *app))
111030568334SDaniel Machon {
111130568334SDaniel Machon 	struct dcb_app *app_data;
111230568334SDaniel Machon 	enum ieee_attrs_app type;
111330568334SDaniel Machon 	struct nlattr *attr_itr;
111430568334SDaniel Machon 	int rem, err;
111530568334SDaniel Machon 
111630568334SDaniel Machon 	nla_for_each_nested(attr_itr, attr, rem) {
111730568334SDaniel Machon 		type = nla_type(attr_itr);
111830568334SDaniel Machon 
111930568334SDaniel Machon 		if (!dcbnl_app_attr_type_validate(type))
112030568334SDaniel Machon 			continue;
112130568334SDaniel Machon 
112230568334SDaniel Machon 		if (nla_len(attr_itr) < sizeof(struct dcb_app))
112330568334SDaniel Machon 			return -ERANGE;
112430568334SDaniel Machon 
112530568334SDaniel Machon 		app_data = nla_data(attr_itr);
112630568334SDaniel Machon 
112730568334SDaniel Machon 		if (!dcbnl_app_selector_validate(type, app_data->selector))
112830568334SDaniel Machon 			return -EINVAL;
112930568334SDaniel Machon 
113030568334SDaniel Machon 		err = setdel(netdev, app_data);
113130568334SDaniel Machon 		if (err)
113230568334SDaniel Machon 			return err;
113330568334SDaniel Machon 	}
113430568334SDaniel Machon 
113530568334SDaniel Machon 	return 0;
113630568334SDaniel Machon }
113730568334SDaniel Machon 
1138c9368247SShani Michaeli /* Handle IEEE 802.1Qaz/802.1Qau/802.1Qbb GET commands. */
dcbnl_ieee_fill(struct sk_buff * skb,struct net_device * netdev)1139314b4778SJohn Fastabend static int dcbnl_ieee_fill(struct sk_buff *skb, struct net_device *netdev)
11403e29027aSJohn Fastabend {
11413e29027aSJohn Fastabend 	const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
1142622f1b2fSDaniel Machon 	struct nlattr *ieee, *app, *rewr;
11436182d587SDaniel Machon 	struct dcb_app_type *itr;
1144c7797bafSJohn Fastabend 	int dcbx;
11453d1f4869SThomas Graf 	int err;
11463e29027aSJohn Fastabend 
11471eb4c977SDavid S. Miller 	if (nla_put_string(skb, DCB_ATTR_IFNAME, netdev->name))
11483d1f4869SThomas Graf 		return -EMSGSIZE;
11493d1f4869SThomas Graf 
1150ae0be8deSMichal Kubecek 	ieee = nla_nest_start_noflag(skb, DCB_ATTR_IEEE);
11513e29027aSJohn Fastabend 	if (!ieee)
11523d1f4869SThomas Graf 		return -EMSGSIZE;
11533e29027aSJohn Fastabend 
11543e29027aSJohn Fastabend 	if (ops->ieee_getets) {
11553e29027aSJohn Fastabend 		struct ieee_ets ets;
115629cd8ae0SMathias Krause 		memset(&ets, 0, sizeof(ets));
11573e29027aSJohn Fastabend 		err = ops->ieee_getets(netdev, &ets);
11581eb4c977SDavid S. Miller 		if (!err &&
11591eb4c977SDavid S. Miller 		    nla_put(skb, DCB_ATTR_IEEE_ETS, sizeof(ets), &ets))
11603d1f4869SThomas Graf 			return -EMSGSIZE;
11613e29027aSJohn Fastabend 	}
11623e29027aSJohn Fastabend 
116308f10affSAmir Vadai 	if (ops->ieee_getmaxrate) {
116408f10affSAmir Vadai 		struct ieee_maxrate maxrate;
116529cd8ae0SMathias Krause 		memset(&maxrate, 0, sizeof(maxrate));
116608f10affSAmir Vadai 		err = ops->ieee_getmaxrate(netdev, &maxrate);
116708f10affSAmir Vadai 		if (!err) {
116808f10affSAmir Vadai 			err = nla_put(skb, DCB_ATTR_IEEE_MAXRATE,
116908f10affSAmir Vadai 				      sizeof(maxrate), &maxrate);
117008f10affSAmir Vadai 			if (err)
11713d1f4869SThomas Graf 				return -EMSGSIZE;
117208f10affSAmir Vadai 		}
117308f10affSAmir Vadai 	}
117408f10affSAmir Vadai 
1175c9368247SShani Michaeli 	if (ops->ieee_getqcn) {
1176c9368247SShani Michaeli 		struct ieee_qcn qcn;
1177c9368247SShani Michaeli 
1178c9368247SShani Michaeli 		memset(&qcn, 0, sizeof(qcn));
1179c9368247SShani Michaeli 		err = ops->ieee_getqcn(netdev, &qcn);
1180c9368247SShani Michaeli 		if (!err) {
1181c9368247SShani Michaeli 			err = nla_put(skb, DCB_ATTR_IEEE_QCN,
1182c9368247SShani Michaeli 				      sizeof(qcn), &qcn);
1183c9368247SShani Michaeli 			if (err)
1184c9368247SShani Michaeli 				return -EMSGSIZE;
1185c9368247SShani Michaeli 		}
1186c9368247SShani Michaeli 	}
1187c9368247SShani Michaeli 
1188c9368247SShani Michaeli 	if (ops->ieee_getqcnstats) {
1189c9368247SShani Michaeli 		struct ieee_qcn_stats qcn_stats;
1190c9368247SShani Michaeli 
1191c9368247SShani Michaeli 		memset(&qcn_stats, 0, sizeof(qcn_stats));
1192c9368247SShani Michaeli 		err = ops->ieee_getqcnstats(netdev, &qcn_stats);
1193c9368247SShani Michaeli 		if (!err) {
1194c9368247SShani Michaeli 			err = nla_put(skb, DCB_ATTR_IEEE_QCN_STATS,
1195c9368247SShani Michaeli 				      sizeof(qcn_stats), &qcn_stats);
1196c9368247SShani Michaeli 			if (err)
1197c9368247SShani Michaeli 				return -EMSGSIZE;
1198c9368247SShani Michaeli 		}
1199c9368247SShani Michaeli 	}
1200c9368247SShani Michaeli 
12013e29027aSJohn Fastabend 	if (ops->ieee_getpfc) {
12023e29027aSJohn Fastabend 		struct ieee_pfc pfc;
120329cd8ae0SMathias Krause 		memset(&pfc, 0, sizeof(pfc));
12043e29027aSJohn Fastabend 		err = ops->ieee_getpfc(netdev, &pfc);
12051eb4c977SDavid S. Miller 		if (!err &&
12061eb4c977SDavid S. Miller 		    nla_put(skb, DCB_ATTR_IEEE_PFC, sizeof(pfc), &pfc))
12073d1f4869SThomas Graf 			return -EMSGSIZE;
12083e29027aSJohn Fastabend 	}
12093e29027aSJohn Fastabend 
1210e549f6f9SHuy Nguyen 	if (ops->dcbnl_getbuffer) {
1211e549f6f9SHuy Nguyen 		struct dcbnl_buffer buffer;
1212e549f6f9SHuy Nguyen 
1213e549f6f9SHuy Nguyen 		memset(&buffer, 0, sizeof(buffer));
1214e549f6f9SHuy Nguyen 		err = ops->dcbnl_getbuffer(netdev, &buffer);
1215e549f6f9SHuy Nguyen 		if (!err &&
1216e549f6f9SHuy Nguyen 		    nla_put(skb, DCB_ATTR_DCB_BUFFER, sizeof(buffer), &buffer))
1217e549f6f9SHuy Nguyen 			return -EMSGSIZE;
1218e549f6f9SHuy Nguyen 	}
1219e549f6f9SHuy Nguyen 
1220ae0be8deSMichal Kubecek 	app = nla_nest_start_noflag(skb, DCB_ATTR_IEEE_APP_TABLE);
12219ab933abSJohn Fastabend 	if (!app)
12223d1f4869SThomas Graf 		return -EMSGSIZE;
12239ab933abSJohn Fastabend 
122452cff74eSAnish Bhatt 	spin_lock_bh(&dcb_lock);
12259ab933abSJohn Fastabend 	list_for_each_entry(itr, &dcb_app_list, list) {
1226e290ed81SMark Rustad 		if (itr->ifindex == netdev->ifindex) {
1227ec32c0c4SDaniel Machon 			enum ieee_attrs_app type =
1228ec32c0c4SDaniel Machon 				dcbnl_app_attr_type_get(itr->app.selector);
1229ec32c0c4SDaniel Machon 			err = nla_put(skb, type, sizeof(itr->app), &itr->app);
123070bfa2d2SDan Carpenter 			if (err) {
123152cff74eSAnish Bhatt 				spin_unlock_bh(&dcb_lock);
12323d1f4869SThomas Graf 				return -EMSGSIZE;
123370bfa2d2SDan Carpenter 			}
123470bfa2d2SDan Carpenter 		}
12359ab933abSJohn Fastabend 	}
1236c7797bafSJohn Fastabend 
1237c7797bafSJohn Fastabend 	if (netdev->dcbnl_ops->getdcbx)
1238c7797bafSJohn Fastabend 		dcbx = netdev->dcbnl_ops->getdcbx(netdev);
1239c7797bafSJohn Fastabend 	else
1240c7797bafSJohn Fastabend 		dcbx = -EOPNOTSUPP;
1241c7797bafSJohn Fastabend 
124252cff74eSAnish Bhatt 	spin_unlock_bh(&dcb_lock);
12439ab933abSJohn Fastabend 	nla_nest_end(skb, app);
12449ab933abSJohn Fastabend 
1245622f1b2fSDaniel Machon 	rewr = nla_nest_start(skb, DCB_ATTR_DCB_REWR_TABLE);
1246622f1b2fSDaniel Machon 	if (!rewr)
1247622f1b2fSDaniel Machon 		return -EMSGSIZE;
1248622f1b2fSDaniel Machon 
1249622f1b2fSDaniel Machon 	spin_lock_bh(&dcb_lock);
1250622f1b2fSDaniel Machon 	list_for_each_entry(itr, &dcb_rewr_list, list) {
1251622f1b2fSDaniel Machon 		if (itr->ifindex == netdev->ifindex) {
1252622f1b2fSDaniel Machon 			enum ieee_attrs_app type =
1253622f1b2fSDaniel Machon 				dcbnl_app_attr_type_get(itr->app.selector);
1254622f1b2fSDaniel Machon 			err = nla_put(skb, type, sizeof(itr->app), &itr->app);
1255622f1b2fSDaniel Machon 			if (err) {
1256622f1b2fSDaniel Machon 				spin_unlock_bh(&dcb_lock);
1257622f1b2fSDaniel Machon 				nla_nest_cancel(skb, rewr);
1258622f1b2fSDaniel Machon 				return -EMSGSIZE;
1259622f1b2fSDaniel Machon 			}
1260622f1b2fSDaniel Machon 		}
1261622f1b2fSDaniel Machon 	}
1262622f1b2fSDaniel Machon 
1263622f1b2fSDaniel Machon 	spin_unlock_bh(&dcb_lock);
1264622f1b2fSDaniel Machon 	nla_nest_end(skb, rewr);
1265622f1b2fSDaniel Machon 
12666182d587SDaniel Machon 	if (ops->dcbnl_getapptrust) {
12677eba4505SDaniel Machon 		err = dcbnl_getapptrust(netdev, skb);
12687eba4505SDaniel Machon 		if (err)
12696182d587SDaniel Machon 			return err;
12706182d587SDaniel Machon 	}
12716182d587SDaniel Machon 
1272eed84713SShmulik Ravid 	/* get peer info if available */
1273eed84713SShmulik Ravid 	if (ops->ieee_peer_getets) {
1274eed84713SShmulik Ravid 		struct ieee_ets ets;
127529cd8ae0SMathias Krause 		memset(&ets, 0, sizeof(ets));
1276eed84713SShmulik Ravid 		err = ops->ieee_peer_getets(netdev, &ets);
12771eb4c977SDavid S. Miller 		if (!err &&
12781eb4c977SDavid S. Miller 		    nla_put(skb, DCB_ATTR_IEEE_PEER_ETS, sizeof(ets), &ets))
12793d1f4869SThomas Graf 			return -EMSGSIZE;
1280eed84713SShmulik Ravid 	}
1281eed84713SShmulik Ravid 
1282eed84713SShmulik Ravid 	if (ops->ieee_peer_getpfc) {
1283eed84713SShmulik Ravid 		struct ieee_pfc pfc;
128429cd8ae0SMathias Krause 		memset(&pfc, 0, sizeof(pfc));
1285eed84713SShmulik Ravid 		err = ops->ieee_peer_getpfc(netdev, &pfc);
12861eb4c977SDavid S. Miller 		if (!err &&
12871eb4c977SDavid S. Miller 		    nla_put(skb, DCB_ATTR_IEEE_PEER_PFC, sizeof(pfc), &pfc))
12883d1f4869SThomas Graf 			return -EMSGSIZE;
1289eed84713SShmulik Ravid 	}
1290eed84713SShmulik Ravid 
1291eed84713SShmulik Ravid 	if (ops->peer_getappinfo && ops->peer_getapptable) {
1292dc6ed1dfSShmulik Ravid 		err = dcbnl_build_peer_app(netdev, skb,
1293dc6ed1dfSShmulik Ravid 					   DCB_ATTR_IEEE_PEER_APP,
1294dc6ed1dfSShmulik Ravid 					   DCB_ATTR_IEEE_APP_UNSPEC,
1295dc6ed1dfSShmulik Ravid 					   DCB_ATTR_IEEE_APP);
1296eed84713SShmulik Ravid 		if (err)
12973d1f4869SThomas Graf 			return -EMSGSIZE;
1298eed84713SShmulik Ravid 	}
1299eed84713SShmulik Ravid 
13003e29027aSJohn Fastabend 	nla_nest_end(skb, ieee);
1301c7797bafSJohn Fastabend 	if (dcbx >= 0) {
1302c7797bafSJohn Fastabend 		err = nla_put_u8(skb, DCB_ATTR_DCBX, dcbx);
1303c7797bafSJohn Fastabend 		if (err)
13043d1f4869SThomas Graf 			return -EMSGSIZE;
1305c7797bafSJohn Fastabend 	}
13063e29027aSJohn Fastabend 
1307314b4778SJohn Fastabend 	return 0;
13083e29027aSJohn Fastabend }
13093e29027aSJohn Fastabend 
dcbnl_cee_pg_fill(struct sk_buff * skb,struct net_device * dev,int dir)13105b7f7626SShmulik Ravid static int dcbnl_cee_pg_fill(struct sk_buff *skb, struct net_device *dev,
13115b7f7626SShmulik Ravid 			     int dir)
13125b7f7626SShmulik Ravid {
13135b7f7626SShmulik Ravid 	u8 pgid, up_map, prio, tc_pct;
13145b7f7626SShmulik Ravid 	const struct dcbnl_rtnl_ops *ops = dev->dcbnl_ops;
13155b7f7626SShmulik Ravid 	int i = dir ? DCB_ATTR_CEE_TX_PG : DCB_ATTR_CEE_RX_PG;
1316ae0be8deSMichal Kubecek 	struct nlattr *pg = nla_nest_start_noflag(skb, i);
13175b7f7626SShmulik Ravid 
13185b7f7626SShmulik Ravid 	if (!pg)
13193d1f4869SThomas Graf 		return -EMSGSIZE;
13205b7f7626SShmulik Ravid 
13215b7f7626SShmulik Ravid 	for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) {
1322ae0be8deSMichal Kubecek 		struct nlattr *tc_nest = nla_nest_start_noflag(skb, i);
13235b7f7626SShmulik Ravid 
13245b7f7626SShmulik Ravid 		if (!tc_nest)
13253d1f4869SThomas Graf 			return -EMSGSIZE;
13265b7f7626SShmulik Ravid 
13275b7f7626SShmulik Ravid 		pgid = DCB_ATTR_VALUE_UNDEFINED;
13285b7f7626SShmulik Ravid 		prio = DCB_ATTR_VALUE_UNDEFINED;
13295b7f7626SShmulik Ravid 		tc_pct = DCB_ATTR_VALUE_UNDEFINED;
13305b7f7626SShmulik Ravid 		up_map = DCB_ATTR_VALUE_UNDEFINED;
13315b7f7626SShmulik Ravid 
13325b7f7626SShmulik Ravid 		if (!dir)
13335b7f7626SShmulik Ravid 			ops->getpgtccfgrx(dev, i - DCB_PG_ATTR_TC_0,
13345b7f7626SShmulik Ravid 					  &prio, &pgid, &tc_pct, &up_map);
13355b7f7626SShmulik Ravid 		else
13365b7f7626SShmulik Ravid 			ops->getpgtccfgtx(dev, i - DCB_PG_ATTR_TC_0,
13375b7f7626SShmulik Ravid 					  &prio, &pgid, &tc_pct, &up_map);
13385b7f7626SShmulik Ravid 
13391eb4c977SDavid S. Miller 		if (nla_put_u8(skb, DCB_TC_ATTR_PARAM_PGID, pgid) ||
13401eb4c977SDavid S. Miller 		    nla_put_u8(skb, DCB_TC_ATTR_PARAM_UP_MAPPING, up_map) ||
13411eb4c977SDavid S. Miller 		    nla_put_u8(skb, DCB_TC_ATTR_PARAM_STRICT_PRIO, prio) ||
13421eb4c977SDavid S. Miller 		    nla_put_u8(skb, DCB_TC_ATTR_PARAM_BW_PCT, tc_pct))
13433d1f4869SThomas Graf 			return -EMSGSIZE;
13445b7f7626SShmulik Ravid 		nla_nest_end(skb, tc_nest);
13455b7f7626SShmulik Ravid 	}
13465b7f7626SShmulik Ravid 
13475b7f7626SShmulik Ravid 	for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) {
13485b7f7626SShmulik Ravid 		tc_pct = DCB_ATTR_VALUE_UNDEFINED;
13495b7f7626SShmulik Ravid 
13505b7f7626SShmulik Ravid 		if (!dir)
13515b7f7626SShmulik Ravid 			ops->getpgbwgcfgrx(dev, i - DCB_PG_ATTR_BW_ID_0,
13525b7f7626SShmulik Ravid 					   &tc_pct);
13535b7f7626SShmulik Ravid 		else
13545b7f7626SShmulik Ravid 			ops->getpgbwgcfgtx(dev, i - DCB_PG_ATTR_BW_ID_0,
13555b7f7626SShmulik Ravid 					   &tc_pct);
13561eb4c977SDavid S. Miller 		if (nla_put_u8(skb, i, tc_pct))
13573d1f4869SThomas Graf 			return -EMSGSIZE;
13585b7f7626SShmulik Ravid 	}
13595b7f7626SShmulik Ravid 	nla_nest_end(skb, pg);
13605b7f7626SShmulik Ravid 	return 0;
13615b7f7626SShmulik Ravid }
13625b7f7626SShmulik Ravid 
dcbnl_cee_fill(struct sk_buff * skb,struct net_device * netdev)13635b7f7626SShmulik Ravid static int dcbnl_cee_fill(struct sk_buff *skb, struct net_device *netdev)
13645b7f7626SShmulik Ravid {
13655b7f7626SShmulik Ravid 	struct nlattr *cee, *app;
13665b7f7626SShmulik Ravid 	struct dcb_app_type *itr;
13675b7f7626SShmulik Ravid 	const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
13685b7f7626SShmulik Ravid 	int dcbx, i, err = -EMSGSIZE;
13695b7f7626SShmulik Ravid 	u8 value;
13705b7f7626SShmulik Ravid 
13711eb4c977SDavid S. Miller 	if (nla_put_string(skb, DCB_ATTR_IFNAME, netdev->name))
13721eb4c977SDavid S. Miller 		goto nla_put_failure;
1373ae0be8deSMichal Kubecek 	cee = nla_nest_start_noflag(skb, DCB_ATTR_CEE);
13745b7f7626SShmulik Ravid 	if (!cee)
13755b7f7626SShmulik Ravid 		goto nla_put_failure;
13765b7f7626SShmulik Ravid 
13775b7f7626SShmulik Ravid 	/* local pg */
13785b7f7626SShmulik Ravid 	if (ops->getpgtccfgtx && ops->getpgbwgcfgtx) {
13795b7f7626SShmulik Ravid 		err = dcbnl_cee_pg_fill(skb, netdev, 1);
13805b7f7626SShmulik Ravid 		if (err)
13815b7f7626SShmulik Ravid 			goto nla_put_failure;
13825b7f7626SShmulik Ravid 	}
13835b7f7626SShmulik Ravid 
13845b7f7626SShmulik Ravid 	if (ops->getpgtccfgrx && ops->getpgbwgcfgrx) {
13855b7f7626SShmulik Ravid 		err = dcbnl_cee_pg_fill(skb, netdev, 0);
13865b7f7626SShmulik Ravid 		if (err)
13875b7f7626SShmulik Ravid 			goto nla_put_failure;
13885b7f7626SShmulik Ravid 	}
13895b7f7626SShmulik Ravid 
13905b7f7626SShmulik Ravid 	/* local pfc */
13915b7f7626SShmulik Ravid 	if (ops->getpfccfg) {
1392ae0be8deSMichal Kubecek 		struct nlattr *pfc_nest = nla_nest_start_noflag(skb,
1393ae0be8deSMichal Kubecek 								DCB_ATTR_CEE_PFC);
13945b7f7626SShmulik Ravid 
13955b7f7626SShmulik Ravid 		if (!pfc_nest)
13965b7f7626SShmulik Ravid 			goto nla_put_failure;
13975b7f7626SShmulik Ravid 
13985b7f7626SShmulik Ravid 		for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) {
13995b7f7626SShmulik Ravid 			ops->getpfccfg(netdev, i - DCB_PFC_UP_ATTR_0, &value);
14001eb4c977SDavid S. Miller 			if (nla_put_u8(skb, i, value))
14011eb4c977SDavid S. Miller 				goto nla_put_failure;
14025b7f7626SShmulik Ravid 		}
14035b7f7626SShmulik Ravid 		nla_nest_end(skb, pfc_nest);
14045b7f7626SShmulik Ravid 	}
14055b7f7626SShmulik Ravid 
14065b7f7626SShmulik Ravid 	/* local app */
140752cff74eSAnish Bhatt 	spin_lock_bh(&dcb_lock);
1408ae0be8deSMichal Kubecek 	app = nla_nest_start_noflag(skb, DCB_ATTR_CEE_APP_TABLE);
14095b7f7626SShmulik Ravid 	if (!app)
141040f5d72aSDan Carpenter 		goto dcb_unlock;
14115b7f7626SShmulik Ravid 
14125b7f7626SShmulik Ravid 	list_for_each_entry(itr, &dcb_app_list, list) {
1413e290ed81SMark Rustad 		if (itr->ifindex == netdev->ifindex) {
1414ae0be8deSMichal Kubecek 			struct nlattr *app_nest = nla_nest_start_noflag(skb,
14155b7f7626SShmulik Ravid 									DCB_ATTR_APP);
14165b7f7626SShmulik Ravid 			if (!app_nest)
14175b7f7626SShmulik Ravid 				goto dcb_unlock;
14185b7f7626SShmulik Ravid 
14195b7f7626SShmulik Ravid 			err = nla_put_u8(skb, DCB_APP_ATTR_IDTYPE,
14205b7f7626SShmulik Ravid 					 itr->app.selector);
14215b7f7626SShmulik Ravid 			if (err)
14225b7f7626SShmulik Ravid 				goto dcb_unlock;
14235b7f7626SShmulik Ravid 
14245b7f7626SShmulik Ravid 			err = nla_put_u16(skb, DCB_APP_ATTR_ID,
14255b7f7626SShmulik Ravid 					  itr->app.protocol);
14265b7f7626SShmulik Ravid 			if (err)
14275b7f7626SShmulik Ravid 				goto dcb_unlock;
14285b7f7626SShmulik Ravid 
14295b7f7626SShmulik Ravid 			err = nla_put_u8(skb, DCB_APP_ATTR_PRIORITY,
14305b7f7626SShmulik Ravid 					 itr->app.priority);
14315b7f7626SShmulik Ravid 			if (err)
14325b7f7626SShmulik Ravid 				goto dcb_unlock;
14335b7f7626SShmulik Ravid 
14345b7f7626SShmulik Ravid 			nla_nest_end(skb, app_nest);
14355b7f7626SShmulik Ravid 		}
14365b7f7626SShmulik Ravid 	}
14375b7f7626SShmulik Ravid 	nla_nest_end(skb, app);
14385b7f7626SShmulik Ravid 
14395b7f7626SShmulik Ravid 	if (netdev->dcbnl_ops->getdcbx)
14405b7f7626SShmulik Ravid 		dcbx = netdev->dcbnl_ops->getdcbx(netdev);
14415b7f7626SShmulik Ravid 	else
14425b7f7626SShmulik Ravid 		dcbx = -EOPNOTSUPP;
14435b7f7626SShmulik Ravid 
144452cff74eSAnish Bhatt 	spin_unlock_bh(&dcb_lock);
14455b7f7626SShmulik Ravid 
14465b7f7626SShmulik Ravid 	/* features flags */
14475b7f7626SShmulik Ravid 	if (ops->getfeatcfg) {
1448ae0be8deSMichal Kubecek 		struct nlattr *feat = nla_nest_start_noflag(skb,
1449ae0be8deSMichal Kubecek 							    DCB_ATTR_CEE_FEAT);
14505b7f7626SShmulik Ravid 		if (!feat)
14515b7f7626SShmulik Ravid 			goto nla_put_failure;
14525b7f7626SShmulik Ravid 
14535b7f7626SShmulik Ravid 		for (i = DCB_FEATCFG_ATTR_ALL + 1; i <= DCB_FEATCFG_ATTR_MAX;
14545b7f7626SShmulik Ravid 		     i++)
14551eb4c977SDavid S. Miller 			if (!ops->getfeatcfg(netdev, i, &value) &&
14561eb4c977SDavid S. Miller 			    nla_put_u8(skb, i, value))
14571eb4c977SDavid S. Miller 				goto nla_put_failure;
14585b7f7626SShmulik Ravid 
14595b7f7626SShmulik Ravid 		nla_nest_end(skb, feat);
14605b7f7626SShmulik Ravid 	}
14615b7f7626SShmulik Ravid 
14625b7f7626SShmulik Ravid 	/* peer info if available */
14635b7f7626SShmulik Ravid 	if (ops->cee_peer_getpg) {
14645b7f7626SShmulik Ravid 		struct cee_pg pg;
146529cd8ae0SMathias Krause 		memset(&pg, 0, sizeof(pg));
14665b7f7626SShmulik Ravid 		err = ops->cee_peer_getpg(netdev, &pg);
14671eb4c977SDavid S. Miller 		if (!err &&
14681eb4c977SDavid S. Miller 		    nla_put(skb, DCB_ATTR_CEE_PEER_PG, sizeof(pg), &pg))
14691eb4c977SDavid S. Miller 			goto nla_put_failure;
14705b7f7626SShmulik Ravid 	}
14715b7f7626SShmulik Ravid 
14725b7f7626SShmulik Ravid 	if (ops->cee_peer_getpfc) {
14735b7f7626SShmulik Ravid 		struct cee_pfc pfc;
147429cd8ae0SMathias Krause 		memset(&pfc, 0, sizeof(pfc));
14755b7f7626SShmulik Ravid 		err = ops->cee_peer_getpfc(netdev, &pfc);
14761eb4c977SDavid S. Miller 		if (!err &&
14771eb4c977SDavid S. Miller 		    nla_put(skb, DCB_ATTR_CEE_PEER_PFC, sizeof(pfc), &pfc))
14781eb4c977SDavid S. Miller 			goto nla_put_failure;
14795b7f7626SShmulik Ravid 	}
14805b7f7626SShmulik Ravid 
14815b7f7626SShmulik Ravid 	if (ops->peer_getappinfo && ops->peer_getapptable) {
14825b7f7626SShmulik Ravid 		err = dcbnl_build_peer_app(netdev, skb,
14835b7f7626SShmulik Ravid 					   DCB_ATTR_CEE_PEER_APP_TABLE,
14845b7f7626SShmulik Ravid 					   DCB_ATTR_CEE_PEER_APP_INFO,
14855b7f7626SShmulik Ravid 					   DCB_ATTR_CEE_PEER_APP);
14865b7f7626SShmulik Ravid 		if (err)
14875b7f7626SShmulik Ravid 			goto nla_put_failure;
14885b7f7626SShmulik Ravid 	}
14895b7f7626SShmulik Ravid 	nla_nest_end(skb, cee);
14905b7f7626SShmulik Ravid 
14915b7f7626SShmulik Ravid 	/* DCBX state */
14925b7f7626SShmulik Ravid 	if (dcbx >= 0) {
14935b7f7626SShmulik Ravid 		err = nla_put_u8(skb, DCB_ATTR_DCBX, dcbx);
14945b7f7626SShmulik Ravid 		if (err)
14955b7f7626SShmulik Ravid 			goto nla_put_failure;
14965b7f7626SShmulik Ravid 	}
14975b7f7626SShmulik Ravid 	return 0;
14985b7f7626SShmulik Ravid 
14995b7f7626SShmulik Ravid dcb_unlock:
150052cff74eSAnish Bhatt 	spin_unlock_bh(&dcb_lock);
15015b7f7626SShmulik Ravid nla_put_failure:
1502c66ebf2dSPan Bian 	err = -EMSGSIZE;
15035b7f7626SShmulik Ravid 	return err;
15045b7f7626SShmulik Ravid }
15055b7f7626SShmulik Ravid 
dcbnl_notify(struct net_device * dev,int event,int cmd,u32 seq,u32 portid,int dcbx_ver)15065b7f7626SShmulik Ravid static int dcbnl_notify(struct net_device *dev, int event, int cmd,
150715e47304SEric W. Biederman 			u32 seq, u32 portid, int dcbx_ver)
1508314b4778SJohn Fastabend {
1509314b4778SJohn Fastabend 	struct net *net = dev_net(dev);
1510314b4778SJohn Fastabend 	struct sk_buff *skb;
1511314b4778SJohn Fastabend 	struct nlmsghdr *nlh;
1512314b4778SJohn Fastabend 	const struct dcbnl_rtnl_ops *ops = dev->dcbnl_ops;
1513314b4778SJohn Fastabend 	int err;
1514314b4778SJohn Fastabend 
1515314b4778SJohn Fastabend 	if (!ops)
1516314b4778SJohn Fastabend 		return -EOPNOTSUPP;
1517314b4778SJohn Fastabend 
151815e47304SEric W. Biederman 	skb = dcbnl_newmsg(event, cmd, portid, seq, 0, &nlh);
1519314b4778SJohn Fastabend 	if (!skb)
1520b923cda9SZheng Yongjun 		return -ENOMEM;
1521314b4778SJohn Fastabend 
15225b7f7626SShmulik Ravid 	if (dcbx_ver == DCB_CAP_DCBX_VER_IEEE)
1523314b4778SJohn Fastabend 		err = dcbnl_ieee_fill(skb, dev);
15245b7f7626SShmulik Ravid 	else
15255b7f7626SShmulik Ravid 		err = dcbnl_cee_fill(skb, dev);
15265b7f7626SShmulik Ravid 
1527314b4778SJohn Fastabend 	if (err < 0) {
1528314b4778SJohn Fastabend 		/* Report error to broadcast listeners */
1529ab6d4707SThomas Graf 		nlmsg_free(skb);
1530314b4778SJohn Fastabend 		rtnl_set_sk_err(net, RTNLGRP_DCB, err);
1531314b4778SJohn Fastabend 	} else {
1532314b4778SJohn Fastabend 		/* End nlmsg and notify broadcast listeners */
1533314b4778SJohn Fastabend 		nlmsg_end(skb, nlh);
1534314b4778SJohn Fastabend 		rtnl_notify(skb, net, 0, RTNLGRP_DCB, NULL, GFP_KERNEL);
1535314b4778SJohn Fastabend 	}
1536314b4778SJohn Fastabend 
1537314b4778SJohn Fastabend 	return err;
1538314b4778SJohn Fastabend }
15395b7f7626SShmulik Ravid 
dcbnl_ieee_notify(struct net_device * dev,int event,int cmd,u32 seq,u32 portid)15405b7f7626SShmulik Ravid int dcbnl_ieee_notify(struct net_device *dev, int event, int cmd,
154115e47304SEric W. Biederman 		      u32 seq, u32 portid)
15425b7f7626SShmulik Ravid {
154315e47304SEric W. Biederman 	return dcbnl_notify(dev, event, cmd, seq, portid, DCB_CAP_DCBX_VER_IEEE);
15445b7f7626SShmulik Ravid }
15455b7f7626SShmulik Ravid EXPORT_SYMBOL(dcbnl_ieee_notify);
15465b7f7626SShmulik Ravid 
dcbnl_cee_notify(struct net_device * dev,int event,int cmd,u32 seq,u32 portid)15475b7f7626SShmulik Ravid int dcbnl_cee_notify(struct net_device *dev, int event, int cmd,
154815e47304SEric W. Biederman 		     u32 seq, u32 portid)
15495b7f7626SShmulik Ravid {
155015e47304SEric W. Biederman 	return dcbnl_notify(dev, event, cmd, seq, portid, DCB_CAP_DCBX_VER_CEE);
15515b7f7626SShmulik Ravid }
15525b7f7626SShmulik Ravid EXPORT_SYMBOL(dcbnl_cee_notify);
1553314b4778SJohn Fastabend 
1554c9368247SShani Michaeli /* Handle IEEE 802.1Qaz/802.1Qau/802.1Qbb SET commands.
1555c9368247SShani Michaeli  * If any requested operation can not be completed
1556c9368247SShani Michaeli  * the entire msg is aborted and error value is returned.
1557314b4778SJohn Fastabend  * No attempt is made to reconcile the case where only part of the
1558314b4778SJohn Fastabend  * cmd can be completed.
1559314b4778SJohn Fastabend  */
dcbnl_ieee_set(struct net_device * netdev,struct nlmsghdr * nlh,u32 seq,struct nlattr ** tb,struct sk_buff * skb)15607be99413SThomas Graf static int dcbnl_ieee_set(struct net_device *netdev, struct nlmsghdr *nlh,
15617be99413SThomas Graf 			  u32 seq, struct nlattr **tb, struct sk_buff *skb)
1562314b4778SJohn Fastabend {
1563314b4778SJohn Fastabend 	const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
1564314b4778SJohn Fastabend 	struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1];
1565297e77e5SPetr Machata 	int prio;
15663d1f4869SThomas Graf 	int err;
1567314b4778SJohn Fastabend 
1568314b4778SJohn Fastabend 	if (!ops)
15693d1f4869SThomas Graf 		return -EOPNOTSUPP;
1570314b4778SJohn Fastabend 
15714003b658SJohn Fastabend 	if (!tb[DCB_ATTR_IEEE])
15724003b658SJohn Fastabend 		return -EINVAL;
15734003b658SJohn Fastabend 
15748cb08174SJohannes Berg 	err = nla_parse_nested_deprecated(ieee, DCB_ATTR_IEEE_MAX,
15758cb08174SJohannes Berg 					  tb[DCB_ATTR_IEEE],
1576fceb6435SJohannes Berg 					  dcbnl_ieee_policy, NULL);
1577314b4778SJohn Fastabend 	if (err)
1578314b4778SJohn Fastabend 		return err;
1579314b4778SJohn Fastabend 
1580314b4778SJohn Fastabend 	if (ieee[DCB_ATTR_IEEE_ETS] && ops->ieee_setets) {
1581314b4778SJohn Fastabend 		struct ieee_ets *ets = nla_data(ieee[DCB_ATTR_IEEE_ETS]);
1582314b4778SJohn Fastabend 		err = ops->ieee_setets(netdev, ets);
1583314b4778SJohn Fastabend 		if (err)
1584314b4778SJohn Fastabend 			goto err;
1585314b4778SJohn Fastabend 	}
1586314b4778SJohn Fastabend 
158708f10affSAmir Vadai 	if (ieee[DCB_ATTR_IEEE_MAXRATE] && ops->ieee_setmaxrate) {
158808f10affSAmir Vadai 		struct ieee_maxrate *maxrate =
158908f10affSAmir Vadai 			nla_data(ieee[DCB_ATTR_IEEE_MAXRATE]);
159008f10affSAmir Vadai 		err = ops->ieee_setmaxrate(netdev, maxrate);
159108f10affSAmir Vadai 		if (err)
159208f10affSAmir Vadai 			goto err;
159308f10affSAmir Vadai 	}
159408f10affSAmir Vadai 
1595c9368247SShani Michaeli 	if (ieee[DCB_ATTR_IEEE_QCN] && ops->ieee_setqcn) {
1596c9368247SShani Michaeli 		struct ieee_qcn *qcn =
1597c9368247SShani Michaeli 			nla_data(ieee[DCB_ATTR_IEEE_QCN]);
1598c9368247SShani Michaeli 
1599c9368247SShani Michaeli 		err = ops->ieee_setqcn(netdev, qcn);
1600c9368247SShani Michaeli 		if (err)
1601c9368247SShani Michaeli 			goto err;
1602c9368247SShani Michaeli 	}
1603c9368247SShani Michaeli 
1604314b4778SJohn Fastabend 	if (ieee[DCB_ATTR_IEEE_PFC] && ops->ieee_setpfc) {
1605314b4778SJohn Fastabend 		struct ieee_pfc *pfc = nla_data(ieee[DCB_ATTR_IEEE_PFC]);
1606314b4778SJohn Fastabend 		err = ops->ieee_setpfc(netdev, pfc);
1607314b4778SJohn Fastabend 		if (err)
1608314b4778SJohn Fastabend 			goto err;
1609314b4778SJohn Fastabend 	}
1610314b4778SJohn Fastabend 
1611e549f6f9SHuy Nguyen 	if (ieee[DCB_ATTR_DCB_BUFFER] && ops->dcbnl_setbuffer) {
1612e549f6f9SHuy Nguyen 		struct dcbnl_buffer *buffer =
1613e549f6f9SHuy Nguyen 			nla_data(ieee[DCB_ATTR_DCB_BUFFER]);
1614e549f6f9SHuy Nguyen 
1615297e77e5SPetr Machata 		for (prio = 0; prio < ARRAY_SIZE(buffer->prio2buffer); prio++) {
1616297e77e5SPetr Machata 			if (buffer->prio2buffer[prio] >= DCBX_MAX_BUFFERS) {
1617297e77e5SPetr Machata 				err = -EINVAL;
1618297e77e5SPetr Machata 				goto err;
1619297e77e5SPetr Machata 			}
1620297e77e5SPetr Machata 		}
1621297e77e5SPetr Machata 
1622e549f6f9SHuy Nguyen 		err = ops->dcbnl_setbuffer(netdev, buffer);
1623e549f6f9SHuy Nguyen 		if (err)
1624e549f6f9SHuy Nguyen 			goto err;
1625e549f6f9SHuy Nguyen 	}
1626e549f6f9SHuy Nguyen 
1627622f1b2fSDaniel Machon 	if (ieee[DCB_ATTR_DCB_REWR_TABLE]) {
1628622f1b2fSDaniel Machon 		err = dcbnl_app_table_setdel(ieee[DCB_ATTR_DCB_REWR_TABLE],
1629622f1b2fSDaniel Machon 					     netdev,
1630622f1b2fSDaniel Machon 					     ops->dcbnl_setrewr ?: dcb_setrewr);
1631622f1b2fSDaniel Machon 		if (err)
1632622f1b2fSDaniel Machon 			goto err;
1633622f1b2fSDaniel Machon 	}
1634622f1b2fSDaniel Machon 
1635314b4778SJohn Fastabend 	if (ieee[DCB_ATTR_IEEE_APP_TABLE]) {
163630568334SDaniel Machon 		err = dcbnl_app_table_setdel(ieee[DCB_ATTR_IEEE_APP_TABLE],
163730568334SDaniel Machon 					     netdev, ops->ieee_setapp ?:
163830568334SDaniel Machon 					     dcb_ieee_setapp);
1639314b4778SJohn Fastabend 		if (err)
1640314b4778SJohn Fastabend 			goto err;
1641314b4778SJohn Fastabend 	}
1642314b4778SJohn Fastabend 
16436182d587SDaniel Machon 	if (ieee[DCB_ATTR_DCB_APP_TRUST_TABLE]) {
16446182d587SDaniel Machon 		u8 selectors[IEEE_8021QAZ_APP_SEL_MAX + 1] = {0};
16456182d587SDaniel Machon 		struct nlattr *attr;
16466182d587SDaniel Machon 		int nselectors = 0;
16476182d587SDaniel Machon 		int rem;
16486182d587SDaniel Machon 
16496182d587SDaniel Machon 		if (!ops->dcbnl_setapptrust) {
16506182d587SDaniel Machon 			err = -EOPNOTSUPP;
16516182d587SDaniel Machon 			goto err;
16526182d587SDaniel Machon 		}
16536182d587SDaniel Machon 
16546182d587SDaniel Machon 		nla_for_each_nested(attr, ieee[DCB_ATTR_DCB_APP_TRUST_TABLE],
16556182d587SDaniel Machon 				    rem) {
16566182d587SDaniel Machon 			enum ieee_attrs_app type = nla_type(attr);
16576182d587SDaniel Machon 			u8 selector;
16586182d587SDaniel Machon 			int i;
16596182d587SDaniel Machon 
16606182d587SDaniel Machon 			if (!dcbnl_app_attr_type_validate(type) ||
16616182d587SDaniel Machon 			    nla_len(attr) != 1 ||
16626182d587SDaniel Machon 			    nselectors >= sizeof(selectors)) {
16636182d587SDaniel Machon 				err = -EINVAL;
16646182d587SDaniel Machon 				goto err;
16656182d587SDaniel Machon 			}
16666182d587SDaniel Machon 
16676182d587SDaniel Machon 			selector = nla_get_u8(attr);
16686182d587SDaniel Machon 
16696182d587SDaniel Machon 			if (!dcbnl_app_selector_validate(type, selector)) {
16706182d587SDaniel Machon 				err = -EINVAL;
16716182d587SDaniel Machon 				goto err;
16726182d587SDaniel Machon 			}
16736182d587SDaniel Machon 
16746182d587SDaniel Machon 			/* Duplicate selector ? */
16756182d587SDaniel Machon 			for (i = 0; i < nselectors; i++) {
16766182d587SDaniel Machon 				if (selectors[i] == selector) {
16776182d587SDaniel Machon 					err = -EINVAL;
16786182d587SDaniel Machon 					goto err;
16796182d587SDaniel Machon 				}
16806182d587SDaniel Machon 			}
16816182d587SDaniel Machon 
16826182d587SDaniel Machon 			selectors[nselectors++] = selector;
16836182d587SDaniel Machon 		}
16846182d587SDaniel Machon 
16856182d587SDaniel Machon 		err = ops->dcbnl_setapptrust(netdev, selectors, nselectors);
16866182d587SDaniel Machon 		if (err)
16876182d587SDaniel Machon 			goto err;
16886182d587SDaniel Machon 	}
16896182d587SDaniel Machon 
1690314b4778SJohn Fastabend err:
16917be99413SThomas Graf 	err = nla_put_u8(skb, DCB_ATTR_IEEE, err);
16925b7f7626SShmulik Ravid 	dcbnl_ieee_notify(netdev, RTM_SETDCB, DCB_CMD_IEEE_SET, seq, 0);
1693314b4778SJohn Fastabend 	return err;
1694314b4778SJohn Fastabend }
1695314b4778SJohn Fastabend 
dcbnl_ieee_get(struct net_device * netdev,struct nlmsghdr * nlh,u32 seq,struct nlattr ** tb,struct sk_buff * skb)16967be99413SThomas Graf static int dcbnl_ieee_get(struct net_device *netdev, struct nlmsghdr *nlh,
16977be99413SThomas Graf 			  u32 seq, struct nlattr **tb, struct sk_buff *skb)
1698314b4778SJohn Fastabend {
1699314b4778SJohn Fastabend 	const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
1700314b4778SJohn Fastabend 
1701314b4778SJohn Fastabend 	if (!ops)
1702314b4778SJohn Fastabend 		return -EOPNOTSUPP;
1703314b4778SJohn Fastabend 
17047be99413SThomas Graf 	return dcbnl_ieee_fill(skb, netdev);
1705314b4778SJohn Fastabend }
1706314b4778SJohn Fastabend 
dcbnl_ieee_del(struct net_device * netdev,struct nlmsghdr * nlh,u32 seq,struct nlattr ** tb,struct sk_buff * skb)17077be99413SThomas Graf static int dcbnl_ieee_del(struct net_device *netdev, struct nlmsghdr *nlh,
17087be99413SThomas Graf 			  u32 seq, struct nlattr **tb, struct sk_buff *skb)
1709f9ae7e4bSJohn Fastabend {
1710f9ae7e4bSJohn Fastabend 	const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
1711f9ae7e4bSJohn Fastabend 	struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1];
17123d1f4869SThomas Graf 	int err;
1713f9ae7e4bSJohn Fastabend 
1714f9ae7e4bSJohn Fastabend 	if (!ops)
1715f9ae7e4bSJohn Fastabend 		return -EOPNOTSUPP;
1716f9ae7e4bSJohn Fastabend 
1717f9ae7e4bSJohn Fastabend 	if (!tb[DCB_ATTR_IEEE])
1718f9ae7e4bSJohn Fastabend 		return -EINVAL;
1719f9ae7e4bSJohn Fastabend 
17208cb08174SJohannes Berg 	err = nla_parse_nested_deprecated(ieee, DCB_ATTR_IEEE_MAX,
17218cb08174SJohannes Berg 					  tb[DCB_ATTR_IEEE],
1722fceb6435SJohannes Berg 					  dcbnl_ieee_policy, NULL);
1723f9ae7e4bSJohn Fastabend 	if (err)
1724f9ae7e4bSJohn Fastabend 		return err;
1725f9ae7e4bSJohn Fastabend 
1726f9ae7e4bSJohn Fastabend 	if (ieee[DCB_ATTR_IEEE_APP_TABLE]) {
172730568334SDaniel Machon 		err = dcbnl_app_table_setdel(ieee[DCB_ATTR_IEEE_APP_TABLE],
172830568334SDaniel Machon 					     netdev, ops->ieee_delapp ?:
172930568334SDaniel Machon 					     dcb_ieee_delapp);
1730f9ae7e4bSJohn Fastabend 		if (err)
1731f9ae7e4bSJohn Fastabend 			goto err;
1732f9ae7e4bSJohn Fastabend 	}
1733f9ae7e4bSJohn Fastabend 
1734622f1b2fSDaniel Machon 	if (ieee[DCB_ATTR_DCB_REWR_TABLE]) {
1735622f1b2fSDaniel Machon 		err = dcbnl_app_table_setdel(ieee[DCB_ATTR_DCB_REWR_TABLE],
1736622f1b2fSDaniel Machon 					     netdev,
1737622f1b2fSDaniel Machon 					     ops->dcbnl_delrewr ?: dcb_delrewr);
1738622f1b2fSDaniel Machon 		if (err)
1739622f1b2fSDaniel Machon 			goto err;
1740622f1b2fSDaniel Machon 	}
1741622f1b2fSDaniel Machon 
1742f9ae7e4bSJohn Fastabend err:
17437be99413SThomas Graf 	err = nla_put_u8(skb, DCB_ATTR_IEEE, err);
17445b7f7626SShmulik Ravid 	dcbnl_ieee_notify(netdev, RTM_SETDCB, DCB_CMD_IEEE_DEL, seq, 0);
1745f9ae7e4bSJohn Fastabend 	return err;
1746f9ae7e4bSJohn Fastabend }
1747f9ae7e4bSJohn Fastabend 
1748f9ae7e4bSJohn Fastabend 
17496241b625SShmulik Ravid /* DCBX configuration */
dcbnl_getdcbx(struct net_device * netdev,struct nlmsghdr * nlh,u32 seq,struct nlattr ** tb,struct sk_buff * skb)17507be99413SThomas Graf static int dcbnl_getdcbx(struct net_device *netdev, struct nlmsghdr *nlh,
17517be99413SThomas Graf 			 u32 seq, struct nlattr **tb, struct sk_buff *skb)
17526241b625SShmulik Ravid {
17536241b625SShmulik Ravid 	if (!netdev->dcbnl_ops->getdcbx)
17547f891cf1SShmulik Ravid 		return -EOPNOTSUPP;
17556241b625SShmulik Ravid 
17567be99413SThomas Graf 	return nla_put_u8(skb, DCB_ATTR_DCBX,
17577be99413SThomas Graf 			  netdev->dcbnl_ops->getdcbx(netdev));
17586241b625SShmulik Ravid }
17596241b625SShmulik Ravid 
dcbnl_setdcbx(struct net_device * netdev,struct nlmsghdr * nlh,u32 seq,struct nlattr ** tb,struct sk_buff * skb)17607be99413SThomas Graf static int dcbnl_setdcbx(struct net_device *netdev, struct nlmsghdr *nlh,
17617be99413SThomas Graf 			 u32 seq, struct nlattr **tb, struct sk_buff *skb)
17626241b625SShmulik Ravid {
17636241b625SShmulik Ravid 	u8 value;
17646241b625SShmulik Ravid 
17657f891cf1SShmulik Ravid 	if (!netdev->dcbnl_ops->setdcbx)
17667f891cf1SShmulik Ravid 		return -EOPNOTSUPP;
17677f891cf1SShmulik Ravid 
17687f891cf1SShmulik Ravid 	if (!tb[DCB_ATTR_DCBX])
17697f891cf1SShmulik Ravid 		return -EINVAL;
17706241b625SShmulik Ravid 
17716241b625SShmulik Ravid 	value = nla_get_u8(tb[DCB_ATTR_DCBX]);
17726241b625SShmulik Ravid 
17737be99413SThomas Graf 	return nla_put_u8(skb, DCB_ATTR_DCBX,
17747be99413SThomas Graf 			  netdev->dcbnl_ops->setdcbx(netdev, value));
17756241b625SShmulik Ravid }
17766241b625SShmulik Ravid 
dcbnl_getfeatcfg(struct net_device * netdev,struct nlmsghdr * nlh,u32 seq,struct nlattr ** tb,struct sk_buff * skb)17777be99413SThomas Graf static int dcbnl_getfeatcfg(struct net_device *netdev, struct nlmsghdr *nlh,
17787be99413SThomas Graf 			    u32 seq, struct nlattr **tb, struct sk_buff *skb)
1779ea45fe4eSShmulik Ravid {
1780ea45fe4eSShmulik Ravid 	struct nlattr *data[DCB_FEATCFG_ATTR_MAX + 1], *nest;
1781ea45fe4eSShmulik Ravid 	u8 value;
17827f891cf1SShmulik Ravid 	int ret, i;
1783ea45fe4eSShmulik Ravid 	int getall = 0;
1784ea45fe4eSShmulik Ravid 
17857f891cf1SShmulik Ravid 	if (!netdev->dcbnl_ops->getfeatcfg)
17867f891cf1SShmulik Ravid 		return -EOPNOTSUPP;
17877f891cf1SShmulik Ravid 
17887f891cf1SShmulik Ravid 	if (!tb[DCB_ATTR_FEATCFG])
17897f891cf1SShmulik Ravid 		return -EINVAL;
1790ea45fe4eSShmulik Ravid 
17918cb08174SJohannes Berg 	ret = nla_parse_nested_deprecated(data, DCB_FEATCFG_ATTR_MAX,
17928cb08174SJohannes Berg 					  tb[DCB_ATTR_FEATCFG],
17938cb08174SJohannes Berg 					  dcbnl_featcfg_nest, NULL);
17947f891cf1SShmulik Ravid 	if (ret)
17957be99413SThomas Graf 		return ret;
1796ea45fe4eSShmulik Ravid 
1797ae0be8deSMichal Kubecek 	nest = nla_nest_start_noflag(skb, DCB_ATTR_FEATCFG);
17987be99413SThomas Graf 	if (!nest)
17997be99413SThomas Graf 		return -EMSGSIZE;
1800ea45fe4eSShmulik Ravid 
1801ea45fe4eSShmulik Ravid 	if (data[DCB_FEATCFG_ATTR_ALL])
1802ea45fe4eSShmulik Ravid 		getall = 1;
1803ea45fe4eSShmulik Ravid 
1804ea45fe4eSShmulik Ravid 	for (i = DCB_FEATCFG_ATTR_ALL+1; i <= DCB_FEATCFG_ATTR_MAX; i++) {
1805ea45fe4eSShmulik Ravid 		if (!getall && !data[i])
1806ea45fe4eSShmulik Ravid 			continue;
1807ea45fe4eSShmulik Ravid 
1808ea45fe4eSShmulik Ravid 		ret = netdev->dcbnl_ops->getfeatcfg(netdev, i, &value);
18097f891cf1SShmulik Ravid 		if (!ret)
18107be99413SThomas Graf 			ret = nla_put_u8(skb, i, value);
1811ea45fe4eSShmulik Ravid 
1812ea45fe4eSShmulik Ravid 		if (ret) {
18137be99413SThomas Graf 			nla_nest_cancel(skb, nest);
18147f891cf1SShmulik Ravid 			goto nla_put_failure;
1815ea45fe4eSShmulik Ravid 		}
1816ea45fe4eSShmulik Ravid 	}
18177be99413SThomas Graf 	nla_nest_end(skb, nest);
1818ea45fe4eSShmulik Ravid 
18197f891cf1SShmulik Ravid nla_put_failure:
1820ea45fe4eSShmulik Ravid 	return ret;
1821ea45fe4eSShmulik Ravid }
1822ea45fe4eSShmulik Ravid 
dcbnl_setfeatcfg(struct net_device * netdev,struct nlmsghdr * nlh,u32 seq,struct nlattr ** tb,struct sk_buff * skb)18237be99413SThomas Graf static int dcbnl_setfeatcfg(struct net_device *netdev, struct nlmsghdr *nlh,
18247be99413SThomas Graf 			    u32 seq, struct nlattr **tb, struct sk_buff *skb)
1825ea45fe4eSShmulik Ravid {
1826ea45fe4eSShmulik Ravid 	struct nlattr *data[DCB_FEATCFG_ATTR_MAX + 1];
18277f891cf1SShmulik Ravid 	int ret, i;
1828ea45fe4eSShmulik Ravid 	u8 value;
1829ea45fe4eSShmulik Ravid 
18307f891cf1SShmulik Ravid 	if (!netdev->dcbnl_ops->setfeatcfg)
18317f891cf1SShmulik Ravid 		return -ENOTSUPP;
18327f891cf1SShmulik Ravid 
18337f891cf1SShmulik Ravid 	if (!tb[DCB_ATTR_FEATCFG])
18347f891cf1SShmulik Ravid 		return -EINVAL;
1835ea45fe4eSShmulik Ravid 
18368cb08174SJohannes Berg 	ret = nla_parse_nested_deprecated(data, DCB_FEATCFG_ATTR_MAX,
18378cb08174SJohannes Berg 					  tb[DCB_ATTR_FEATCFG],
18388cb08174SJohannes Berg 					  dcbnl_featcfg_nest, NULL);
1839ea45fe4eSShmulik Ravid 
18407f891cf1SShmulik Ravid 	if (ret)
1841ea45fe4eSShmulik Ravid 		goto err;
1842ea45fe4eSShmulik Ravid 
1843ea45fe4eSShmulik Ravid 	for (i = DCB_FEATCFG_ATTR_ALL+1; i <= DCB_FEATCFG_ATTR_MAX; i++) {
1844ea45fe4eSShmulik Ravid 		if (data[i] == NULL)
1845ea45fe4eSShmulik Ravid 			continue;
1846ea45fe4eSShmulik Ravid 
1847ea45fe4eSShmulik Ravid 		value = nla_get_u8(data[i]);
1848ea45fe4eSShmulik Ravid 
1849ea45fe4eSShmulik Ravid 		ret = netdev->dcbnl_ops->setfeatcfg(netdev, i, value);
1850ea45fe4eSShmulik Ravid 
1851ea45fe4eSShmulik Ravid 		if (ret)
18527f891cf1SShmulik Ravid 			goto err;
1853ea45fe4eSShmulik Ravid 	}
1854ea45fe4eSShmulik Ravid err:
18557be99413SThomas Graf 	ret = nla_put_u8(skb, DCB_ATTR_FEATCFG, ret);
18567f891cf1SShmulik Ravid 
1857ea45fe4eSShmulik Ravid 	return ret;
1858ea45fe4eSShmulik Ravid }
1859ea45fe4eSShmulik Ravid 
1860dc6ed1dfSShmulik Ravid /* Handle CEE DCBX GET commands. */
dcbnl_cee_get(struct net_device * netdev,struct nlmsghdr * nlh,u32 seq,struct nlattr ** tb,struct sk_buff * skb)18617be99413SThomas Graf static int dcbnl_cee_get(struct net_device *netdev, struct nlmsghdr *nlh,
18627be99413SThomas Graf 			 u32 seq, struct nlattr **tb, struct sk_buff *skb)
1863dc6ed1dfSShmulik Ravid {
1864dc6ed1dfSShmulik Ravid 	const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
1865dc6ed1dfSShmulik Ravid 
1866dc6ed1dfSShmulik Ravid 	if (!ops)
1867dc6ed1dfSShmulik Ravid 		return -EOPNOTSUPP;
1868dc6ed1dfSShmulik Ravid 
18697be99413SThomas Graf 	return dcbnl_cee_fill(skb, netdev);
1870dc6ed1dfSShmulik Ravid }
1871dc6ed1dfSShmulik Ravid 
187233a03aadSThomas Graf struct reply_func {
187333a03aadSThomas Graf 	/* reply netlink message type */
187433a03aadSThomas Graf 	int	type;
187533a03aadSThomas Graf 
187633a03aadSThomas Graf 	/* function to fill message contents */
187733a03aadSThomas Graf 	int   (*cb)(struct net_device *, struct nlmsghdr *, u32,
187833a03aadSThomas Graf 		    struct nlattr **, struct sk_buff *);
187933a03aadSThomas Graf };
188033a03aadSThomas Graf 
188133a03aadSThomas Graf static const struct reply_func reply_funcs[DCB_CMD_MAX+1] = {
18827be99413SThomas Graf 	[DCB_CMD_GSTATE]	= { RTM_GETDCB, dcbnl_getstate },
18837be99413SThomas Graf 	[DCB_CMD_SSTATE]	= { RTM_SETDCB, dcbnl_setstate },
18847be99413SThomas Graf 	[DCB_CMD_PFC_GCFG]	= { RTM_GETDCB, dcbnl_getpfccfg },
18857be99413SThomas Graf 	[DCB_CMD_PFC_SCFG]	= { RTM_SETDCB, dcbnl_setpfccfg },
18867be99413SThomas Graf 	[DCB_CMD_GPERM_HWADDR]	= { RTM_GETDCB, dcbnl_getperm_hwaddr },
18877be99413SThomas Graf 	[DCB_CMD_GCAP]		= { RTM_GETDCB, dcbnl_getcap },
18887be99413SThomas Graf 	[DCB_CMD_GNUMTCS]	= { RTM_GETDCB, dcbnl_getnumtcs },
18897be99413SThomas Graf 	[DCB_CMD_SNUMTCS]	= { RTM_SETDCB, dcbnl_setnumtcs },
18907be99413SThomas Graf 	[DCB_CMD_PFC_GSTATE]	= { RTM_GETDCB, dcbnl_getpfcstate },
18917be99413SThomas Graf 	[DCB_CMD_PFC_SSTATE]	= { RTM_SETDCB, dcbnl_setpfcstate },
18927be99413SThomas Graf 	[DCB_CMD_GAPP]		= { RTM_GETDCB, dcbnl_getapp },
18937be99413SThomas Graf 	[DCB_CMD_SAPP]		= { RTM_SETDCB, dcbnl_setapp },
18947be99413SThomas Graf 	[DCB_CMD_PGTX_GCFG]	= { RTM_GETDCB, dcbnl_pgtx_getcfg },
18957be99413SThomas Graf 	[DCB_CMD_PGTX_SCFG]	= { RTM_SETDCB, dcbnl_pgtx_setcfg },
18967be99413SThomas Graf 	[DCB_CMD_PGRX_GCFG]	= { RTM_GETDCB, dcbnl_pgrx_getcfg },
18977be99413SThomas Graf 	[DCB_CMD_PGRX_SCFG]	= { RTM_SETDCB, dcbnl_pgrx_setcfg },
18987be99413SThomas Graf 	[DCB_CMD_SET_ALL]	= { RTM_SETDCB, dcbnl_setall },
18997be99413SThomas Graf 	[DCB_CMD_BCN_GCFG]	= { RTM_GETDCB, dcbnl_bcn_getcfg },
19007be99413SThomas Graf 	[DCB_CMD_BCN_SCFG]	= { RTM_SETDCB, dcbnl_bcn_setcfg },
19017be99413SThomas Graf 	[DCB_CMD_IEEE_GET]	= { RTM_GETDCB, dcbnl_ieee_get },
19027be99413SThomas Graf 	[DCB_CMD_IEEE_SET]	= { RTM_SETDCB, dcbnl_ieee_set },
19037be99413SThomas Graf 	[DCB_CMD_IEEE_DEL]	= { RTM_SETDCB, dcbnl_ieee_del },
19047be99413SThomas Graf 	[DCB_CMD_GDCBX]		= { RTM_GETDCB, dcbnl_getdcbx },
19057be99413SThomas Graf 	[DCB_CMD_SDCBX]		= { RTM_SETDCB, dcbnl_setdcbx },
19067be99413SThomas Graf 	[DCB_CMD_GFEATCFG]	= { RTM_GETDCB, dcbnl_getfeatcfg },
19077be99413SThomas Graf 	[DCB_CMD_SFEATCFG]	= { RTM_SETDCB, dcbnl_setfeatcfg },
19087be99413SThomas Graf 	[DCB_CMD_CEE_GET]	= { RTM_GETDCB, dcbnl_cee_get },
190933a03aadSThomas Graf };
191033a03aadSThomas Graf 
dcb_doit(struct sk_buff * skb,struct nlmsghdr * nlh,struct netlink_ext_ack * extack)1911c21ef3e3SDavid Ahern static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
1912c21ef3e3SDavid Ahern 		    struct netlink_ext_ack *extack)
19132f90b865SAlexander Duyck {
19142f90b865SAlexander Duyck 	struct net *net = sock_net(skb->sk);
19152f90b865SAlexander Duyck 	struct net_device *netdev;
19167a282bc3SThomas Graf 	struct dcbmsg *dcb = nlmsg_data(nlh);
19172f90b865SAlexander Duyck 	struct nlattr *tb[DCB_ATTR_MAX + 1];
19180cc55e69SGaurav Singh 	u32 portid = NETLINK_CB(skb).portid;
19192f90b865SAlexander Duyck 	int ret = -EINVAL;
192033a03aadSThomas Graf 	struct sk_buff *reply_skb;
192139912f9cSThomas Graf 	struct nlmsghdr *reply_nlh = NULL;
192233a03aadSThomas Graf 	const struct reply_func *fn;
19232f90b865SAlexander Duyck 
192490f62cf3SEric W. Biederman 	if ((nlh->nlmsg_type == RTM_SETDCB) && !netlink_capable(skb, CAP_NET_ADMIN))
1925dfc47ef8SEric W. Biederman 		return -EPERM;
1926dfc47ef8SEric W. Biederman 
19278cb08174SJohannes Berg 	ret = nlmsg_parse_deprecated(nlh, sizeof(*dcb), tb, DCB_ATTR_MAX,
1928c21ef3e3SDavid Ahern 				     dcbnl_rtnl_policy, extack);
19292f90b865SAlexander Duyck 	if (ret < 0)
19302f90b865SAlexander Duyck 		return ret;
19312f90b865SAlexander Duyck 
193233a03aadSThomas Graf 	if (dcb->cmd > DCB_CMD_MAX)
193333a03aadSThomas Graf 		return -EINVAL;
193433a03aadSThomas Graf 
193533a03aadSThomas Graf 	/* check if a reply function has been defined for the command */
193633a03aadSThomas Graf 	fn = &reply_funcs[dcb->cmd];
193733a03aadSThomas Graf 	if (!fn->cb)
193833a03aadSThomas Graf 		return -EOPNOTSUPP;
1939df85bc14SPetr Machata 	if (fn->type == RTM_SETDCB && !netlink_capable(skb, CAP_NET_ADMIN))
1940826f328eSPetr Machata 		return -EPERM;
194133a03aadSThomas Graf 
19422f90b865SAlexander Duyck 	if (!tb[DCB_ATTR_IFNAME])
19432f90b865SAlexander Duyck 		return -EINVAL;
19442f90b865SAlexander Duyck 
1945d9ac62beSYing Xue 	netdev = __dev_get_by_name(net, nla_data(tb[DCB_ATTR_IFNAME]));
19462f90b865SAlexander Duyck 	if (!netdev)
19473d1f4869SThomas Graf 		return -ENODEV;
19482f90b865SAlexander Duyck 
1949d9ac62beSYing Xue 	if (!netdev->dcbnl_ops)
1950d9ac62beSYing Xue 		return -EOPNOTSUPP;
19512f90b865SAlexander Duyck 
195215e47304SEric W. Biederman 	reply_skb = dcbnl_newmsg(fn->type, dcb->cmd, portid, nlh->nlmsg_seq,
195333a03aadSThomas Graf 				 nlh->nlmsg_flags, &reply_nlh);
1954d9ac62beSYing Xue 	if (!reply_skb)
1955b923cda9SZheng Yongjun 		return -ENOMEM;
195633a03aadSThomas Graf 
195733a03aadSThomas Graf 	ret = fn->cb(netdev, nlh, nlh->nlmsg_seq, tb, reply_skb);
195833a03aadSThomas Graf 	if (ret < 0) {
195933a03aadSThomas Graf 		nlmsg_free(reply_skb);
196033a03aadSThomas Graf 		goto out;
196133a03aadSThomas Graf 	}
196233a03aadSThomas Graf 
196333a03aadSThomas Graf 	nlmsg_end(reply_skb, reply_nlh);
196433a03aadSThomas Graf 
19657c77ab24SJohn Fastabend 	ret = rtnl_unicast(reply_skb, net, portid);
19662f90b865SAlexander Duyck out:
19672f90b865SAlexander Duyck 	return ret;
19682f90b865SAlexander Duyck }
19692f90b865SAlexander Duyck 
dcb_rewr_lookup(const struct dcb_app * app,int ifindex,int proto)1970622f1b2fSDaniel Machon static struct dcb_app_type *dcb_rewr_lookup(const struct dcb_app *app,
1971622f1b2fSDaniel Machon 					    int ifindex, int proto)
1972622f1b2fSDaniel Machon {
1973622f1b2fSDaniel Machon 	struct dcb_app_type *itr;
1974622f1b2fSDaniel Machon 
1975622f1b2fSDaniel Machon 	list_for_each_entry(itr, &dcb_rewr_list, list) {
1976622f1b2fSDaniel Machon 		if (itr->app.selector == app->selector &&
1977622f1b2fSDaniel Machon 		    itr->app.priority == app->priority &&
1978622f1b2fSDaniel Machon 		    itr->ifindex == ifindex &&
1979622f1b2fSDaniel Machon 		    ((proto == -1) || itr->app.protocol == proto))
1980622f1b2fSDaniel Machon 			return itr;
1981622f1b2fSDaniel Machon 	}
1982622f1b2fSDaniel Machon 
1983622f1b2fSDaniel Machon 	return NULL;
1984622f1b2fSDaniel Machon }
1985622f1b2fSDaniel Machon 
dcb_app_lookup(const struct dcb_app * app,int ifindex,int prio)1986716b31abSThomas Graf static struct dcb_app_type *dcb_app_lookup(const struct dcb_app *app,
1987716b31abSThomas Graf 					   int ifindex, int prio)
1988716b31abSThomas Graf {
1989716b31abSThomas Graf 	struct dcb_app_type *itr;
1990716b31abSThomas Graf 
1991716b31abSThomas Graf 	list_for_each_entry(itr, &dcb_app_list, list) {
1992716b31abSThomas Graf 		if (itr->app.selector == app->selector &&
1993716b31abSThomas Graf 		    itr->app.protocol == app->protocol &&
1994716b31abSThomas Graf 		    itr->ifindex == ifindex &&
199508193d1aSPetr Machata 		    ((prio == -1) || itr->app.priority == prio))
1996716b31abSThomas Graf 			return itr;
1997716b31abSThomas Graf 	}
1998716b31abSThomas Graf 
1999716b31abSThomas Graf 	return NULL;
2000716b31abSThomas Graf }
2001716b31abSThomas Graf 
dcb_app_add(struct list_head * list,const struct dcb_app * app,int ifindex)200234b7074dSDaniel Machon static int dcb_app_add(struct list_head *list, const struct dcb_app *app,
200334b7074dSDaniel Machon 		       int ifindex)
20044e4f2f69SThomas Graf {
20054e4f2f69SThomas Graf 	struct dcb_app_type *entry;
20064e4f2f69SThomas Graf 
20074e4f2f69SThomas Graf 	entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
20084e4f2f69SThomas Graf 	if (!entry)
20094e4f2f69SThomas Graf 		return -ENOMEM;
20104e4f2f69SThomas Graf 
20114e4f2f69SThomas Graf 	memcpy(&entry->app, app, sizeof(*app));
20124e4f2f69SThomas Graf 	entry->ifindex = ifindex;
201334b7074dSDaniel Machon 	list_add(&entry->list, list);
20144e4f2f69SThomas Graf 
20154e4f2f69SThomas Graf 	return 0;
20164e4f2f69SThomas Graf }
20174e4f2f69SThomas Graf 
20189ab933abSJohn Fastabend /**
20199ab933abSJohn Fastabend  * dcb_getapp - retrieve the DCBX application user priority
2020a89a501cSAndrew Lunn  * @dev: network interface
2021a89a501cSAndrew Lunn  * @app: application to get user priority of
20229ab933abSJohn Fastabend  *
20239ab933abSJohn Fastabend  * On success returns a non-zero 802.1p user priority bitmap
20249ab933abSJohn Fastabend  * otherwise returns 0 as the invalid user priority bitmap to
20259ab933abSJohn Fastabend  * indicate an error.
20269ab933abSJohn Fastabend  */
dcb_getapp(struct net_device * dev,struct dcb_app * app)20279ab933abSJohn Fastabend u8 dcb_getapp(struct net_device *dev, struct dcb_app *app)
20289ab933abSJohn Fastabend {
20299ab933abSJohn Fastabend 	struct dcb_app_type *itr;
20309ab933abSJohn Fastabend 	u8 prio = 0;
20319ab933abSJohn Fastabend 
203252cff74eSAnish Bhatt 	spin_lock_bh(&dcb_lock);
203308193d1aSPetr Machata 	itr = dcb_app_lookup(app, dev->ifindex, -1);
203408193d1aSPetr Machata 	if (itr)
20359ab933abSJohn Fastabend 		prio = itr->app.priority;
203652cff74eSAnish Bhatt 	spin_unlock_bh(&dcb_lock);
20379ab933abSJohn Fastabend 
20389ab933abSJohn Fastabend 	return prio;
20399ab933abSJohn Fastabend }
20409ab933abSJohn Fastabend EXPORT_SYMBOL(dcb_getapp);
20419ab933abSJohn Fastabend 
20429ab933abSJohn Fastabend /**
2043b6db2174SJohn Fastabend  * dcb_setapp - add CEE dcb application data to app list
2044a89a501cSAndrew Lunn  * @dev: network interface
2045a89a501cSAndrew Lunn  * @new: application data to add
20469ab933abSJohn Fastabend  *
2047b6db2174SJohn Fastabend  * Priority 0 is an invalid priority in CEE spec. This routine
2048b6db2174SJohn Fastabend  * removes applications from the app list if the priority is
204916eecd9bSAnish Bhatt  * set to zero. Priority is expected to be 8-bit 802.1p user priority bitmap
20509ab933abSJohn Fastabend  */
dcb_setapp(struct net_device * dev,struct dcb_app * new)2051ab6baf98SJohn Fastabend int dcb_setapp(struct net_device *dev, struct dcb_app *new)
20529ab933abSJohn Fastabend {
20539ab933abSJohn Fastabend 	struct dcb_app_type *itr;
20547ec79270SJohn Fastabend 	struct dcb_app_type event;
20554e4f2f69SThomas Graf 	int err = 0;
20567ec79270SJohn Fastabend 
2057e290ed81SMark Rustad 	event.ifindex = dev->ifindex;
20587ec79270SJohn Fastabend 	memcpy(&event.app, new, sizeof(event.app));
20596bd0e1cbSJohn Fastabend 	if (dev->dcbnl_ops->getdcbx)
20606bd0e1cbSJohn Fastabend 		event.dcbx = dev->dcbnl_ops->getdcbx(dev);
20619ab933abSJohn Fastabend 
206252cff74eSAnish Bhatt 	spin_lock_bh(&dcb_lock);
20639ab933abSJohn Fastabend 	/* Search for existing match and replace */
206408193d1aSPetr Machata 	itr = dcb_app_lookup(new, dev->ifindex, -1);
206508193d1aSPetr Machata 	if (itr) {
20669ab933abSJohn Fastabend 		if (new->priority)
20679ab933abSJohn Fastabend 			itr->app.priority = new->priority;
20689ab933abSJohn Fastabend 		else {
20699ab933abSJohn Fastabend 			list_del(&itr->list);
20709ab933abSJohn Fastabend 			kfree(itr);
20719ab933abSJohn Fastabend 		}
20729ab933abSJohn Fastabend 		goto out;
20739ab933abSJohn Fastabend 	}
20749ab933abSJohn Fastabend 	/* App type does not exist add new application type */
20754e4f2f69SThomas Graf 	if (new->priority)
207634b7074dSDaniel Machon 		err = dcb_app_add(&dcb_app_list, new, dev->ifindex);
20779ab933abSJohn Fastabend out:
207852cff74eSAnish Bhatt 	spin_unlock_bh(&dcb_lock);
20794e4f2f69SThomas Graf 	if (!err)
20807ec79270SJohn Fastabend 		call_dcbevent_notifiers(DCB_APP_EVENT, &event);
20814e4f2f69SThomas Graf 	return err;
20829ab933abSJohn Fastabend }
20839ab933abSJohn Fastabend EXPORT_SYMBOL(dcb_setapp);
20849ab933abSJohn Fastabend 
2085b6db2174SJohn Fastabend /**
2086a364c8cfSJohn Fastabend  * dcb_ieee_getapp_mask - retrieve the IEEE DCB application priority
2087a89a501cSAndrew Lunn  * @dev: network interface
2088a89a501cSAndrew Lunn  * @app: where to store the retrieve application data
2089a364c8cfSJohn Fastabend  *
2090a364c8cfSJohn Fastabend  * Helper routine which on success returns a non-zero 802.1Qaz user
2091a364c8cfSJohn Fastabend  * priority bitmap otherwise returns 0 to indicate the dcb_app was
2092a364c8cfSJohn Fastabend  * not found in APP list.
2093a364c8cfSJohn Fastabend  */
dcb_ieee_getapp_mask(struct net_device * dev,struct dcb_app * app)2094a364c8cfSJohn Fastabend u8 dcb_ieee_getapp_mask(struct net_device *dev, struct dcb_app *app)
2095a364c8cfSJohn Fastabend {
2096a364c8cfSJohn Fastabend 	struct dcb_app_type *itr;
2097a364c8cfSJohn Fastabend 	u8 prio = 0;
2098a364c8cfSJohn Fastabend 
209952cff74eSAnish Bhatt 	spin_lock_bh(&dcb_lock);
210008193d1aSPetr Machata 	itr = dcb_app_lookup(app, dev->ifindex, -1);
210108193d1aSPetr Machata 	if (itr)
2102a364c8cfSJohn Fastabend 		prio |= 1 << itr->app.priority;
210352cff74eSAnish Bhatt 	spin_unlock_bh(&dcb_lock);
2104a364c8cfSJohn Fastabend 
2105a364c8cfSJohn Fastabend 	return prio;
2106a364c8cfSJohn Fastabend }
2107a364c8cfSJohn Fastabend EXPORT_SYMBOL(dcb_ieee_getapp_mask);
2108a364c8cfSJohn Fastabend 
2109622f1b2fSDaniel Machon /* Get protocol value from rewrite entry. */
dcb_getrewr(struct net_device * dev,struct dcb_app * app)2110622f1b2fSDaniel Machon u16 dcb_getrewr(struct net_device *dev, struct dcb_app *app)
2111622f1b2fSDaniel Machon {
2112622f1b2fSDaniel Machon 	struct dcb_app_type *itr;
2113622f1b2fSDaniel Machon 	u16 proto = 0;
2114622f1b2fSDaniel Machon 
2115622f1b2fSDaniel Machon 	spin_lock_bh(&dcb_lock);
2116622f1b2fSDaniel Machon 	itr = dcb_rewr_lookup(app, dev->ifindex, -1);
2117622f1b2fSDaniel Machon 	if (itr)
2118622f1b2fSDaniel Machon 		proto = itr->app.protocol;
2119622f1b2fSDaniel Machon 	spin_unlock_bh(&dcb_lock);
2120622f1b2fSDaniel Machon 
2121622f1b2fSDaniel Machon 	return proto;
2122622f1b2fSDaniel Machon }
2123622f1b2fSDaniel Machon EXPORT_SYMBOL(dcb_getrewr);
2124622f1b2fSDaniel Machon 
2125622f1b2fSDaniel Machon  /* Add rewrite entry to the rewrite list. */
dcb_setrewr(struct net_device * dev,struct dcb_app * new)2126622f1b2fSDaniel Machon int dcb_setrewr(struct net_device *dev, struct dcb_app *new)
2127622f1b2fSDaniel Machon {
2128622f1b2fSDaniel Machon 	int err;
2129622f1b2fSDaniel Machon 
2130622f1b2fSDaniel Machon 	spin_lock_bh(&dcb_lock);
2131622f1b2fSDaniel Machon 	/* Search for existing match and abort if found. */
2132622f1b2fSDaniel Machon 	if (dcb_rewr_lookup(new, dev->ifindex, new->protocol)) {
2133622f1b2fSDaniel Machon 		err = -EEXIST;
2134622f1b2fSDaniel Machon 		goto out;
2135622f1b2fSDaniel Machon 	}
2136622f1b2fSDaniel Machon 
2137622f1b2fSDaniel Machon 	err = dcb_app_add(&dcb_rewr_list, new, dev->ifindex);
2138622f1b2fSDaniel Machon out:
2139622f1b2fSDaniel Machon 	spin_unlock_bh(&dcb_lock);
2140622f1b2fSDaniel Machon 
2141622f1b2fSDaniel Machon 	return err;
2142622f1b2fSDaniel Machon }
2143622f1b2fSDaniel Machon EXPORT_SYMBOL(dcb_setrewr);
2144622f1b2fSDaniel Machon 
2145622f1b2fSDaniel Machon /* Delete rewrite entry from the rewrite list. */
dcb_delrewr(struct net_device * dev,struct dcb_app * del)2146622f1b2fSDaniel Machon int dcb_delrewr(struct net_device *dev, struct dcb_app *del)
2147622f1b2fSDaniel Machon {
2148622f1b2fSDaniel Machon 	struct dcb_app_type *itr;
2149622f1b2fSDaniel Machon 	int err = -ENOENT;
2150622f1b2fSDaniel Machon 
2151622f1b2fSDaniel Machon 	spin_lock_bh(&dcb_lock);
2152622f1b2fSDaniel Machon 	/* Search for existing match and remove it. */
2153622f1b2fSDaniel Machon 	itr = dcb_rewr_lookup(del, dev->ifindex, del->protocol);
2154622f1b2fSDaniel Machon 	if (itr) {
2155622f1b2fSDaniel Machon 		list_del(&itr->list);
2156622f1b2fSDaniel Machon 		kfree(itr);
2157622f1b2fSDaniel Machon 		err = 0;
2158622f1b2fSDaniel Machon 	}
2159622f1b2fSDaniel Machon 
2160622f1b2fSDaniel Machon 	spin_unlock_bh(&dcb_lock);
2161622f1b2fSDaniel Machon 
2162622f1b2fSDaniel Machon 	return err;
2163622f1b2fSDaniel Machon }
2164622f1b2fSDaniel Machon EXPORT_SYMBOL(dcb_delrewr);
2165622f1b2fSDaniel Machon 
2166a364c8cfSJohn Fastabend /**
2167b6db2174SJohn Fastabend  * dcb_ieee_setapp - add IEEE dcb application data to app list
2168a89a501cSAndrew Lunn  * @dev: network interface
2169a89a501cSAndrew Lunn  * @new: application data to add
2170b6db2174SJohn Fastabend  *
2171b6db2174SJohn Fastabend  * This adds Application data to the list. Multiple application
2172b6db2174SJohn Fastabend  * entries may exists for the same selector and protocol as long
217316eecd9bSAnish Bhatt  * as the priorities are different. Priority is expected to be a
217416eecd9bSAnish Bhatt  * 3-bit unsigned integer
2175b6db2174SJohn Fastabend  */
dcb_ieee_setapp(struct net_device * dev,struct dcb_app * new)2176b6db2174SJohn Fastabend int dcb_ieee_setapp(struct net_device *dev, struct dcb_app *new)
2177b6db2174SJohn Fastabend {
2178b6db2174SJohn Fastabend 	struct dcb_app_type event;
2179b6db2174SJohn Fastabend 	int err = 0;
2180b6db2174SJohn Fastabend 
2181e290ed81SMark Rustad 	event.ifindex = dev->ifindex;
2182b6db2174SJohn Fastabend 	memcpy(&event.app, new, sizeof(event.app));
21836bd0e1cbSJohn Fastabend 	if (dev->dcbnl_ops->getdcbx)
21846bd0e1cbSJohn Fastabend 		event.dcbx = dev->dcbnl_ops->getdcbx(dev);
2185b6db2174SJohn Fastabend 
218652cff74eSAnish Bhatt 	spin_lock_bh(&dcb_lock);
2187b6db2174SJohn Fastabend 	/* Search for existing match and abort if found */
2188716b31abSThomas Graf 	if (dcb_app_lookup(new, dev->ifindex, new->priority)) {
2189b6db2174SJohn Fastabend 		err = -EEXIST;
2190b6db2174SJohn Fastabend 		goto out;
2191b6db2174SJohn Fastabend 	}
2192b6db2174SJohn Fastabend 
219334b7074dSDaniel Machon 	err = dcb_app_add(&dcb_app_list, new, dev->ifindex);
2194b6db2174SJohn Fastabend out:
219552cff74eSAnish Bhatt 	spin_unlock_bh(&dcb_lock);
2196b6db2174SJohn Fastabend 	if (!err)
2197b6db2174SJohn Fastabend 		call_dcbevent_notifiers(DCB_APP_EVENT, &event);
2198b6db2174SJohn Fastabend 	return err;
2199b6db2174SJohn Fastabend }
2200b6db2174SJohn Fastabend EXPORT_SYMBOL(dcb_ieee_setapp);
2201b6db2174SJohn Fastabend 
2202f9ae7e4bSJohn Fastabend /**
2203f9ae7e4bSJohn Fastabend  * dcb_ieee_delapp - delete IEEE dcb application data from list
2204a89a501cSAndrew Lunn  * @dev: network interface
2205a89a501cSAndrew Lunn  * @del: application data to delete
2206f9ae7e4bSJohn Fastabend  *
2207f9ae7e4bSJohn Fastabend  * This removes a matching APP data from the APP list
2208f9ae7e4bSJohn Fastabend  */
dcb_ieee_delapp(struct net_device * dev,struct dcb_app * del)2209f9ae7e4bSJohn Fastabend int dcb_ieee_delapp(struct net_device *dev, struct dcb_app *del)
2210f9ae7e4bSJohn Fastabend {
2211f9ae7e4bSJohn Fastabend 	struct dcb_app_type *itr;
2212f9ae7e4bSJohn Fastabend 	struct dcb_app_type event;
2213f9ae7e4bSJohn Fastabend 	int err = -ENOENT;
2214f9ae7e4bSJohn Fastabend 
2215e290ed81SMark Rustad 	event.ifindex = dev->ifindex;
2216f9ae7e4bSJohn Fastabend 	memcpy(&event.app, del, sizeof(event.app));
22176bd0e1cbSJohn Fastabend 	if (dev->dcbnl_ops->getdcbx)
22186bd0e1cbSJohn Fastabend 		event.dcbx = dev->dcbnl_ops->getdcbx(dev);
2219f9ae7e4bSJohn Fastabend 
222052cff74eSAnish Bhatt 	spin_lock_bh(&dcb_lock);
2221f9ae7e4bSJohn Fastabend 	/* Search for existing match and remove it. */
2222716b31abSThomas Graf 	if ((itr = dcb_app_lookup(del, dev->ifindex, del->priority))) {
2223f9ae7e4bSJohn Fastabend 		list_del(&itr->list);
2224f9ae7e4bSJohn Fastabend 		kfree(itr);
2225f9ae7e4bSJohn Fastabend 		err = 0;
2226f9ae7e4bSJohn Fastabend 	}
2227f9ae7e4bSJohn Fastabend 
222852cff74eSAnish Bhatt 	spin_unlock_bh(&dcb_lock);
2229f9ae7e4bSJohn Fastabend 	if (!err)
2230f9ae7e4bSJohn Fastabend 		call_dcbevent_notifiers(DCB_APP_EVENT, &event);
2231f9ae7e4bSJohn Fastabend 	return err;
2232f9ae7e4bSJohn Fastabend }
2233f9ae7e4bSJohn Fastabend EXPORT_SYMBOL(dcb_ieee_delapp);
2234f9ae7e4bSJohn Fastabend 
22351df99338SDaniel Machon /* dcb_getrewr_prio_pcp_mask_map - For a given device, find mapping from
22361df99338SDaniel Machon  * priorities to the PCP and DEI values assigned to that priority.
22371df99338SDaniel Machon  */
dcb_getrewr_prio_pcp_mask_map(const struct net_device * dev,struct dcb_rewr_prio_pcp_map * p_map)22381df99338SDaniel Machon void dcb_getrewr_prio_pcp_mask_map(const struct net_device *dev,
22391df99338SDaniel Machon 				   struct dcb_rewr_prio_pcp_map *p_map)
22401df99338SDaniel Machon {
22411df99338SDaniel Machon 	int ifindex = dev->ifindex;
22421df99338SDaniel Machon 	struct dcb_app_type *itr;
22431df99338SDaniel Machon 	u8 prio;
22441df99338SDaniel Machon 
22451df99338SDaniel Machon 	memset(p_map->map, 0, sizeof(p_map->map));
22461df99338SDaniel Machon 
22471df99338SDaniel Machon 	spin_lock_bh(&dcb_lock);
22481df99338SDaniel Machon 	list_for_each_entry(itr, &dcb_rewr_list, list) {
22491df99338SDaniel Machon 		if (itr->ifindex == ifindex &&
22501df99338SDaniel Machon 		    itr->app.selector == DCB_APP_SEL_PCP &&
22511df99338SDaniel Machon 		    itr->app.protocol < 16 &&
22521df99338SDaniel Machon 		    itr->app.priority < IEEE_8021QAZ_MAX_TCS) {
22531df99338SDaniel Machon 			prio = itr->app.priority;
22541df99338SDaniel Machon 			p_map->map[prio] |= 1 << itr->app.protocol;
22551df99338SDaniel Machon 		}
22561df99338SDaniel Machon 	}
22571df99338SDaniel Machon 	spin_unlock_bh(&dcb_lock);
22581df99338SDaniel Machon }
22591df99338SDaniel Machon EXPORT_SYMBOL(dcb_getrewr_prio_pcp_mask_map);
22601df99338SDaniel Machon 
22611df99338SDaniel Machon /* dcb_getrewr_prio_dscp_mask_map - For a given device, find mapping from
22621df99338SDaniel Machon  * priorities to the DSCP values assigned to that priority.
22631df99338SDaniel Machon  */
dcb_getrewr_prio_dscp_mask_map(const struct net_device * dev,struct dcb_ieee_app_prio_map * p_map)22641df99338SDaniel Machon void dcb_getrewr_prio_dscp_mask_map(const struct net_device *dev,
22651df99338SDaniel Machon 				    struct dcb_ieee_app_prio_map *p_map)
22661df99338SDaniel Machon {
22671df99338SDaniel Machon 	int ifindex = dev->ifindex;
22681df99338SDaniel Machon 	struct dcb_app_type *itr;
22691df99338SDaniel Machon 	u8 prio;
22701df99338SDaniel Machon 
22711df99338SDaniel Machon 	memset(p_map->map, 0, sizeof(p_map->map));
22721df99338SDaniel Machon 
22731df99338SDaniel Machon 	spin_lock_bh(&dcb_lock);
22741df99338SDaniel Machon 	list_for_each_entry(itr, &dcb_rewr_list, list) {
22751df99338SDaniel Machon 		if (itr->ifindex == ifindex &&
22761df99338SDaniel Machon 		    itr->app.selector == IEEE_8021QAZ_APP_SEL_DSCP &&
22771df99338SDaniel Machon 		    itr->app.protocol < 64 &&
22781df99338SDaniel Machon 		    itr->app.priority < IEEE_8021QAZ_MAX_TCS) {
22791df99338SDaniel Machon 			prio = itr->app.priority;
22801df99338SDaniel Machon 			p_map->map[prio] |= 1ULL << itr->app.protocol;
22811df99338SDaniel Machon 		}
22821df99338SDaniel Machon 	}
22831df99338SDaniel Machon 	spin_unlock_bh(&dcb_lock);
22841df99338SDaniel Machon }
22851df99338SDaniel Machon EXPORT_SYMBOL(dcb_getrewr_prio_dscp_mask_map);
22861df99338SDaniel Machon 
2287a89a501cSAndrew Lunn /*
2288b67c540bSPetr Machata  * dcb_ieee_getapp_prio_dscp_mask_map - For a given device, find mapping from
2289b67c540bSPetr Machata  * priorities to the DSCP values assigned to that priority. Initialize p_map
2290b67c540bSPetr Machata  * such that each map element holds a bit mask of DSCP values configured for
2291b67c540bSPetr Machata  * that priority by APP entries.
2292b67c540bSPetr Machata  */
dcb_ieee_getapp_prio_dscp_mask_map(const struct net_device * dev,struct dcb_ieee_app_prio_map * p_map)2293b67c540bSPetr Machata void dcb_ieee_getapp_prio_dscp_mask_map(const struct net_device *dev,
2294b67c540bSPetr Machata 					struct dcb_ieee_app_prio_map *p_map)
2295b67c540bSPetr Machata {
2296b67c540bSPetr Machata 	int ifindex = dev->ifindex;
2297b67c540bSPetr Machata 	struct dcb_app_type *itr;
2298b67c540bSPetr Machata 	u8 prio;
2299b67c540bSPetr Machata 
2300b67c540bSPetr Machata 	memset(p_map->map, 0, sizeof(p_map->map));
2301b67c540bSPetr Machata 
2302b67c540bSPetr Machata 	spin_lock_bh(&dcb_lock);
2303b67c540bSPetr Machata 	list_for_each_entry(itr, &dcb_app_list, list) {
2304b67c540bSPetr Machata 		if (itr->ifindex == ifindex &&
2305b67c540bSPetr Machata 		    itr->app.selector == IEEE_8021QAZ_APP_SEL_DSCP &&
2306b67c540bSPetr Machata 		    itr->app.protocol < 64 &&
2307b67c540bSPetr Machata 		    itr->app.priority < IEEE_8021QAZ_MAX_TCS) {
2308b67c540bSPetr Machata 			prio = itr->app.priority;
2309b67c540bSPetr Machata 			p_map->map[prio] |= 1ULL << itr->app.protocol;
2310b67c540bSPetr Machata 		}
2311b67c540bSPetr Machata 	}
2312b67c540bSPetr Machata 	spin_unlock_bh(&dcb_lock);
2313b67c540bSPetr Machata }
2314b67c540bSPetr Machata EXPORT_SYMBOL(dcb_ieee_getapp_prio_dscp_mask_map);
2315b67c540bSPetr Machata 
2316a89a501cSAndrew Lunn /*
2317b67c540bSPetr Machata  * dcb_ieee_getapp_dscp_prio_mask_map - For a given device, find mapping from
2318b67c540bSPetr Machata  * DSCP values to the priorities assigned to that DSCP value. Initialize p_map
2319b67c540bSPetr Machata  * such that each map element holds a bit mask of priorities configured for a
2320b67c540bSPetr Machata  * given DSCP value by APP entries.
2321b67c540bSPetr Machata  */
2322b67c540bSPetr Machata void
dcb_ieee_getapp_dscp_prio_mask_map(const struct net_device * dev,struct dcb_ieee_app_dscp_map * p_map)2323b67c540bSPetr Machata dcb_ieee_getapp_dscp_prio_mask_map(const struct net_device *dev,
2324b67c540bSPetr Machata 				   struct dcb_ieee_app_dscp_map *p_map)
2325b67c540bSPetr Machata {
2326b67c540bSPetr Machata 	int ifindex = dev->ifindex;
2327b67c540bSPetr Machata 	struct dcb_app_type *itr;
2328b67c540bSPetr Machata 
2329b67c540bSPetr Machata 	memset(p_map->map, 0, sizeof(p_map->map));
2330b67c540bSPetr Machata 
2331b67c540bSPetr Machata 	spin_lock_bh(&dcb_lock);
2332b67c540bSPetr Machata 	list_for_each_entry(itr, &dcb_app_list, list) {
2333b67c540bSPetr Machata 		if (itr->ifindex == ifindex &&
2334b67c540bSPetr Machata 		    itr->app.selector == IEEE_8021QAZ_APP_SEL_DSCP &&
2335b67c540bSPetr Machata 		    itr->app.protocol < 64 &&
2336b67c540bSPetr Machata 		    itr->app.priority < IEEE_8021QAZ_MAX_TCS)
2337b67c540bSPetr Machata 			p_map->map[itr->app.protocol] |= 1 << itr->app.priority;
2338b67c540bSPetr Machata 	}
2339b67c540bSPetr Machata 	spin_unlock_bh(&dcb_lock);
2340b67c540bSPetr Machata }
2341b67c540bSPetr Machata EXPORT_SYMBOL(dcb_ieee_getapp_dscp_prio_mask_map);
2342b67c540bSPetr Machata 
2343a89a501cSAndrew Lunn /*
2344b67c540bSPetr Machata  * Per 802.1Q-2014, the selector value of 1 is used for matching on Ethernet
2345b67c540bSPetr Machata  * type, with valid PID values >= 1536. A special meaning is then assigned to
2346b67c540bSPetr Machata  * protocol value of 0: "default priority. For use when priority is not
2347b67c540bSPetr Machata  * otherwise specified".
2348b67c540bSPetr Machata  *
2349b67c540bSPetr Machata  * dcb_ieee_getapp_default_prio_mask - For a given device, find all APP entries
2350b67c540bSPetr Machata  * of the form {$PRIO, ETHERTYPE, 0} and construct a bit mask of all default
2351b67c540bSPetr Machata  * priorities set by these entries.
2352b67c540bSPetr Machata  */
dcb_ieee_getapp_default_prio_mask(const struct net_device * dev)2353b67c540bSPetr Machata u8 dcb_ieee_getapp_default_prio_mask(const struct net_device *dev)
2354b67c540bSPetr Machata {
2355b67c540bSPetr Machata 	int ifindex = dev->ifindex;
2356b67c540bSPetr Machata 	struct dcb_app_type *itr;
2357b67c540bSPetr Machata 	u8 mask = 0;
2358b67c540bSPetr Machata 
2359b67c540bSPetr Machata 	spin_lock_bh(&dcb_lock);
2360b67c540bSPetr Machata 	list_for_each_entry(itr, &dcb_app_list, list) {
2361b67c540bSPetr Machata 		if (itr->ifindex == ifindex &&
2362b67c540bSPetr Machata 		    itr->app.selector == IEEE_8021QAZ_APP_SEL_ETHERTYPE &&
2363b67c540bSPetr Machata 		    itr->app.protocol == 0 &&
2364b67c540bSPetr Machata 		    itr->app.priority < IEEE_8021QAZ_MAX_TCS)
2365b67c540bSPetr Machata 			mask |= 1 << itr->app.priority;
2366b67c540bSPetr Machata 	}
2367b67c540bSPetr Machata 	spin_unlock_bh(&dcb_lock);
2368b67c540bSPetr Machata 
2369b67c540bSPetr Machata 	return mask;
2370b67c540bSPetr Machata }
2371b67c540bSPetr Machata EXPORT_SYMBOL(dcb_ieee_getapp_default_prio_mask);
2372b67c540bSPetr Machata 
dcbnl_flush_dev(struct net_device * dev)237391b0383fSVladimir Oltean static void dcbnl_flush_dev(struct net_device *dev)
237491b0383fSVladimir Oltean {
237591b0383fSVladimir Oltean 	struct dcb_app_type *itr, *tmp;
237691b0383fSVladimir Oltean 
237710b6bb62SVladimir Oltean 	spin_lock_bh(&dcb_lock);
237891b0383fSVladimir Oltean 
237991b0383fSVladimir Oltean 	list_for_each_entry_safe(itr, tmp, &dcb_app_list, list) {
238091b0383fSVladimir Oltean 		if (itr->ifindex == dev->ifindex) {
238191b0383fSVladimir Oltean 			list_del(&itr->list);
238291b0383fSVladimir Oltean 			kfree(itr);
238391b0383fSVladimir Oltean 		}
238491b0383fSVladimir Oltean 	}
238591b0383fSVladimir Oltean 
238610b6bb62SVladimir Oltean 	spin_unlock_bh(&dcb_lock);
238791b0383fSVladimir Oltean }
238891b0383fSVladimir Oltean 
dcbnl_netdevice_event(struct notifier_block * nb,unsigned long event,void * ptr)238991b0383fSVladimir Oltean static int dcbnl_netdevice_event(struct notifier_block *nb,
239091b0383fSVladimir Oltean 				 unsigned long event, void *ptr)
239191b0383fSVladimir Oltean {
239291b0383fSVladimir Oltean 	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
239391b0383fSVladimir Oltean 
239491b0383fSVladimir Oltean 	switch (event) {
239591b0383fSVladimir Oltean 	case NETDEV_UNREGISTER:
239691b0383fSVladimir Oltean 		if (!dev->dcbnl_ops)
239791b0383fSVladimir Oltean 			return NOTIFY_DONE;
239891b0383fSVladimir Oltean 
239991b0383fSVladimir Oltean 		dcbnl_flush_dev(dev);
240091b0383fSVladimir Oltean 
240191b0383fSVladimir Oltean 		return NOTIFY_OK;
240291b0383fSVladimir Oltean 	default:
240391b0383fSVladimir Oltean 		return NOTIFY_DONE;
240491b0383fSVladimir Oltean 	}
240591b0383fSVladimir Oltean }
240691b0383fSVladimir Oltean 
240791b0383fSVladimir Oltean static struct notifier_block dcbnl_nb __read_mostly = {
240891b0383fSVladimir Oltean 	.notifier_call  = dcbnl_netdevice_event,
240991b0383fSVladimir Oltean };
241091b0383fSVladimir Oltean 
dcbnl_init(void)24112f90b865SAlexander Duyck static int __init dcbnl_init(void)
24122f90b865SAlexander Duyck {
241391b0383fSVladimir Oltean 	int err;
241491b0383fSVladimir Oltean 
241591b0383fSVladimir Oltean 	err = register_netdevice_notifier(&dcbnl_nb);
241691b0383fSVladimir Oltean 	if (err)
241791b0383fSVladimir Oltean 		return err;
241891b0383fSVladimir Oltean 
2419b97bac64SFlorian Westphal 	rtnl_register(PF_UNSPEC, RTM_GETDCB, dcb_doit, NULL, 0);
2420b97bac64SFlorian Westphal 	rtnl_register(PF_UNSPEC, RTM_SETDCB, dcb_doit, NULL, 0);
24212f90b865SAlexander Duyck 
24222f90b865SAlexander Duyck 	return 0;
24232f90b865SAlexander Duyck }
242436b9ad80SPaul Gortmaker device_initcall(dcbnl_init);
2425