xref: /openbmc/linux/net/dcb/dcbnl.c (revision 3e29027a)
12f90b865SAlexander Duyck /*
22f90b865SAlexander Duyck  * Copyright (c) 2008, Intel Corporation.
32f90b865SAlexander Duyck  *
42f90b865SAlexander Duyck  * This program is free software; you can redistribute it and/or modify it
52f90b865SAlexander Duyck  * under the terms and conditions of the GNU General Public License,
62f90b865SAlexander Duyck  * version 2, as published by the Free Software Foundation.
72f90b865SAlexander Duyck  *
82f90b865SAlexander Duyck  * This program is distributed in the hope it will be useful, but WITHOUT
92f90b865SAlexander Duyck  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
102f90b865SAlexander Duyck  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
112f90b865SAlexander Duyck  * more details.
122f90b865SAlexander Duyck  *
132f90b865SAlexander Duyck  * You should have received a copy of the GNU General Public License along with
142f90b865SAlexander Duyck  * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
152f90b865SAlexander Duyck  * Place - Suite 330, Boston, MA 02111-1307 USA.
162f90b865SAlexander Duyck  *
172f90b865SAlexander Duyck  * Author: Lucy Liu <lucy.liu@intel.com>
182f90b865SAlexander Duyck  */
192f90b865SAlexander Duyck 
202f90b865SAlexander Duyck #include <linux/netdevice.h>
212f90b865SAlexander Duyck #include <linux/netlink.h>
225a0e3ad6STejun Heo #include <linux/slab.h>
232f90b865SAlexander Duyck #include <net/netlink.h>
242f90b865SAlexander Duyck #include <net/rtnetlink.h>
252f90b865SAlexander Duyck #include <linux/dcbnl.h>
262f90b865SAlexander Duyck #include <linux/rtnetlink.h>
272f90b865SAlexander Duyck #include <net/sock.h>
282f90b865SAlexander Duyck 
292f90b865SAlexander Duyck /**
302f90b865SAlexander Duyck  * Data Center Bridging (DCB) is a collection of Ethernet enhancements
312f90b865SAlexander Duyck  * intended to allow network traffic with differing requirements
322f90b865SAlexander Duyck  * (highly reliable, no drops vs. best effort vs. low latency) to operate
332f90b865SAlexander Duyck  * and co-exist on Ethernet.  Current DCB features are:
342f90b865SAlexander Duyck  *
352f90b865SAlexander Duyck  * Enhanced Transmission Selection (aka Priority Grouping [PG]) - provides a
362f90b865SAlexander Duyck  *   framework for assigning bandwidth guarantees to traffic classes.
372f90b865SAlexander Duyck  *
382f90b865SAlexander Duyck  * Priority-based Flow Control (PFC) - provides a flow control mechanism which
392f90b865SAlexander Duyck  *   can work independently for each 802.1p priority.
402f90b865SAlexander Duyck  *
412f90b865SAlexander Duyck  * Congestion Notification - provides a mechanism for end-to-end congestion
422f90b865SAlexander Duyck  *   control for protocols which do not have built-in congestion management.
432f90b865SAlexander Duyck  *
442f90b865SAlexander Duyck  * More information about the emerging standards for these Ethernet features
452f90b865SAlexander Duyck  * can be found at: http://www.ieee802.org/1/pages/dcbridges.html
462f90b865SAlexander Duyck  *
472f90b865SAlexander Duyck  * This file implements an rtnetlink interface to allow configuration of DCB
482f90b865SAlexander Duyck  * features for capable devices.
492f90b865SAlexander Duyck  */
502f90b865SAlexander Duyck 
512f90b865SAlexander Duyck MODULE_AUTHOR("Lucy Liu, <lucy.liu@intel.com>");
527a6b6f51SJeff Kirsher MODULE_DESCRIPTION("Data Center Bridging netlink interface");
532f90b865SAlexander Duyck MODULE_LICENSE("GPL");
542f90b865SAlexander Duyck 
552f90b865SAlexander Duyck /**************** DCB attribute policies *************************************/
562f90b865SAlexander Duyck 
572f90b865SAlexander Duyck /* DCB netlink attributes policy */
58b54452b0SAlexey Dobriyan static const struct nla_policy dcbnl_rtnl_policy[DCB_ATTR_MAX + 1] = {
59859ee3c4SAlexander Duyck 	[DCB_ATTR_IFNAME]      = {.type = NLA_NUL_STRING, .len = IFNAMSIZ - 1},
602f90b865SAlexander Duyck 	[DCB_ATTR_STATE]       = {.type = NLA_U8},
612f90b865SAlexander Duyck 	[DCB_ATTR_PFC_CFG]     = {.type = NLA_NESTED},
622f90b865SAlexander Duyck 	[DCB_ATTR_PG_CFG]      = {.type = NLA_NESTED},
632f90b865SAlexander Duyck 	[DCB_ATTR_SET_ALL]     = {.type = NLA_U8},
642f90b865SAlexander Duyck 	[DCB_ATTR_PERM_HWADDR] = {.type = NLA_FLAG},
6546132188SAlexander Duyck 	[DCB_ATTR_CAP]         = {.type = NLA_NESTED},
660eb3aa9bSAlexander Duyck 	[DCB_ATTR_PFC_STATE]   = {.type = NLA_U8},
67859ee3c4SAlexander Duyck 	[DCB_ATTR_BCN]         = {.type = NLA_NESTED},
686fa382afSYi Zou 	[DCB_ATTR_APP]         = {.type = NLA_NESTED},
693e29027aSJohn Fastabend 	[DCB_ATTR_IEEE]	       = {.type = NLA_NESTED},
702f90b865SAlexander Duyck };
712f90b865SAlexander Duyck 
722f90b865SAlexander Duyck /* DCB priority flow control to User Priority nested attributes */
73b54452b0SAlexey Dobriyan static const struct nla_policy dcbnl_pfc_up_nest[DCB_PFC_UP_ATTR_MAX + 1] = {
742f90b865SAlexander Duyck 	[DCB_PFC_UP_ATTR_0]   = {.type = NLA_U8},
752f90b865SAlexander Duyck 	[DCB_PFC_UP_ATTR_1]   = {.type = NLA_U8},
762f90b865SAlexander Duyck 	[DCB_PFC_UP_ATTR_2]   = {.type = NLA_U8},
772f90b865SAlexander Duyck 	[DCB_PFC_UP_ATTR_3]   = {.type = NLA_U8},
782f90b865SAlexander Duyck 	[DCB_PFC_UP_ATTR_4]   = {.type = NLA_U8},
792f90b865SAlexander Duyck 	[DCB_PFC_UP_ATTR_5]   = {.type = NLA_U8},
802f90b865SAlexander Duyck 	[DCB_PFC_UP_ATTR_6]   = {.type = NLA_U8},
812f90b865SAlexander Duyck 	[DCB_PFC_UP_ATTR_7]   = {.type = NLA_U8},
822f90b865SAlexander Duyck 	[DCB_PFC_UP_ATTR_ALL] = {.type = NLA_FLAG},
832f90b865SAlexander Duyck };
842f90b865SAlexander Duyck 
852f90b865SAlexander Duyck /* DCB priority grouping nested attributes */
86b54452b0SAlexey Dobriyan static const struct nla_policy dcbnl_pg_nest[DCB_PG_ATTR_MAX + 1] = {
872f90b865SAlexander Duyck 	[DCB_PG_ATTR_TC_0]      = {.type = NLA_NESTED},
882f90b865SAlexander Duyck 	[DCB_PG_ATTR_TC_1]      = {.type = NLA_NESTED},
892f90b865SAlexander Duyck 	[DCB_PG_ATTR_TC_2]      = {.type = NLA_NESTED},
902f90b865SAlexander Duyck 	[DCB_PG_ATTR_TC_3]      = {.type = NLA_NESTED},
912f90b865SAlexander Duyck 	[DCB_PG_ATTR_TC_4]      = {.type = NLA_NESTED},
922f90b865SAlexander Duyck 	[DCB_PG_ATTR_TC_5]      = {.type = NLA_NESTED},
932f90b865SAlexander Duyck 	[DCB_PG_ATTR_TC_6]      = {.type = NLA_NESTED},
942f90b865SAlexander Duyck 	[DCB_PG_ATTR_TC_7]      = {.type = NLA_NESTED},
952f90b865SAlexander Duyck 	[DCB_PG_ATTR_TC_ALL]    = {.type = NLA_NESTED},
962f90b865SAlexander Duyck 	[DCB_PG_ATTR_BW_ID_0]   = {.type = NLA_U8},
972f90b865SAlexander Duyck 	[DCB_PG_ATTR_BW_ID_1]   = {.type = NLA_U8},
982f90b865SAlexander Duyck 	[DCB_PG_ATTR_BW_ID_2]   = {.type = NLA_U8},
992f90b865SAlexander Duyck 	[DCB_PG_ATTR_BW_ID_3]   = {.type = NLA_U8},
1002f90b865SAlexander Duyck 	[DCB_PG_ATTR_BW_ID_4]   = {.type = NLA_U8},
1012f90b865SAlexander Duyck 	[DCB_PG_ATTR_BW_ID_5]   = {.type = NLA_U8},
1022f90b865SAlexander Duyck 	[DCB_PG_ATTR_BW_ID_6]   = {.type = NLA_U8},
1032f90b865SAlexander Duyck 	[DCB_PG_ATTR_BW_ID_7]   = {.type = NLA_U8},
1042f90b865SAlexander Duyck 	[DCB_PG_ATTR_BW_ID_ALL] = {.type = NLA_FLAG},
1052f90b865SAlexander Duyck };
1062f90b865SAlexander Duyck 
1072f90b865SAlexander Duyck /* DCB traffic class nested attributes. */
108b54452b0SAlexey Dobriyan static const struct nla_policy dcbnl_tc_param_nest[DCB_TC_ATTR_PARAM_MAX + 1] = {
1092f90b865SAlexander Duyck 	[DCB_TC_ATTR_PARAM_PGID]            = {.type = NLA_U8},
1102f90b865SAlexander Duyck 	[DCB_TC_ATTR_PARAM_UP_MAPPING]      = {.type = NLA_U8},
1112f90b865SAlexander Duyck 	[DCB_TC_ATTR_PARAM_STRICT_PRIO]     = {.type = NLA_U8},
1122f90b865SAlexander Duyck 	[DCB_TC_ATTR_PARAM_BW_PCT]          = {.type = NLA_U8},
1132f90b865SAlexander Duyck 	[DCB_TC_ATTR_PARAM_ALL]             = {.type = NLA_FLAG},
1142f90b865SAlexander Duyck };
1152f90b865SAlexander Duyck 
11646132188SAlexander Duyck /* DCB capabilities nested attributes. */
117b54452b0SAlexey Dobriyan static const struct nla_policy dcbnl_cap_nest[DCB_CAP_ATTR_MAX + 1] = {
11846132188SAlexander Duyck 	[DCB_CAP_ATTR_ALL]     = {.type = NLA_FLAG},
11946132188SAlexander Duyck 	[DCB_CAP_ATTR_PG]      = {.type = NLA_U8},
12046132188SAlexander Duyck 	[DCB_CAP_ATTR_PFC]     = {.type = NLA_U8},
12146132188SAlexander Duyck 	[DCB_CAP_ATTR_UP2TC]   = {.type = NLA_U8},
12246132188SAlexander Duyck 	[DCB_CAP_ATTR_PG_TCS]  = {.type = NLA_U8},
12346132188SAlexander Duyck 	[DCB_CAP_ATTR_PFC_TCS] = {.type = NLA_U8},
12446132188SAlexander Duyck 	[DCB_CAP_ATTR_GSP]     = {.type = NLA_U8},
12546132188SAlexander Duyck 	[DCB_CAP_ATTR_BCN]     = {.type = NLA_U8},
12646132188SAlexander Duyck };
1272f90b865SAlexander Duyck 
12833dbabc4SAlexander Duyck /* DCB capabilities nested attributes. */
129b54452b0SAlexey Dobriyan static const struct nla_policy dcbnl_numtcs_nest[DCB_NUMTCS_ATTR_MAX + 1] = {
13033dbabc4SAlexander Duyck 	[DCB_NUMTCS_ATTR_ALL]     = {.type = NLA_FLAG},
13133dbabc4SAlexander Duyck 	[DCB_NUMTCS_ATTR_PG]      = {.type = NLA_U8},
13233dbabc4SAlexander Duyck 	[DCB_NUMTCS_ATTR_PFC]     = {.type = NLA_U8},
13333dbabc4SAlexander Duyck };
13433dbabc4SAlexander Duyck 
135859ee3c4SAlexander Duyck /* DCB BCN nested attributes. */
136b54452b0SAlexey Dobriyan static const struct nla_policy dcbnl_bcn_nest[DCB_BCN_ATTR_MAX + 1] = {
137859ee3c4SAlexander Duyck 	[DCB_BCN_ATTR_RP_0]         = {.type = NLA_U8},
138859ee3c4SAlexander Duyck 	[DCB_BCN_ATTR_RP_1]         = {.type = NLA_U8},
139859ee3c4SAlexander Duyck 	[DCB_BCN_ATTR_RP_2]         = {.type = NLA_U8},
140859ee3c4SAlexander Duyck 	[DCB_BCN_ATTR_RP_3]         = {.type = NLA_U8},
141859ee3c4SAlexander Duyck 	[DCB_BCN_ATTR_RP_4]         = {.type = NLA_U8},
142859ee3c4SAlexander Duyck 	[DCB_BCN_ATTR_RP_5]         = {.type = NLA_U8},
143859ee3c4SAlexander Duyck 	[DCB_BCN_ATTR_RP_6]         = {.type = NLA_U8},
144859ee3c4SAlexander Duyck 	[DCB_BCN_ATTR_RP_7]         = {.type = NLA_U8},
145859ee3c4SAlexander Duyck 	[DCB_BCN_ATTR_RP_ALL]       = {.type = NLA_FLAG},
146f4314e81SDon Skidmore 	[DCB_BCN_ATTR_BCNA_0]       = {.type = NLA_U32},
147f4314e81SDon Skidmore 	[DCB_BCN_ATTR_BCNA_1]       = {.type = NLA_U32},
148859ee3c4SAlexander Duyck 	[DCB_BCN_ATTR_ALPHA]        = {.type = NLA_U32},
149859ee3c4SAlexander Duyck 	[DCB_BCN_ATTR_BETA]         = {.type = NLA_U32},
150859ee3c4SAlexander Duyck 	[DCB_BCN_ATTR_GD]           = {.type = NLA_U32},
151859ee3c4SAlexander Duyck 	[DCB_BCN_ATTR_GI]           = {.type = NLA_U32},
152859ee3c4SAlexander Duyck 	[DCB_BCN_ATTR_TMAX]         = {.type = NLA_U32},
153859ee3c4SAlexander Duyck 	[DCB_BCN_ATTR_TD]           = {.type = NLA_U32},
154859ee3c4SAlexander Duyck 	[DCB_BCN_ATTR_RMIN]         = {.type = NLA_U32},
155859ee3c4SAlexander Duyck 	[DCB_BCN_ATTR_W]            = {.type = NLA_U32},
156859ee3c4SAlexander Duyck 	[DCB_BCN_ATTR_RD]           = {.type = NLA_U32},
157859ee3c4SAlexander Duyck 	[DCB_BCN_ATTR_RU]           = {.type = NLA_U32},
158859ee3c4SAlexander Duyck 	[DCB_BCN_ATTR_WRTT]         = {.type = NLA_U32},
159859ee3c4SAlexander Duyck 	[DCB_BCN_ATTR_RI]           = {.type = NLA_U32},
160859ee3c4SAlexander Duyck 	[DCB_BCN_ATTR_C]            = {.type = NLA_U32},
161859ee3c4SAlexander Duyck 	[DCB_BCN_ATTR_ALL]          = {.type = NLA_FLAG},
162859ee3c4SAlexander Duyck };
163859ee3c4SAlexander Duyck 
1646fa382afSYi Zou /* DCB APP nested attributes. */
165b54452b0SAlexey Dobriyan static const struct nla_policy dcbnl_app_nest[DCB_APP_ATTR_MAX + 1] = {
1666fa382afSYi Zou 	[DCB_APP_ATTR_IDTYPE]       = {.type = NLA_U8},
1676fa382afSYi Zou 	[DCB_APP_ATTR_ID]           = {.type = NLA_U16},
1686fa382afSYi Zou 	[DCB_APP_ATTR_PRIORITY]     = {.type = NLA_U8},
1696fa382afSYi Zou };
1706fa382afSYi Zou 
1713e29027aSJohn Fastabend /* IEEE 802.1Qaz nested attributes. */
1723e29027aSJohn Fastabend static const struct nla_policy dcbnl_ieee_policy[DCB_ATTR_IEEE_MAX + 1] = {
1733e29027aSJohn Fastabend 	[DCB_ATTR_IEEE_ETS]	    = {.len = sizeof(struct ieee_ets)},
1743e29027aSJohn Fastabend 	[DCB_ATTR_IEEE_PFC]	    = {.len = sizeof(struct ieee_pfc)},
1753e29027aSJohn Fastabend 	[DCB_ATTR_IEEE_APP_TABLE]   = {.type = NLA_NESTED},
1763e29027aSJohn Fastabend };
1773e29027aSJohn Fastabend 
1783e29027aSJohn Fastabend static const struct nla_policy dcbnl_ieee_app[DCB_ATTR_IEEE_APP_MAX + 1] = {
1793e29027aSJohn Fastabend 	[DCB_ATTR_IEEE_APP]	    = {.len = sizeof(struct dcb_app)},
1803e29027aSJohn Fastabend };
1813e29027aSJohn Fastabend 
1822f90b865SAlexander Duyck /* standard netlink reply call */
1832f90b865SAlexander Duyck static int dcbnl_reply(u8 value, u8 event, u8 cmd, u8 attr, u32 pid,
1842f90b865SAlexander Duyck                        u32 seq, u16 flags)
1852f90b865SAlexander Duyck {
1862f90b865SAlexander Duyck 	struct sk_buff *dcbnl_skb;
1872f90b865SAlexander Duyck 	struct dcbmsg *dcb;
1882f90b865SAlexander Duyck 	struct nlmsghdr *nlh;
1892f90b865SAlexander Duyck 	int ret = -EINVAL;
1902f90b865SAlexander Duyck 
1912f90b865SAlexander Duyck 	dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1922f90b865SAlexander Duyck 	if (!dcbnl_skb)
1932f90b865SAlexander Duyck 		return ret;
1942f90b865SAlexander Duyck 
1952f90b865SAlexander Duyck 	nlh = NLMSG_NEW(dcbnl_skb, pid, seq, event, sizeof(*dcb), flags);
1962f90b865SAlexander Duyck 
1972f90b865SAlexander Duyck 	dcb = NLMSG_DATA(nlh);
1982f90b865SAlexander Duyck 	dcb->dcb_family = AF_UNSPEC;
1992f90b865SAlexander Duyck 	dcb->cmd = cmd;
2002f90b865SAlexander Duyck 	dcb->dcb_pad = 0;
2012f90b865SAlexander Duyck 
2022f90b865SAlexander Duyck 	ret = nla_put_u8(dcbnl_skb, attr, value);
2032f90b865SAlexander Duyck 	if (ret)
2042f90b865SAlexander Duyck 		goto err;
2052f90b865SAlexander Duyck 
2062f90b865SAlexander Duyck 	/* end the message, assign the nlmsg_len. */
2072f90b865SAlexander Duyck 	nlmsg_end(dcbnl_skb, nlh);
2082f90b865SAlexander Duyck 	ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
2092f90b865SAlexander Duyck 	if (ret)
2107eaf5077SJohn Fastabend 		return -EINVAL;
2112f90b865SAlexander Duyck 
2122f90b865SAlexander Duyck 	return 0;
2132f90b865SAlexander Duyck nlmsg_failure:
2142f90b865SAlexander Duyck err:
215858eb711SRoel Kluin 	kfree_skb(dcbnl_skb);
2162f90b865SAlexander Duyck 	return ret;
2172f90b865SAlexander Duyck }
2182f90b865SAlexander Duyck 
2192f90b865SAlexander Duyck static int dcbnl_getstate(struct net_device *netdev, struct nlattr **tb,
2202f90b865SAlexander Duyck                           u32 pid, u32 seq, u16 flags)
2212f90b865SAlexander Duyck {
2222f90b865SAlexander Duyck 	int ret = -EINVAL;
2232f90b865SAlexander Duyck 
2242f90b865SAlexander Duyck 	/* if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->getstate) */
2252f90b865SAlexander Duyck 	if (!netdev->dcbnl_ops->getstate)
2262f90b865SAlexander Duyck 		return ret;
2272f90b865SAlexander Duyck 
2282f90b865SAlexander Duyck 	ret = dcbnl_reply(netdev->dcbnl_ops->getstate(netdev), RTM_GETDCB,
2292f90b865SAlexander Duyck 	                  DCB_CMD_GSTATE, DCB_ATTR_STATE, pid, seq, flags);
2302f90b865SAlexander Duyck 
2312f90b865SAlexander Duyck 	return ret;
2322f90b865SAlexander Duyck }
2332f90b865SAlexander Duyck 
2342f90b865SAlexander Duyck static int dcbnl_getpfccfg(struct net_device *netdev, struct nlattr **tb,
2352f90b865SAlexander Duyck                            u32 pid, u32 seq, u16 flags)
2362f90b865SAlexander Duyck {
2372f90b865SAlexander Duyck 	struct sk_buff *dcbnl_skb;
2382f90b865SAlexander Duyck 	struct nlmsghdr *nlh;
2392f90b865SAlexander Duyck 	struct dcbmsg *dcb;
2402f90b865SAlexander Duyck 	struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1], *nest;
2412f90b865SAlexander Duyck 	u8 value;
2422f90b865SAlexander Duyck 	int ret = -EINVAL;
2432f90b865SAlexander Duyck 	int i;
2442f90b865SAlexander Duyck 	int getall = 0;
2452f90b865SAlexander Duyck 
2462f90b865SAlexander Duyck 	if (!tb[DCB_ATTR_PFC_CFG] || !netdev->dcbnl_ops->getpfccfg)
2472f90b865SAlexander Duyck 		return ret;
2482f90b865SAlexander Duyck 
2492f90b865SAlexander Duyck 	ret = nla_parse_nested(data, DCB_PFC_UP_ATTR_MAX,
2502f90b865SAlexander Duyck 	                       tb[DCB_ATTR_PFC_CFG],
2512f90b865SAlexander Duyck 	                       dcbnl_pfc_up_nest);
2522f90b865SAlexander Duyck 	if (ret)
2532f90b865SAlexander Duyck 		goto err_out;
2542f90b865SAlexander Duyck 
2552f90b865SAlexander Duyck 	dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
2562f90b865SAlexander Duyck 	if (!dcbnl_skb)
2572f90b865SAlexander Duyck 		goto err_out;
2582f90b865SAlexander Duyck 
2592f90b865SAlexander Duyck 	nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
2602f90b865SAlexander Duyck 
2612f90b865SAlexander Duyck 	dcb = NLMSG_DATA(nlh);
2622f90b865SAlexander Duyck 	dcb->dcb_family = AF_UNSPEC;
2632f90b865SAlexander Duyck 	dcb->cmd = DCB_CMD_PFC_GCFG;
2642f90b865SAlexander Duyck 
2652f90b865SAlexander Duyck 	nest = nla_nest_start(dcbnl_skb, DCB_ATTR_PFC_CFG);
2662f90b865SAlexander Duyck 	if (!nest)
2672f90b865SAlexander Duyck 		goto err;
2682f90b865SAlexander Duyck 
2692f90b865SAlexander Duyck 	if (data[DCB_PFC_UP_ATTR_ALL])
2702f90b865SAlexander Duyck 		getall = 1;
2712f90b865SAlexander Duyck 
2722f90b865SAlexander Duyck 	for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) {
2732f90b865SAlexander Duyck 		if (!getall && !data[i])
2742f90b865SAlexander Duyck 			continue;
2752f90b865SAlexander Duyck 
2762f90b865SAlexander Duyck 		netdev->dcbnl_ops->getpfccfg(netdev, i - DCB_PFC_UP_ATTR_0,
2772f90b865SAlexander Duyck 		                             &value);
2782f90b865SAlexander Duyck 		ret = nla_put_u8(dcbnl_skb, i, value);
2792f90b865SAlexander Duyck 
2802f90b865SAlexander Duyck 		if (ret) {
2812f90b865SAlexander Duyck 			nla_nest_cancel(dcbnl_skb, nest);
2822f90b865SAlexander Duyck 			goto err;
2832f90b865SAlexander Duyck 		}
2842f90b865SAlexander Duyck 	}
2852f90b865SAlexander Duyck 	nla_nest_end(dcbnl_skb, nest);
2862f90b865SAlexander Duyck 
2872f90b865SAlexander Duyck 	nlmsg_end(dcbnl_skb, nlh);
2882f90b865SAlexander Duyck 
2892f90b865SAlexander Duyck 	ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
2902f90b865SAlexander Duyck 	if (ret)
2917eaf5077SJohn Fastabend 		goto err_out;
2922f90b865SAlexander Duyck 
2932f90b865SAlexander Duyck 	return 0;
2942f90b865SAlexander Duyck nlmsg_failure:
2952f90b865SAlexander Duyck err:
296858eb711SRoel Kluin 	kfree_skb(dcbnl_skb);
2972f90b865SAlexander Duyck err_out:
2982f90b865SAlexander Duyck 	return -EINVAL;
2992f90b865SAlexander Duyck }
3002f90b865SAlexander Duyck 
3012f90b865SAlexander Duyck static int dcbnl_getperm_hwaddr(struct net_device *netdev, struct nlattr **tb,
3022f90b865SAlexander Duyck                                 u32 pid, u32 seq, u16 flags)
3032f90b865SAlexander Duyck {
3042f90b865SAlexander Duyck 	struct sk_buff *dcbnl_skb;
3052f90b865SAlexander Duyck 	struct nlmsghdr *nlh;
3062f90b865SAlexander Duyck 	struct dcbmsg *dcb;
3072f90b865SAlexander Duyck 	u8 perm_addr[MAX_ADDR_LEN];
3082f90b865SAlexander Duyck 	int ret = -EINVAL;
3092f90b865SAlexander Duyck 
3102f90b865SAlexander Duyck 	if (!netdev->dcbnl_ops->getpermhwaddr)
3112f90b865SAlexander Duyck 		return ret;
3122f90b865SAlexander Duyck 
3132f90b865SAlexander Duyck 	dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3142f90b865SAlexander Duyck 	if (!dcbnl_skb)
3152f90b865SAlexander Duyck 		goto err_out;
3162f90b865SAlexander Duyck 
3172f90b865SAlexander Duyck 	nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
3182f90b865SAlexander Duyck 
3192f90b865SAlexander Duyck 	dcb = NLMSG_DATA(nlh);
3202f90b865SAlexander Duyck 	dcb->dcb_family = AF_UNSPEC;
3212f90b865SAlexander Duyck 	dcb->cmd = DCB_CMD_GPERM_HWADDR;
3222f90b865SAlexander Duyck 
3232f90b865SAlexander Duyck 	netdev->dcbnl_ops->getpermhwaddr(netdev, perm_addr);
3242f90b865SAlexander Duyck 
3252f90b865SAlexander Duyck 	ret = nla_put(dcbnl_skb, DCB_ATTR_PERM_HWADDR, sizeof(perm_addr),
3262f90b865SAlexander Duyck 	              perm_addr);
3272f90b865SAlexander Duyck 
3282f90b865SAlexander Duyck 	nlmsg_end(dcbnl_skb, nlh);
3292f90b865SAlexander Duyck 
3302f90b865SAlexander Duyck 	ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
3312f90b865SAlexander Duyck 	if (ret)
3327eaf5077SJohn Fastabend 		goto err_out;
3332f90b865SAlexander Duyck 
3342f90b865SAlexander Duyck 	return 0;
3352f90b865SAlexander Duyck 
3362f90b865SAlexander Duyck nlmsg_failure:
337858eb711SRoel Kluin 	kfree_skb(dcbnl_skb);
3382f90b865SAlexander Duyck err_out:
3392f90b865SAlexander Duyck 	return -EINVAL;
3402f90b865SAlexander Duyck }
3412f90b865SAlexander Duyck 
34246132188SAlexander Duyck static int dcbnl_getcap(struct net_device *netdev, struct nlattr **tb,
34346132188SAlexander Duyck                         u32 pid, u32 seq, u16 flags)
34446132188SAlexander Duyck {
34546132188SAlexander Duyck 	struct sk_buff *dcbnl_skb;
34646132188SAlexander Duyck 	struct nlmsghdr *nlh;
34746132188SAlexander Duyck 	struct dcbmsg *dcb;
34846132188SAlexander Duyck 	struct nlattr *data[DCB_CAP_ATTR_MAX + 1], *nest;
34946132188SAlexander Duyck 	u8 value;
35046132188SAlexander Duyck 	int ret = -EINVAL;
35146132188SAlexander Duyck 	int i;
35246132188SAlexander Duyck 	int getall = 0;
35346132188SAlexander Duyck 
35446132188SAlexander Duyck 	if (!tb[DCB_ATTR_CAP] || !netdev->dcbnl_ops->getcap)
35546132188SAlexander Duyck 		return ret;
35646132188SAlexander Duyck 
35746132188SAlexander Duyck 	ret = nla_parse_nested(data, DCB_CAP_ATTR_MAX, tb[DCB_ATTR_CAP],
35846132188SAlexander Duyck 	                       dcbnl_cap_nest);
35946132188SAlexander Duyck 	if (ret)
36046132188SAlexander Duyck 		goto err_out;
36146132188SAlexander Duyck 
36246132188SAlexander Duyck 	dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
36346132188SAlexander Duyck 	if (!dcbnl_skb)
36446132188SAlexander Duyck 		goto err_out;
36546132188SAlexander Duyck 
36646132188SAlexander Duyck 	nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
36746132188SAlexander Duyck 
36846132188SAlexander Duyck 	dcb = NLMSG_DATA(nlh);
36946132188SAlexander Duyck 	dcb->dcb_family = AF_UNSPEC;
37046132188SAlexander Duyck 	dcb->cmd = DCB_CMD_GCAP;
37146132188SAlexander Duyck 
37246132188SAlexander Duyck 	nest = nla_nest_start(dcbnl_skb, DCB_ATTR_CAP);
37346132188SAlexander Duyck 	if (!nest)
37446132188SAlexander Duyck 		goto err;
37546132188SAlexander Duyck 
37646132188SAlexander Duyck 	if (data[DCB_CAP_ATTR_ALL])
37746132188SAlexander Duyck 		getall = 1;
37846132188SAlexander Duyck 
37946132188SAlexander Duyck 	for (i = DCB_CAP_ATTR_ALL+1; i <= DCB_CAP_ATTR_MAX; i++) {
38046132188SAlexander Duyck 		if (!getall && !data[i])
38146132188SAlexander Duyck 			continue;
38246132188SAlexander Duyck 
38346132188SAlexander Duyck 		if (!netdev->dcbnl_ops->getcap(netdev, i, &value)) {
38446132188SAlexander Duyck 			ret = nla_put_u8(dcbnl_skb, i, value);
38546132188SAlexander Duyck 
38646132188SAlexander Duyck 			if (ret) {
38746132188SAlexander Duyck 				nla_nest_cancel(dcbnl_skb, nest);
38846132188SAlexander Duyck 				goto err;
38946132188SAlexander Duyck 			}
39046132188SAlexander Duyck 		}
39146132188SAlexander Duyck 	}
39246132188SAlexander Duyck 	nla_nest_end(dcbnl_skb, nest);
39346132188SAlexander Duyck 
39446132188SAlexander Duyck 	nlmsg_end(dcbnl_skb, nlh);
39546132188SAlexander Duyck 
39646132188SAlexander Duyck 	ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
39746132188SAlexander Duyck 	if (ret)
3987eaf5077SJohn Fastabend 		goto err_out;
39946132188SAlexander Duyck 
40046132188SAlexander Duyck 	return 0;
40146132188SAlexander Duyck nlmsg_failure:
40246132188SAlexander Duyck err:
403858eb711SRoel Kluin 	kfree_skb(dcbnl_skb);
40446132188SAlexander Duyck err_out:
40546132188SAlexander Duyck 	return -EINVAL;
40646132188SAlexander Duyck }
40746132188SAlexander Duyck 
40833dbabc4SAlexander Duyck static int dcbnl_getnumtcs(struct net_device *netdev, struct nlattr **tb,
40933dbabc4SAlexander Duyck                            u32 pid, u32 seq, u16 flags)
41033dbabc4SAlexander Duyck {
41133dbabc4SAlexander Duyck 	struct sk_buff *dcbnl_skb;
41233dbabc4SAlexander Duyck 	struct nlmsghdr *nlh;
41333dbabc4SAlexander Duyck 	struct dcbmsg *dcb;
41433dbabc4SAlexander Duyck 	struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1], *nest;
41533dbabc4SAlexander Duyck 	u8 value;
41633dbabc4SAlexander Duyck 	int ret = -EINVAL;
41733dbabc4SAlexander Duyck 	int i;
41833dbabc4SAlexander Duyck 	int getall = 0;
41933dbabc4SAlexander Duyck 
42033dbabc4SAlexander Duyck 	if (!tb[DCB_ATTR_NUMTCS] || !netdev->dcbnl_ops->getnumtcs)
42133dbabc4SAlexander Duyck 		return ret;
42233dbabc4SAlexander Duyck 
42333dbabc4SAlexander Duyck 	ret = nla_parse_nested(data, DCB_NUMTCS_ATTR_MAX, tb[DCB_ATTR_NUMTCS],
42433dbabc4SAlexander Duyck 	                       dcbnl_numtcs_nest);
42533dbabc4SAlexander Duyck 	if (ret) {
42633dbabc4SAlexander Duyck 		ret = -EINVAL;
42733dbabc4SAlexander Duyck 		goto err_out;
42833dbabc4SAlexander Duyck 	}
42933dbabc4SAlexander Duyck 
43033dbabc4SAlexander Duyck 	dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
43133dbabc4SAlexander Duyck 	if (!dcbnl_skb) {
43233dbabc4SAlexander Duyck 		ret = -EINVAL;
43333dbabc4SAlexander Duyck 		goto err_out;
43433dbabc4SAlexander Duyck 	}
43533dbabc4SAlexander Duyck 
43633dbabc4SAlexander Duyck 	nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
43733dbabc4SAlexander Duyck 
43833dbabc4SAlexander Duyck 	dcb = NLMSG_DATA(nlh);
43933dbabc4SAlexander Duyck 	dcb->dcb_family = AF_UNSPEC;
44033dbabc4SAlexander Duyck 	dcb->cmd = DCB_CMD_GNUMTCS;
44133dbabc4SAlexander Duyck 
44233dbabc4SAlexander Duyck 	nest = nla_nest_start(dcbnl_skb, DCB_ATTR_NUMTCS);
44333dbabc4SAlexander Duyck 	if (!nest) {
44433dbabc4SAlexander Duyck 		ret = -EINVAL;
44533dbabc4SAlexander Duyck 		goto err;
44633dbabc4SAlexander Duyck 	}
44733dbabc4SAlexander Duyck 
44833dbabc4SAlexander Duyck 	if (data[DCB_NUMTCS_ATTR_ALL])
44933dbabc4SAlexander Duyck 		getall = 1;
45033dbabc4SAlexander Duyck 
45133dbabc4SAlexander Duyck 	for (i = DCB_NUMTCS_ATTR_ALL+1; i <= DCB_NUMTCS_ATTR_MAX; i++) {
45233dbabc4SAlexander Duyck 		if (!getall && !data[i])
45333dbabc4SAlexander Duyck 			continue;
45433dbabc4SAlexander Duyck 
45533dbabc4SAlexander Duyck 		ret = netdev->dcbnl_ops->getnumtcs(netdev, i, &value);
45633dbabc4SAlexander Duyck 		if (!ret) {
45733dbabc4SAlexander Duyck 			ret = nla_put_u8(dcbnl_skb, i, value);
45833dbabc4SAlexander Duyck 
45933dbabc4SAlexander Duyck 			if (ret) {
46033dbabc4SAlexander Duyck 				nla_nest_cancel(dcbnl_skb, nest);
46133dbabc4SAlexander Duyck 				ret = -EINVAL;
46233dbabc4SAlexander Duyck 				goto err;
46333dbabc4SAlexander Duyck 			}
46433dbabc4SAlexander Duyck 		} else {
46533dbabc4SAlexander Duyck 			goto err;
46633dbabc4SAlexander Duyck 		}
46733dbabc4SAlexander Duyck 	}
46833dbabc4SAlexander Duyck 	nla_nest_end(dcbnl_skb, nest);
46933dbabc4SAlexander Duyck 
47033dbabc4SAlexander Duyck 	nlmsg_end(dcbnl_skb, nlh);
47133dbabc4SAlexander Duyck 
47233dbabc4SAlexander Duyck 	ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
47333dbabc4SAlexander Duyck 	if (ret) {
47433dbabc4SAlexander Duyck 		ret = -EINVAL;
4757eaf5077SJohn Fastabend 		goto err_out;
47633dbabc4SAlexander Duyck 	}
47733dbabc4SAlexander Duyck 
47833dbabc4SAlexander Duyck 	return 0;
47933dbabc4SAlexander Duyck nlmsg_failure:
48033dbabc4SAlexander Duyck err:
481858eb711SRoel Kluin 	kfree_skb(dcbnl_skb);
48233dbabc4SAlexander Duyck err_out:
48333dbabc4SAlexander Duyck 	return ret;
48433dbabc4SAlexander Duyck }
48533dbabc4SAlexander Duyck 
48633dbabc4SAlexander Duyck static int dcbnl_setnumtcs(struct net_device *netdev, struct nlattr **tb,
48733dbabc4SAlexander Duyck                            u32 pid, u32 seq, u16 flags)
48833dbabc4SAlexander Duyck {
48933dbabc4SAlexander Duyck 	struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1];
49033dbabc4SAlexander Duyck 	int ret = -EINVAL;
49133dbabc4SAlexander Duyck 	u8 value;
49233dbabc4SAlexander Duyck 	int i;
49333dbabc4SAlexander Duyck 
4948b124a8eSDon Skidmore 	if (!tb[DCB_ATTR_NUMTCS] || !netdev->dcbnl_ops->setnumtcs)
49533dbabc4SAlexander Duyck 		return ret;
49633dbabc4SAlexander Duyck 
49733dbabc4SAlexander Duyck 	ret = nla_parse_nested(data, DCB_NUMTCS_ATTR_MAX, tb[DCB_ATTR_NUMTCS],
49833dbabc4SAlexander Duyck 	                       dcbnl_numtcs_nest);
49933dbabc4SAlexander Duyck 
50033dbabc4SAlexander Duyck 	if (ret) {
50133dbabc4SAlexander Duyck 		ret = -EINVAL;
50233dbabc4SAlexander Duyck 		goto err;
50333dbabc4SAlexander Duyck 	}
50433dbabc4SAlexander Duyck 
50533dbabc4SAlexander Duyck 	for (i = DCB_NUMTCS_ATTR_ALL+1; i <= DCB_NUMTCS_ATTR_MAX; i++) {
50633dbabc4SAlexander Duyck 		if (data[i] == NULL)
50733dbabc4SAlexander Duyck 			continue;
50833dbabc4SAlexander Duyck 
50933dbabc4SAlexander Duyck 		value = nla_get_u8(data[i]);
51033dbabc4SAlexander Duyck 
51133dbabc4SAlexander Duyck 		ret = netdev->dcbnl_ops->setnumtcs(netdev, i, value);
51233dbabc4SAlexander Duyck 
51333dbabc4SAlexander Duyck 		if (ret)
51433dbabc4SAlexander Duyck 			goto operr;
51533dbabc4SAlexander Duyck 	}
51633dbabc4SAlexander Duyck 
51733dbabc4SAlexander Duyck operr:
51833dbabc4SAlexander Duyck 	ret = dcbnl_reply(!!ret, RTM_SETDCB, DCB_CMD_SNUMTCS,
51933dbabc4SAlexander Duyck 	                  DCB_ATTR_NUMTCS, pid, seq, flags);
52033dbabc4SAlexander Duyck 
52133dbabc4SAlexander Duyck err:
52233dbabc4SAlexander Duyck 	return ret;
52333dbabc4SAlexander Duyck }
52433dbabc4SAlexander Duyck 
5250eb3aa9bSAlexander Duyck static int dcbnl_getpfcstate(struct net_device *netdev, struct nlattr **tb,
5260eb3aa9bSAlexander Duyck                              u32 pid, u32 seq, u16 flags)
5270eb3aa9bSAlexander Duyck {
5280eb3aa9bSAlexander Duyck 	int ret = -EINVAL;
5290eb3aa9bSAlexander Duyck 
5300eb3aa9bSAlexander Duyck 	if (!netdev->dcbnl_ops->getpfcstate)
5310eb3aa9bSAlexander Duyck 		return ret;
5320eb3aa9bSAlexander Duyck 
5330eb3aa9bSAlexander Duyck 	ret = dcbnl_reply(netdev->dcbnl_ops->getpfcstate(netdev), RTM_GETDCB,
5340eb3aa9bSAlexander Duyck 	                  DCB_CMD_PFC_GSTATE, DCB_ATTR_PFC_STATE,
5350eb3aa9bSAlexander Duyck 	                  pid, seq, flags);
5360eb3aa9bSAlexander Duyck 
5370eb3aa9bSAlexander Duyck 	return ret;
5380eb3aa9bSAlexander Duyck }
5390eb3aa9bSAlexander Duyck 
5400eb3aa9bSAlexander Duyck static int dcbnl_setpfcstate(struct net_device *netdev, struct nlattr **tb,
5410eb3aa9bSAlexander Duyck                              u32 pid, u32 seq, u16 flags)
5420eb3aa9bSAlexander Duyck {
5430eb3aa9bSAlexander Duyck 	int ret = -EINVAL;
5440eb3aa9bSAlexander Duyck 	u8 value;
5450eb3aa9bSAlexander Duyck 
5460eb3aa9bSAlexander Duyck 	if (!tb[DCB_ATTR_PFC_STATE] || !netdev->dcbnl_ops->setpfcstate)
5470eb3aa9bSAlexander Duyck 		return ret;
5480eb3aa9bSAlexander Duyck 
5490eb3aa9bSAlexander Duyck 	value = nla_get_u8(tb[DCB_ATTR_PFC_STATE]);
5500eb3aa9bSAlexander Duyck 
5510eb3aa9bSAlexander Duyck 	netdev->dcbnl_ops->setpfcstate(netdev, value);
5520eb3aa9bSAlexander Duyck 
5530eb3aa9bSAlexander Duyck 	ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_PFC_SSTATE, DCB_ATTR_PFC_STATE,
5540eb3aa9bSAlexander Duyck 	                  pid, seq, flags);
5550eb3aa9bSAlexander Duyck 
5560eb3aa9bSAlexander Duyck 	return ret;
5570eb3aa9bSAlexander Duyck }
5580eb3aa9bSAlexander Duyck 
55957949686SYi Zou static int dcbnl_getapp(struct net_device *netdev, struct nlattr **tb,
56057949686SYi Zou                         u32 pid, u32 seq, u16 flags)
56157949686SYi Zou {
56257949686SYi Zou 	struct sk_buff *dcbnl_skb;
56357949686SYi Zou 	struct nlmsghdr *nlh;
56457949686SYi Zou 	struct dcbmsg *dcb;
56557949686SYi Zou 	struct nlattr *app_nest;
56657949686SYi Zou 	struct nlattr *app_tb[DCB_APP_ATTR_MAX + 1];
56757949686SYi Zou 	u16 id;
56857949686SYi Zou 	u8 up, idtype;
56957949686SYi Zou 	int ret = -EINVAL;
57057949686SYi Zou 
57157949686SYi Zou 	if (!tb[DCB_ATTR_APP] || !netdev->dcbnl_ops->getapp)
57257949686SYi Zou 		goto out;
57357949686SYi Zou 
57457949686SYi Zou 	ret = nla_parse_nested(app_tb, DCB_APP_ATTR_MAX, tb[DCB_ATTR_APP],
57557949686SYi Zou 	                       dcbnl_app_nest);
57657949686SYi Zou 	if (ret)
57757949686SYi Zou 		goto out;
57857949686SYi Zou 
57957949686SYi Zou 	ret = -EINVAL;
58057949686SYi Zou 	/* all must be non-null */
58157949686SYi Zou 	if ((!app_tb[DCB_APP_ATTR_IDTYPE]) ||
58257949686SYi Zou 	    (!app_tb[DCB_APP_ATTR_ID]))
58357949686SYi Zou 		goto out;
58457949686SYi Zou 
58557949686SYi Zou 	/* either by eth type or by socket number */
58657949686SYi Zou 	idtype = nla_get_u8(app_tb[DCB_APP_ATTR_IDTYPE]);
58757949686SYi Zou 	if ((idtype != DCB_APP_IDTYPE_ETHTYPE) &&
58857949686SYi Zou 	    (idtype != DCB_APP_IDTYPE_PORTNUM))
58957949686SYi Zou 		goto out;
59057949686SYi Zou 
59157949686SYi Zou 	id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]);
59257949686SYi Zou 	up = netdev->dcbnl_ops->getapp(netdev, idtype, id);
59357949686SYi Zou 
59457949686SYi Zou 	/* send this back */
59557949686SYi Zou 	dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
59657949686SYi Zou 	if (!dcbnl_skb)
59757949686SYi Zou 		goto out;
59857949686SYi Zou 
59957949686SYi Zou 	nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
60057949686SYi Zou 	dcb = NLMSG_DATA(nlh);
60157949686SYi Zou 	dcb->dcb_family = AF_UNSPEC;
60257949686SYi Zou 	dcb->cmd = DCB_CMD_GAPP;
60357949686SYi Zou 
60457949686SYi Zou 	app_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_APP);
60557949686SYi Zou 	ret = nla_put_u8(dcbnl_skb, DCB_APP_ATTR_IDTYPE, idtype);
60657949686SYi Zou 	if (ret)
60757949686SYi Zou 		goto out_cancel;
60857949686SYi Zou 
60957949686SYi Zou 	ret = nla_put_u16(dcbnl_skb, DCB_APP_ATTR_ID, id);
61057949686SYi Zou 	if (ret)
61157949686SYi Zou 		goto out_cancel;
61257949686SYi Zou 
61357949686SYi Zou 	ret = nla_put_u8(dcbnl_skb, DCB_APP_ATTR_PRIORITY, up);
61457949686SYi Zou 	if (ret)
61557949686SYi Zou 		goto out_cancel;
61657949686SYi Zou 
61757949686SYi Zou 	nla_nest_end(dcbnl_skb, app_nest);
61857949686SYi Zou 	nlmsg_end(dcbnl_skb, nlh);
61957949686SYi Zou 
62057949686SYi Zou 	ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
62157949686SYi Zou 	if (ret)
62257949686SYi Zou 		goto nlmsg_failure;
62357949686SYi Zou 
62457949686SYi Zou 	goto out;
62557949686SYi Zou 
62657949686SYi Zou out_cancel:
62757949686SYi Zou 	nla_nest_cancel(dcbnl_skb, app_nest);
62857949686SYi Zou nlmsg_failure:
62957949686SYi Zou 	kfree_skb(dcbnl_skb);
63057949686SYi Zou out:
63157949686SYi Zou 	return ret;
63257949686SYi Zou }
63357949686SYi Zou 
63457949686SYi Zou static int dcbnl_setapp(struct net_device *netdev, struct nlattr **tb,
63557949686SYi Zou                         u32 pid, u32 seq, u16 flags)
63657949686SYi Zou {
63757949686SYi Zou 	int ret = -EINVAL;
63857949686SYi Zou 	u16 id;
63957949686SYi Zou 	u8 up, idtype;
64057949686SYi Zou 	struct nlattr *app_tb[DCB_APP_ATTR_MAX + 1];
64157949686SYi Zou 
64257949686SYi Zou 	if (!tb[DCB_ATTR_APP] || !netdev->dcbnl_ops->setapp)
64357949686SYi Zou 		goto out;
64457949686SYi Zou 
64557949686SYi Zou 	ret = nla_parse_nested(app_tb, DCB_APP_ATTR_MAX, tb[DCB_ATTR_APP],
64657949686SYi Zou 	                       dcbnl_app_nest);
64757949686SYi Zou 	if (ret)
64857949686SYi Zou 		goto out;
64957949686SYi Zou 
65057949686SYi Zou 	ret = -EINVAL;
65157949686SYi Zou 	/* all must be non-null */
65257949686SYi Zou 	if ((!app_tb[DCB_APP_ATTR_IDTYPE]) ||
65357949686SYi Zou 	    (!app_tb[DCB_APP_ATTR_ID]) ||
65457949686SYi Zou 	    (!app_tb[DCB_APP_ATTR_PRIORITY]))
65557949686SYi Zou 		goto out;
65657949686SYi Zou 
65757949686SYi Zou 	/* either by eth type or by socket number */
65857949686SYi Zou 	idtype = nla_get_u8(app_tb[DCB_APP_ATTR_IDTYPE]);
65957949686SYi Zou 	if ((idtype != DCB_APP_IDTYPE_ETHTYPE) &&
66057949686SYi Zou 	    (idtype != DCB_APP_IDTYPE_PORTNUM))
66157949686SYi Zou 		goto out;
66257949686SYi Zou 
66357949686SYi Zou 	id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]);
66457949686SYi Zou 	up = nla_get_u8(app_tb[DCB_APP_ATTR_PRIORITY]);
66557949686SYi Zou 
66657949686SYi Zou 	ret = dcbnl_reply(netdev->dcbnl_ops->setapp(netdev, idtype, id, up),
66757949686SYi Zou 	                  RTM_SETDCB, DCB_CMD_SAPP, DCB_ATTR_APP,
66857949686SYi Zou 	                  pid, seq, flags);
66957949686SYi Zou out:
67057949686SYi Zou 	return ret;
67157949686SYi Zou }
67257949686SYi Zou 
6732f90b865SAlexander Duyck static int __dcbnl_pg_getcfg(struct net_device *netdev, struct nlattr **tb,
6742f90b865SAlexander Duyck                              u32 pid, u32 seq, u16 flags, int dir)
6752f90b865SAlexander Duyck {
6762f90b865SAlexander Duyck 	struct sk_buff *dcbnl_skb;
6772f90b865SAlexander Duyck 	struct nlmsghdr *nlh;
6782f90b865SAlexander Duyck 	struct dcbmsg *dcb;
6792f90b865SAlexander Duyck 	struct nlattr *pg_nest, *param_nest, *data;
6802f90b865SAlexander Duyck 	struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1];
6812f90b865SAlexander Duyck 	struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1];
6822f90b865SAlexander Duyck 	u8 prio, pgid, tc_pct, up_map;
6832f90b865SAlexander Duyck 	int ret  = -EINVAL;
6842f90b865SAlexander Duyck 	int getall = 0;
6852f90b865SAlexander Duyck 	int i;
6862f90b865SAlexander Duyck 
6872f90b865SAlexander Duyck 	if (!tb[DCB_ATTR_PG_CFG] ||
6882f90b865SAlexander Duyck 	    !netdev->dcbnl_ops->getpgtccfgtx ||
6892f90b865SAlexander Duyck 	    !netdev->dcbnl_ops->getpgtccfgrx ||
6902f90b865SAlexander Duyck 	    !netdev->dcbnl_ops->getpgbwgcfgtx ||
6912f90b865SAlexander Duyck 	    !netdev->dcbnl_ops->getpgbwgcfgrx)
6922f90b865SAlexander Duyck 		return ret;
6932f90b865SAlexander Duyck 
6942f90b865SAlexander Duyck 	ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX,
6952f90b865SAlexander Duyck 	                       tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest);
6962f90b865SAlexander Duyck 
6972f90b865SAlexander Duyck 	if (ret)
6982f90b865SAlexander Duyck 		goto err_out;
6992f90b865SAlexander Duyck 
7002f90b865SAlexander Duyck 	dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
7012f90b865SAlexander Duyck 	if (!dcbnl_skb)
7022f90b865SAlexander Duyck 		goto err_out;
7032f90b865SAlexander Duyck 
7042f90b865SAlexander Duyck 	nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
7052f90b865SAlexander Duyck 
7062f90b865SAlexander Duyck 	dcb = NLMSG_DATA(nlh);
7072f90b865SAlexander Duyck 	dcb->dcb_family = AF_UNSPEC;
7082f90b865SAlexander Duyck 	dcb->cmd = (dir) ? DCB_CMD_PGRX_GCFG : DCB_CMD_PGTX_GCFG;
7092f90b865SAlexander Duyck 
7102f90b865SAlexander Duyck 	pg_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_PG_CFG);
7112f90b865SAlexander Duyck 	if (!pg_nest)
7122f90b865SAlexander Duyck 		goto err;
7132f90b865SAlexander Duyck 
7142f90b865SAlexander Duyck 	if (pg_tb[DCB_PG_ATTR_TC_ALL])
7152f90b865SAlexander Duyck 		getall = 1;
7162f90b865SAlexander Duyck 
7172f90b865SAlexander Duyck 	for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) {
7182f90b865SAlexander Duyck 		if (!getall && !pg_tb[i])
7192f90b865SAlexander Duyck 			continue;
7202f90b865SAlexander Duyck 
7212f90b865SAlexander Duyck 		if (pg_tb[DCB_PG_ATTR_TC_ALL])
7222f90b865SAlexander Duyck 			data = pg_tb[DCB_PG_ATTR_TC_ALL];
7232f90b865SAlexander Duyck 		else
7242f90b865SAlexander Duyck 			data = pg_tb[i];
7252f90b865SAlexander Duyck 		ret = nla_parse_nested(param_tb, DCB_TC_ATTR_PARAM_MAX,
7262f90b865SAlexander Duyck 				       data, dcbnl_tc_param_nest);
7272f90b865SAlexander Duyck 		if (ret)
7282f90b865SAlexander Duyck 			goto err_pg;
7292f90b865SAlexander Duyck 
7302f90b865SAlexander Duyck 		param_nest = nla_nest_start(dcbnl_skb, i);
7312f90b865SAlexander Duyck 		if (!param_nest)
7322f90b865SAlexander Duyck 			goto err_pg;
7332f90b865SAlexander Duyck 
7342f90b865SAlexander Duyck 		pgid = DCB_ATTR_VALUE_UNDEFINED;
7352f90b865SAlexander Duyck 		prio = DCB_ATTR_VALUE_UNDEFINED;
7362f90b865SAlexander Duyck 		tc_pct = DCB_ATTR_VALUE_UNDEFINED;
7372f90b865SAlexander Duyck 		up_map = DCB_ATTR_VALUE_UNDEFINED;
7382f90b865SAlexander Duyck 
7392f90b865SAlexander Duyck 		if (dir) {
7402f90b865SAlexander Duyck 			/* Rx */
7412f90b865SAlexander Duyck 			netdev->dcbnl_ops->getpgtccfgrx(netdev,
7422f90b865SAlexander Duyck 						i - DCB_PG_ATTR_TC_0, &prio,
7432f90b865SAlexander Duyck 						&pgid, &tc_pct, &up_map);
7442f90b865SAlexander Duyck 		} else {
7452f90b865SAlexander Duyck 			/* Tx */
7462f90b865SAlexander Duyck 			netdev->dcbnl_ops->getpgtccfgtx(netdev,
7472f90b865SAlexander Duyck 						i - DCB_PG_ATTR_TC_0, &prio,
7482f90b865SAlexander Duyck 						&pgid, &tc_pct, &up_map);
7492f90b865SAlexander Duyck 		}
7502f90b865SAlexander Duyck 
7512f90b865SAlexander Duyck 		if (param_tb[DCB_TC_ATTR_PARAM_PGID] ||
7522f90b865SAlexander Duyck 		    param_tb[DCB_TC_ATTR_PARAM_ALL]) {
7532f90b865SAlexander Duyck 			ret = nla_put_u8(dcbnl_skb,
7542f90b865SAlexander Duyck 			                 DCB_TC_ATTR_PARAM_PGID, pgid);
7552f90b865SAlexander Duyck 			if (ret)
7562f90b865SAlexander Duyck 				goto err_param;
7572f90b865SAlexander Duyck 		}
7582f90b865SAlexander Duyck 		if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING] ||
7592f90b865SAlexander Duyck 		    param_tb[DCB_TC_ATTR_PARAM_ALL]) {
7602f90b865SAlexander Duyck 			ret = nla_put_u8(dcbnl_skb,
7612f90b865SAlexander Duyck 			                 DCB_TC_ATTR_PARAM_UP_MAPPING, up_map);
7622f90b865SAlexander Duyck 			if (ret)
7632f90b865SAlexander Duyck 				goto err_param;
7642f90b865SAlexander Duyck 		}
7652f90b865SAlexander Duyck 		if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO] ||
7662f90b865SAlexander Duyck 		    param_tb[DCB_TC_ATTR_PARAM_ALL]) {
7672f90b865SAlexander Duyck 			ret = nla_put_u8(dcbnl_skb,
7682f90b865SAlexander Duyck 			                 DCB_TC_ATTR_PARAM_STRICT_PRIO, prio);
7692f90b865SAlexander Duyck 			if (ret)
7702f90b865SAlexander Duyck 				goto err_param;
7712f90b865SAlexander Duyck 		}
7722f90b865SAlexander Duyck 		if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT] ||
7732f90b865SAlexander Duyck 		    param_tb[DCB_TC_ATTR_PARAM_ALL]) {
7742f90b865SAlexander Duyck 			ret = nla_put_u8(dcbnl_skb, DCB_TC_ATTR_PARAM_BW_PCT,
7752f90b865SAlexander Duyck 			                 tc_pct);
7762f90b865SAlexander Duyck 			if (ret)
7772f90b865SAlexander Duyck 				goto err_param;
7782f90b865SAlexander Duyck 		}
7792f90b865SAlexander Duyck 		nla_nest_end(dcbnl_skb, param_nest);
7802f90b865SAlexander Duyck 	}
7812f90b865SAlexander Duyck 
7822f90b865SAlexander Duyck 	if (pg_tb[DCB_PG_ATTR_BW_ID_ALL])
7832f90b865SAlexander Duyck 		getall = 1;
7842f90b865SAlexander Duyck 	else
7852f90b865SAlexander Duyck 		getall = 0;
7862f90b865SAlexander Duyck 
7872f90b865SAlexander Duyck 	for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) {
7882f90b865SAlexander Duyck 		if (!getall && !pg_tb[i])
7892f90b865SAlexander Duyck 			continue;
7902f90b865SAlexander Duyck 
7912f90b865SAlexander Duyck 		tc_pct = DCB_ATTR_VALUE_UNDEFINED;
7922f90b865SAlexander Duyck 
7932f90b865SAlexander Duyck 		if (dir) {
7942f90b865SAlexander Duyck 			/* Rx */
7952f90b865SAlexander Duyck 			netdev->dcbnl_ops->getpgbwgcfgrx(netdev,
7962f90b865SAlexander Duyck 					i - DCB_PG_ATTR_BW_ID_0, &tc_pct);
7972f90b865SAlexander Duyck 		} else {
7982f90b865SAlexander Duyck 			/* Tx */
7992f90b865SAlexander Duyck 			netdev->dcbnl_ops->getpgbwgcfgtx(netdev,
8002f90b865SAlexander Duyck 					i - DCB_PG_ATTR_BW_ID_0, &tc_pct);
8012f90b865SAlexander Duyck 		}
8022f90b865SAlexander Duyck 		ret = nla_put_u8(dcbnl_skb, i, tc_pct);
8032f90b865SAlexander Duyck 
8042f90b865SAlexander Duyck 		if (ret)
8052f90b865SAlexander Duyck 			goto err_pg;
8062f90b865SAlexander Duyck 	}
8072f90b865SAlexander Duyck 
8082f90b865SAlexander Duyck 	nla_nest_end(dcbnl_skb, pg_nest);
8092f90b865SAlexander Duyck 
8102f90b865SAlexander Duyck 	nlmsg_end(dcbnl_skb, nlh);
8112f90b865SAlexander Duyck 
8122f90b865SAlexander Duyck 	ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
8132f90b865SAlexander Duyck 	if (ret)
8147eaf5077SJohn Fastabend 		goto err_out;
8152f90b865SAlexander Duyck 
8162f90b865SAlexander Duyck 	return 0;
8172f90b865SAlexander Duyck 
8182f90b865SAlexander Duyck err_param:
8192f90b865SAlexander Duyck 	nla_nest_cancel(dcbnl_skb, param_nest);
8202f90b865SAlexander Duyck err_pg:
8212f90b865SAlexander Duyck 	nla_nest_cancel(dcbnl_skb, pg_nest);
8222f90b865SAlexander Duyck nlmsg_failure:
8232f90b865SAlexander Duyck err:
824858eb711SRoel Kluin 	kfree_skb(dcbnl_skb);
8252f90b865SAlexander Duyck err_out:
8262f90b865SAlexander Duyck 	ret  = -EINVAL;
8272f90b865SAlexander Duyck 	return ret;
8282f90b865SAlexander Duyck }
8292f90b865SAlexander Duyck 
8302f90b865SAlexander Duyck static int dcbnl_pgtx_getcfg(struct net_device *netdev, struct nlattr **tb,
8312f90b865SAlexander Duyck                              u32 pid, u32 seq, u16 flags)
8322f90b865SAlexander Duyck {
8332f90b865SAlexander Duyck 	return __dcbnl_pg_getcfg(netdev, tb, pid, seq, flags, 0);
8342f90b865SAlexander Duyck }
8352f90b865SAlexander Duyck 
8362f90b865SAlexander Duyck static int dcbnl_pgrx_getcfg(struct net_device *netdev, struct nlattr **tb,
8372f90b865SAlexander Duyck                              u32 pid, u32 seq, u16 flags)
8382f90b865SAlexander Duyck {
8392f90b865SAlexander Duyck 	return __dcbnl_pg_getcfg(netdev, tb, pid, seq, flags, 1);
8402f90b865SAlexander Duyck }
8412f90b865SAlexander Duyck 
8422f90b865SAlexander Duyck static int dcbnl_setstate(struct net_device *netdev, struct nlattr **tb,
8432f90b865SAlexander Duyck                           u32 pid, u32 seq, u16 flags)
8442f90b865SAlexander Duyck {
8452f90b865SAlexander Duyck 	int ret = -EINVAL;
8462f90b865SAlexander Duyck 	u8 value;
8472f90b865SAlexander Duyck 
8482f90b865SAlexander Duyck 	if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->setstate)
8492f90b865SAlexander Duyck 		return ret;
8502f90b865SAlexander Duyck 
8512f90b865SAlexander Duyck 	value = nla_get_u8(tb[DCB_ATTR_STATE]);
8522f90b865SAlexander Duyck 
8531486a61eSDon Skidmore 	ret = dcbnl_reply(netdev->dcbnl_ops->setstate(netdev, value),
8541486a61eSDon Skidmore 	                  RTM_SETDCB, DCB_CMD_SSTATE, DCB_ATTR_STATE,
8552f90b865SAlexander Duyck 	                  pid, seq, flags);
8562f90b865SAlexander Duyck 
8572f90b865SAlexander Duyck 	return ret;
8582f90b865SAlexander Duyck }
8592f90b865SAlexander Duyck 
8602f90b865SAlexander Duyck static int dcbnl_setpfccfg(struct net_device *netdev, struct nlattr **tb,
8612f90b865SAlexander Duyck                            u32 pid, u32 seq, u16 flags)
8622f90b865SAlexander Duyck {
8632f90b865SAlexander Duyck 	struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1];
8642f90b865SAlexander Duyck 	int i;
8652f90b865SAlexander Duyck 	int ret = -EINVAL;
8662f90b865SAlexander Duyck 	u8 value;
8672f90b865SAlexander Duyck 
8682f90b865SAlexander Duyck 	if (!tb[DCB_ATTR_PFC_CFG] || !netdev->dcbnl_ops->setpfccfg)
8692f90b865SAlexander Duyck 		return ret;
8702f90b865SAlexander Duyck 
8712f90b865SAlexander Duyck 	ret = nla_parse_nested(data, DCB_PFC_UP_ATTR_MAX,
8722f90b865SAlexander Duyck 	                       tb[DCB_ATTR_PFC_CFG],
8732f90b865SAlexander Duyck 	                       dcbnl_pfc_up_nest);
8742f90b865SAlexander Duyck 	if (ret)
8752f90b865SAlexander Duyck 		goto err;
8762f90b865SAlexander Duyck 
8772f90b865SAlexander Duyck 	for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) {
8782f90b865SAlexander Duyck 		if (data[i] == NULL)
8792f90b865SAlexander Duyck 			continue;
8802f90b865SAlexander Duyck 		value = nla_get_u8(data[i]);
8812f90b865SAlexander Duyck 		netdev->dcbnl_ops->setpfccfg(netdev,
8822f90b865SAlexander Duyck 			data[i]->nla_type - DCB_PFC_UP_ATTR_0, value);
8832f90b865SAlexander Duyck 	}
8842f90b865SAlexander Duyck 
8852f90b865SAlexander Duyck 	ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_PFC_SCFG, DCB_ATTR_PFC_CFG,
8862f90b865SAlexander Duyck 	                  pid, seq, flags);
8872f90b865SAlexander Duyck err:
8882f90b865SAlexander Duyck 	return ret;
8892f90b865SAlexander Duyck }
8902f90b865SAlexander Duyck 
8912f90b865SAlexander Duyck static int dcbnl_setall(struct net_device *netdev, struct nlattr **tb,
8922f90b865SAlexander Duyck                         u32 pid, u32 seq, u16 flags)
8932f90b865SAlexander Duyck {
8942f90b865SAlexander Duyck 	int ret = -EINVAL;
8952f90b865SAlexander Duyck 
8962f90b865SAlexander Duyck 	if (!tb[DCB_ATTR_SET_ALL] || !netdev->dcbnl_ops->setall)
8972f90b865SAlexander Duyck 		return ret;
8982f90b865SAlexander Duyck 
8992f90b865SAlexander Duyck 	ret = dcbnl_reply(netdev->dcbnl_ops->setall(netdev), RTM_SETDCB,
9002f90b865SAlexander Duyck 	                  DCB_CMD_SET_ALL, DCB_ATTR_SET_ALL, pid, seq, flags);
9012f90b865SAlexander Duyck 
9022f90b865SAlexander Duyck 	return ret;
9032f90b865SAlexander Duyck }
9042f90b865SAlexander Duyck 
9052f90b865SAlexander Duyck static int __dcbnl_pg_setcfg(struct net_device *netdev, struct nlattr **tb,
9062f90b865SAlexander Duyck                              u32 pid, u32 seq, u16 flags, int dir)
9072f90b865SAlexander Duyck {
9082f90b865SAlexander Duyck 	struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1];
9092f90b865SAlexander Duyck 	struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1];
9102f90b865SAlexander Duyck 	int ret = -EINVAL;
9112f90b865SAlexander Duyck 	int i;
9122f90b865SAlexander Duyck 	u8 pgid;
9132f90b865SAlexander Duyck 	u8 up_map;
9142f90b865SAlexander Duyck 	u8 prio;
9152f90b865SAlexander Duyck 	u8 tc_pct;
9162f90b865SAlexander Duyck 
9172f90b865SAlexander Duyck 	if (!tb[DCB_ATTR_PG_CFG] ||
9182f90b865SAlexander Duyck 	    !netdev->dcbnl_ops->setpgtccfgtx ||
9192f90b865SAlexander Duyck 	    !netdev->dcbnl_ops->setpgtccfgrx ||
9202f90b865SAlexander Duyck 	    !netdev->dcbnl_ops->setpgbwgcfgtx ||
9212f90b865SAlexander Duyck 	    !netdev->dcbnl_ops->setpgbwgcfgrx)
9222f90b865SAlexander Duyck 		return ret;
9232f90b865SAlexander Duyck 
9242f90b865SAlexander Duyck 	ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX,
9252f90b865SAlexander Duyck 	                       tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest);
9262f90b865SAlexander Duyck 	if (ret)
9272f90b865SAlexander Duyck 		goto err;
9282f90b865SAlexander Duyck 
9292f90b865SAlexander Duyck 	for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) {
9302f90b865SAlexander Duyck 		if (!pg_tb[i])
9312f90b865SAlexander Duyck 			continue;
9322f90b865SAlexander Duyck 
9332f90b865SAlexander Duyck 		ret = nla_parse_nested(param_tb, DCB_TC_ATTR_PARAM_MAX,
9342f90b865SAlexander Duyck 		                       pg_tb[i], dcbnl_tc_param_nest);
9352f90b865SAlexander Duyck 		if (ret)
9362f90b865SAlexander Duyck 			goto err;
9372f90b865SAlexander Duyck 
9382f90b865SAlexander Duyck 		pgid = DCB_ATTR_VALUE_UNDEFINED;
9392f90b865SAlexander Duyck 		prio = DCB_ATTR_VALUE_UNDEFINED;
9402f90b865SAlexander Duyck 		tc_pct = DCB_ATTR_VALUE_UNDEFINED;
9412f90b865SAlexander Duyck 		up_map = DCB_ATTR_VALUE_UNDEFINED;
9422f90b865SAlexander Duyck 
9432f90b865SAlexander Duyck 		if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO])
9442f90b865SAlexander Duyck 			prio =
9452f90b865SAlexander Duyck 			    nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO]);
9462f90b865SAlexander Duyck 
9472f90b865SAlexander Duyck 		if (param_tb[DCB_TC_ATTR_PARAM_PGID])
9482f90b865SAlexander Duyck 			pgid = nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_PGID]);
9492f90b865SAlexander Duyck 
9502f90b865SAlexander Duyck 		if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT])
9512f90b865SAlexander Duyck 			tc_pct = nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_BW_PCT]);
9522f90b865SAlexander Duyck 
9532f90b865SAlexander Duyck 		if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING])
9542f90b865SAlexander Duyck 			up_map =
9552f90b865SAlexander Duyck 			     nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING]);
9562f90b865SAlexander Duyck 
9572f90b865SAlexander Duyck 		/* dir: Tx = 0, Rx = 1 */
9582f90b865SAlexander Duyck 		if (dir) {
9592f90b865SAlexander Duyck 			/* Rx */
9602f90b865SAlexander Duyck 			netdev->dcbnl_ops->setpgtccfgrx(netdev,
9612f90b865SAlexander Duyck 				i - DCB_PG_ATTR_TC_0,
9622f90b865SAlexander Duyck 				prio, pgid, tc_pct, up_map);
9632f90b865SAlexander Duyck 		} else {
9642f90b865SAlexander Duyck 			/* Tx */
9652f90b865SAlexander Duyck 			netdev->dcbnl_ops->setpgtccfgtx(netdev,
9662f90b865SAlexander Duyck 				i - DCB_PG_ATTR_TC_0,
9672f90b865SAlexander Duyck 				prio, pgid, tc_pct, up_map);
9682f90b865SAlexander Duyck 		}
9692f90b865SAlexander Duyck 	}
9702f90b865SAlexander Duyck 
9712f90b865SAlexander Duyck 	for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) {
9722f90b865SAlexander Duyck 		if (!pg_tb[i])
9732f90b865SAlexander Duyck 			continue;
9742f90b865SAlexander Duyck 
9752f90b865SAlexander Duyck 		tc_pct = nla_get_u8(pg_tb[i]);
9762f90b865SAlexander Duyck 
9772f90b865SAlexander Duyck 		/* dir: Tx = 0, Rx = 1 */
9782f90b865SAlexander Duyck 		if (dir) {
9792f90b865SAlexander Duyck 			/* Rx */
9802f90b865SAlexander Duyck 			netdev->dcbnl_ops->setpgbwgcfgrx(netdev,
9812f90b865SAlexander Duyck 					 i - DCB_PG_ATTR_BW_ID_0, tc_pct);
9822f90b865SAlexander Duyck 		} else {
9832f90b865SAlexander Duyck 			/* Tx */
9842f90b865SAlexander Duyck 			netdev->dcbnl_ops->setpgbwgcfgtx(netdev,
9852f90b865SAlexander Duyck 					 i - DCB_PG_ATTR_BW_ID_0, tc_pct);
9862f90b865SAlexander Duyck 		}
9872f90b865SAlexander Duyck 	}
9882f90b865SAlexander Duyck 
9892f90b865SAlexander Duyck 	ret = dcbnl_reply(0, RTM_SETDCB,
9902f90b865SAlexander Duyck 			  (dir ? DCB_CMD_PGRX_SCFG : DCB_CMD_PGTX_SCFG),
9912f90b865SAlexander Duyck 			  DCB_ATTR_PG_CFG, pid, seq, flags);
9922f90b865SAlexander Duyck 
9932f90b865SAlexander Duyck err:
9942f90b865SAlexander Duyck 	return ret;
9952f90b865SAlexander Duyck }
9962f90b865SAlexander Duyck 
9972f90b865SAlexander Duyck static int dcbnl_pgtx_setcfg(struct net_device *netdev, struct nlattr **tb,
9982f90b865SAlexander Duyck                              u32 pid, u32 seq, u16 flags)
9992f90b865SAlexander Duyck {
10002f90b865SAlexander Duyck 	return __dcbnl_pg_setcfg(netdev, tb, pid, seq, flags, 0);
10012f90b865SAlexander Duyck }
10022f90b865SAlexander Duyck 
10032f90b865SAlexander Duyck static int dcbnl_pgrx_setcfg(struct net_device *netdev, struct nlattr **tb,
10042f90b865SAlexander Duyck                              u32 pid, u32 seq, u16 flags)
10052f90b865SAlexander Duyck {
10062f90b865SAlexander Duyck 	return __dcbnl_pg_setcfg(netdev, tb, pid, seq, flags, 1);
10072f90b865SAlexander Duyck }
10082f90b865SAlexander Duyck 
1009859ee3c4SAlexander Duyck static int dcbnl_bcn_getcfg(struct net_device *netdev, struct nlattr **tb,
1010859ee3c4SAlexander Duyck                             u32 pid, u32 seq, u16 flags)
1011859ee3c4SAlexander Duyck {
1012859ee3c4SAlexander Duyck 	struct sk_buff *dcbnl_skb;
1013859ee3c4SAlexander Duyck 	struct nlmsghdr *nlh;
1014859ee3c4SAlexander Duyck 	struct dcbmsg *dcb;
1015859ee3c4SAlexander Duyck 	struct nlattr *bcn_nest;
1016859ee3c4SAlexander Duyck 	struct nlattr *bcn_tb[DCB_BCN_ATTR_MAX + 1];
1017859ee3c4SAlexander Duyck 	u8 value_byte;
1018859ee3c4SAlexander Duyck 	u32 value_integer;
1019859ee3c4SAlexander Duyck 	int ret  = -EINVAL;
1020859ee3c4SAlexander Duyck 	bool getall = false;
1021859ee3c4SAlexander Duyck 	int i;
1022859ee3c4SAlexander Duyck 
1023859ee3c4SAlexander Duyck 	if (!tb[DCB_ATTR_BCN] || !netdev->dcbnl_ops->getbcnrp ||
1024859ee3c4SAlexander Duyck 	    !netdev->dcbnl_ops->getbcncfg)
1025859ee3c4SAlexander Duyck 		return ret;
1026859ee3c4SAlexander Duyck 
1027859ee3c4SAlexander Duyck 	ret = nla_parse_nested(bcn_tb, DCB_BCN_ATTR_MAX,
1028859ee3c4SAlexander Duyck 	                       tb[DCB_ATTR_BCN], dcbnl_bcn_nest);
1029859ee3c4SAlexander Duyck 
1030859ee3c4SAlexander Duyck 	if (ret)
1031859ee3c4SAlexander Duyck 		goto err_out;
1032859ee3c4SAlexander Duyck 
1033859ee3c4SAlexander Duyck 	dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1034859ee3c4SAlexander Duyck 	if (!dcbnl_skb)
1035859ee3c4SAlexander Duyck 		goto err_out;
1036859ee3c4SAlexander Duyck 
1037859ee3c4SAlexander Duyck 	nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
1038859ee3c4SAlexander Duyck 
1039859ee3c4SAlexander Duyck 	dcb = NLMSG_DATA(nlh);
1040859ee3c4SAlexander Duyck 	dcb->dcb_family = AF_UNSPEC;
1041859ee3c4SAlexander Duyck 	dcb->cmd = DCB_CMD_BCN_GCFG;
1042859ee3c4SAlexander Duyck 
1043859ee3c4SAlexander Duyck 	bcn_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_BCN);
1044859ee3c4SAlexander Duyck 	if (!bcn_nest)
1045859ee3c4SAlexander Duyck 		goto err;
1046859ee3c4SAlexander Duyck 
1047859ee3c4SAlexander Duyck 	if (bcn_tb[DCB_BCN_ATTR_ALL])
1048859ee3c4SAlexander Duyck 		getall = true;
1049859ee3c4SAlexander Duyck 
1050859ee3c4SAlexander Duyck 	for (i = DCB_BCN_ATTR_RP_0; i <= DCB_BCN_ATTR_RP_7; i++) {
1051859ee3c4SAlexander Duyck 		if (!getall && !bcn_tb[i])
1052859ee3c4SAlexander Duyck 			continue;
1053859ee3c4SAlexander Duyck 
1054859ee3c4SAlexander Duyck 		netdev->dcbnl_ops->getbcnrp(netdev, i - DCB_BCN_ATTR_RP_0,
1055859ee3c4SAlexander Duyck 		                            &value_byte);
1056859ee3c4SAlexander Duyck 		ret = nla_put_u8(dcbnl_skb, i, value_byte);
1057859ee3c4SAlexander Duyck 		if (ret)
1058859ee3c4SAlexander Duyck 			goto err_bcn;
1059859ee3c4SAlexander Duyck 	}
1060859ee3c4SAlexander Duyck 
1061f4314e81SDon Skidmore 	for (i = DCB_BCN_ATTR_BCNA_0; i <= DCB_BCN_ATTR_RI; i++) {
1062859ee3c4SAlexander Duyck 		if (!getall && !bcn_tb[i])
1063859ee3c4SAlexander Duyck 			continue;
1064859ee3c4SAlexander Duyck 
1065859ee3c4SAlexander Duyck 		netdev->dcbnl_ops->getbcncfg(netdev, i,
1066859ee3c4SAlexander Duyck 		                             &value_integer);
1067859ee3c4SAlexander Duyck 		ret = nla_put_u32(dcbnl_skb, i, value_integer);
1068859ee3c4SAlexander Duyck 		if (ret)
1069859ee3c4SAlexander Duyck 			goto err_bcn;
1070859ee3c4SAlexander Duyck 	}
1071859ee3c4SAlexander Duyck 
1072859ee3c4SAlexander Duyck 	nla_nest_end(dcbnl_skb, bcn_nest);
1073859ee3c4SAlexander Duyck 
1074859ee3c4SAlexander Duyck 	nlmsg_end(dcbnl_skb, nlh);
1075859ee3c4SAlexander Duyck 
1076859ee3c4SAlexander Duyck 	ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
1077859ee3c4SAlexander Duyck 	if (ret)
10787eaf5077SJohn Fastabend 		goto err_out;
1079859ee3c4SAlexander Duyck 
1080859ee3c4SAlexander Duyck 	return 0;
1081859ee3c4SAlexander Duyck 
1082859ee3c4SAlexander Duyck err_bcn:
1083859ee3c4SAlexander Duyck 	nla_nest_cancel(dcbnl_skb, bcn_nest);
1084859ee3c4SAlexander Duyck nlmsg_failure:
1085859ee3c4SAlexander Duyck err:
1086858eb711SRoel Kluin 	kfree_skb(dcbnl_skb);
1087859ee3c4SAlexander Duyck err_out:
1088859ee3c4SAlexander Duyck 	ret  = -EINVAL;
1089859ee3c4SAlexander Duyck 	return ret;
1090859ee3c4SAlexander Duyck }
1091859ee3c4SAlexander Duyck 
1092859ee3c4SAlexander Duyck static int dcbnl_bcn_setcfg(struct net_device *netdev, struct nlattr **tb,
1093859ee3c4SAlexander Duyck                             u32 pid, u32 seq, u16 flags)
1094859ee3c4SAlexander Duyck {
1095859ee3c4SAlexander Duyck 	struct nlattr *data[DCB_BCN_ATTR_MAX + 1];
1096859ee3c4SAlexander Duyck 	int i;
1097859ee3c4SAlexander Duyck 	int ret = -EINVAL;
1098859ee3c4SAlexander Duyck 	u8 value_byte;
1099859ee3c4SAlexander Duyck 	u32 value_int;
1100859ee3c4SAlexander Duyck 
1101f64f9e71SJoe Perches 	if (!tb[DCB_ATTR_BCN] || !netdev->dcbnl_ops->setbcncfg ||
1102f64f9e71SJoe Perches 	    !netdev->dcbnl_ops->setbcnrp)
1103859ee3c4SAlexander Duyck 		return ret;
1104859ee3c4SAlexander Duyck 
1105859ee3c4SAlexander Duyck 	ret = nla_parse_nested(data, DCB_BCN_ATTR_MAX,
1106859ee3c4SAlexander Duyck 	                       tb[DCB_ATTR_BCN],
1107859ee3c4SAlexander Duyck 	                       dcbnl_pfc_up_nest);
1108859ee3c4SAlexander Duyck 	if (ret)
1109859ee3c4SAlexander Duyck 		goto err;
1110859ee3c4SAlexander Duyck 
1111859ee3c4SAlexander Duyck 	for (i = DCB_BCN_ATTR_RP_0; i <= DCB_BCN_ATTR_RP_7; i++) {
1112859ee3c4SAlexander Duyck 		if (data[i] == NULL)
1113859ee3c4SAlexander Duyck 			continue;
1114859ee3c4SAlexander Duyck 		value_byte = nla_get_u8(data[i]);
1115859ee3c4SAlexander Duyck 		netdev->dcbnl_ops->setbcnrp(netdev,
1116859ee3c4SAlexander Duyck 			data[i]->nla_type - DCB_BCN_ATTR_RP_0, value_byte);
1117859ee3c4SAlexander Duyck 	}
1118859ee3c4SAlexander Duyck 
1119f4314e81SDon Skidmore 	for (i = DCB_BCN_ATTR_BCNA_0; i <= DCB_BCN_ATTR_RI; i++) {
1120859ee3c4SAlexander Duyck 		if (data[i] == NULL)
1121859ee3c4SAlexander Duyck 			continue;
1122859ee3c4SAlexander Duyck 		value_int = nla_get_u32(data[i]);
1123859ee3c4SAlexander Duyck 		netdev->dcbnl_ops->setbcncfg(netdev,
1124859ee3c4SAlexander Duyck 	                                     i, value_int);
1125859ee3c4SAlexander Duyck 	}
1126859ee3c4SAlexander Duyck 
1127859ee3c4SAlexander Duyck 	ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_BCN_SCFG, DCB_ATTR_BCN,
1128859ee3c4SAlexander Duyck 	                  pid, seq, flags);
1129859ee3c4SAlexander Duyck err:
1130859ee3c4SAlexander Duyck 	return ret;
1131859ee3c4SAlexander Duyck }
1132859ee3c4SAlexander Duyck 
11333e29027aSJohn Fastabend /* Handle IEEE 802.1Qaz SET commands. If any requested operation can not
11343e29027aSJohn Fastabend  * be completed the entire msg is aborted and error value is returned.
11353e29027aSJohn Fastabend  * No attempt is made to reconcile the case where only part of the
11363e29027aSJohn Fastabend  * cmd can be completed.
11373e29027aSJohn Fastabend  */
11383e29027aSJohn Fastabend static int dcbnl_ieee_set(struct net_device *netdev, struct nlattr **tb,
11393e29027aSJohn Fastabend 			  u32 pid, u32 seq, u16 flags)
11403e29027aSJohn Fastabend {
11413e29027aSJohn Fastabend 	const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
11423e29027aSJohn Fastabend 	struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1];
11433e29027aSJohn Fastabend 	int err = -EOPNOTSUPP;
11443e29027aSJohn Fastabend 
11453e29027aSJohn Fastabend 	if (!ops)
11463e29027aSJohn Fastabend 		goto err;
11473e29027aSJohn Fastabend 
11483e29027aSJohn Fastabend 	err = nla_parse_nested(ieee, DCB_ATTR_IEEE_MAX,
11493e29027aSJohn Fastabend 			       tb[DCB_ATTR_IEEE], dcbnl_ieee_policy);
11503e29027aSJohn Fastabend 	if (err)
11513e29027aSJohn Fastabend 		goto err;
11523e29027aSJohn Fastabend 
11533e29027aSJohn Fastabend 	if (ieee[DCB_ATTR_IEEE_ETS] && ops->ieee_setets) {
11543e29027aSJohn Fastabend 		struct ieee_ets *ets = nla_data(ieee[DCB_ATTR_IEEE_ETS]);
11553e29027aSJohn Fastabend 		err = ops->ieee_setets(netdev, ets);
11563e29027aSJohn Fastabend 		if (err)
11573e29027aSJohn Fastabend 			goto err;
11583e29027aSJohn Fastabend 	}
11593e29027aSJohn Fastabend 
11603e29027aSJohn Fastabend 	if (ieee[DCB_ATTR_IEEE_PFC] && ops->ieee_setets) {
11613e29027aSJohn Fastabend 		struct ieee_pfc *pfc = nla_data(ieee[DCB_ATTR_IEEE_PFC]);
11623e29027aSJohn Fastabend 		err = ops->ieee_setpfc(netdev, pfc);
11633e29027aSJohn Fastabend 		if (err)
11643e29027aSJohn Fastabend 			goto err;
11653e29027aSJohn Fastabend 	}
11663e29027aSJohn Fastabend 
11673e29027aSJohn Fastabend 	if (ieee[DCB_ATTR_IEEE_APP_TABLE] && ops->ieee_setapp) {
11683e29027aSJohn Fastabend 		struct nlattr *attr;
11693e29027aSJohn Fastabend 		int rem;
11703e29027aSJohn Fastabend 
11713e29027aSJohn Fastabend 		nla_for_each_nested(attr, ieee[DCB_ATTR_IEEE_APP_TABLE], rem) {
11723e29027aSJohn Fastabend 			struct dcb_app *app_data;
11733e29027aSJohn Fastabend 			if (nla_type(attr) != DCB_ATTR_IEEE_APP)
11743e29027aSJohn Fastabend 				continue;
11753e29027aSJohn Fastabend 			app_data = nla_data(attr);
11763e29027aSJohn Fastabend 			err = ops->ieee_setapp(netdev, app_data);
11773e29027aSJohn Fastabend 			if (err)
11783e29027aSJohn Fastabend 				goto err;
11793e29027aSJohn Fastabend 		}
11803e29027aSJohn Fastabend 	}
11813e29027aSJohn Fastabend 
11823e29027aSJohn Fastabend err:
11833e29027aSJohn Fastabend 	dcbnl_reply(err, RTM_SETDCB, DCB_CMD_IEEE_SET, DCB_ATTR_IEEE,
11843e29027aSJohn Fastabend 		    pid, seq, flags);
11853e29027aSJohn Fastabend 	return err;
11863e29027aSJohn Fastabend }
11873e29027aSJohn Fastabend 
11883e29027aSJohn Fastabend 
11893e29027aSJohn Fastabend /* Handle IEEE 802.1Qaz GET commands. */
11903e29027aSJohn Fastabend static int dcbnl_ieee_get(struct net_device *netdev, struct nlattr **tb,
11913e29027aSJohn Fastabend 			  u32 pid, u32 seq, u16 flags)
11923e29027aSJohn Fastabend {
11933e29027aSJohn Fastabend 	struct sk_buff *skb;
11943e29027aSJohn Fastabend 	struct nlmsghdr *nlh;
11953e29027aSJohn Fastabend 	struct dcbmsg *dcb;
11963e29027aSJohn Fastabend 	struct nlattr *ieee;
11973e29027aSJohn Fastabend 	const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
11983e29027aSJohn Fastabend 	int err;
11993e29027aSJohn Fastabend 
12003e29027aSJohn Fastabend 	if (!ops)
12013e29027aSJohn Fastabend 		return -EOPNOTSUPP;
12023e29027aSJohn Fastabend 
12033e29027aSJohn Fastabend 	skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
12043e29027aSJohn Fastabend 	if (!skb)
12053e29027aSJohn Fastabend 		return -ENOBUFS;
12063e29027aSJohn Fastabend 
12073e29027aSJohn Fastabend 	nlh = NLMSG_NEW(skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
12083e29027aSJohn Fastabend 
12093e29027aSJohn Fastabend 	dcb = NLMSG_DATA(nlh);
12103e29027aSJohn Fastabend 	dcb->dcb_family = AF_UNSPEC;
12113e29027aSJohn Fastabend 	dcb->cmd = DCB_CMD_IEEE_GET;
12123e29027aSJohn Fastabend 
12133e29027aSJohn Fastabend 	NLA_PUT_STRING(skb, DCB_ATTR_IFNAME, netdev->name);
12143e29027aSJohn Fastabend 
12153e29027aSJohn Fastabend 	ieee = nla_nest_start(skb, DCB_ATTR_IEEE);
12163e29027aSJohn Fastabend 	if (!ieee)
12173e29027aSJohn Fastabend 		goto nla_put_failure;
12183e29027aSJohn Fastabend 
12193e29027aSJohn Fastabend 	if (ops->ieee_getets) {
12203e29027aSJohn Fastabend 		struct ieee_ets ets;
12213e29027aSJohn Fastabend 		err = ops->ieee_getets(netdev, &ets);
12223e29027aSJohn Fastabend 		if (!err)
12233e29027aSJohn Fastabend 			NLA_PUT(skb, DCB_ATTR_IEEE_ETS, sizeof(ets), &ets);
12243e29027aSJohn Fastabend 	}
12253e29027aSJohn Fastabend 
12263e29027aSJohn Fastabend 	if (ops->ieee_getpfc) {
12273e29027aSJohn Fastabend 		struct ieee_pfc pfc;
12283e29027aSJohn Fastabend 		err = ops->ieee_getpfc(netdev, &pfc);
12293e29027aSJohn Fastabend 		if (!err)
12303e29027aSJohn Fastabend 			NLA_PUT(skb, DCB_ATTR_IEEE_PFC, sizeof(pfc), &pfc);
12313e29027aSJohn Fastabend 	}
12323e29027aSJohn Fastabend 
12333e29027aSJohn Fastabend 	nla_nest_end(skb, ieee);
12343e29027aSJohn Fastabend 	nlmsg_end(skb, nlh);
12353e29027aSJohn Fastabend 
12363e29027aSJohn Fastabend 	return rtnl_unicast(skb, &init_net, pid);
12373e29027aSJohn Fastabend nla_put_failure:
12383e29027aSJohn Fastabend 	nlmsg_cancel(skb, nlh);
12393e29027aSJohn Fastabend nlmsg_failure:
12403e29027aSJohn Fastabend 	kfree_skb(skb);
12413e29027aSJohn Fastabend 	return -1;
12423e29027aSJohn Fastabend }
12433e29027aSJohn Fastabend 
12442f90b865SAlexander Duyck static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
12452f90b865SAlexander Duyck {
12462f90b865SAlexander Duyck 	struct net *net = sock_net(skb->sk);
12472f90b865SAlexander Duyck 	struct net_device *netdev;
12482f90b865SAlexander Duyck 	struct dcbmsg  *dcb = (struct dcbmsg *)NLMSG_DATA(nlh);
12492f90b865SAlexander Duyck 	struct nlattr *tb[DCB_ATTR_MAX + 1];
12502f90b865SAlexander Duyck 	u32 pid = skb ? NETLINK_CB(skb).pid : 0;
12512f90b865SAlexander Duyck 	int ret = -EINVAL;
12522f90b865SAlexander Duyck 
125309ad9bc7SOctavian Purdila 	if (!net_eq(net, &init_net))
12542f90b865SAlexander Duyck 		return -EINVAL;
12552f90b865SAlexander Duyck 
12562f90b865SAlexander Duyck 	ret = nlmsg_parse(nlh, sizeof(*dcb), tb, DCB_ATTR_MAX,
12572f90b865SAlexander Duyck 			  dcbnl_rtnl_policy);
12582f90b865SAlexander Duyck 	if (ret < 0)
12592f90b865SAlexander Duyck 		return ret;
12602f90b865SAlexander Duyck 
12612f90b865SAlexander Duyck 	if (!tb[DCB_ATTR_IFNAME])
12622f90b865SAlexander Duyck 		return -EINVAL;
12632f90b865SAlexander Duyck 
12642f90b865SAlexander Duyck 	netdev = dev_get_by_name(&init_net, nla_data(tb[DCB_ATTR_IFNAME]));
12652f90b865SAlexander Duyck 	if (!netdev)
12662f90b865SAlexander Duyck 		return -EINVAL;
12672f90b865SAlexander Duyck 
12682f90b865SAlexander Duyck 	if (!netdev->dcbnl_ops)
12692f90b865SAlexander Duyck 		goto errout;
12702f90b865SAlexander Duyck 
12712f90b865SAlexander Duyck 	switch (dcb->cmd) {
12722f90b865SAlexander Duyck 	case DCB_CMD_GSTATE:
12732f90b865SAlexander Duyck 		ret = dcbnl_getstate(netdev, tb, pid, nlh->nlmsg_seq,
12742f90b865SAlexander Duyck 		                     nlh->nlmsg_flags);
12752f90b865SAlexander Duyck 		goto out;
12762f90b865SAlexander Duyck 	case DCB_CMD_PFC_GCFG:
12772f90b865SAlexander Duyck 		ret = dcbnl_getpfccfg(netdev, tb, pid, nlh->nlmsg_seq,
12782f90b865SAlexander Duyck 		                      nlh->nlmsg_flags);
12792f90b865SAlexander Duyck 		goto out;
12802f90b865SAlexander Duyck 	case DCB_CMD_GPERM_HWADDR:
12812f90b865SAlexander Duyck 		ret = dcbnl_getperm_hwaddr(netdev, tb, pid, nlh->nlmsg_seq,
12822f90b865SAlexander Duyck 		                           nlh->nlmsg_flags);
12832f90b865SAlexander Duyck 		goto out;
12842f90b865SAlexander Duyck 	case DCB_CMD_PGTX_GCFG:
12852f90b865SAlexander Duyck 		ret = dcbnl_pgtx_getcfg(netdev, tb, pid, nlh->nlmsg_seq,
12862f90b865SAlexander Duyck 		                        nlh->nlmsg_flags);
12872f90b865SAlexander Duyck 		goto out;
12882f90b865SAlexander Duyck 	case DCB_CMD_PGRX_GCFG:
12892f90b865SAlexander Duyck 		ret = dcbnl_pgrx_getcfg(netdev, tb, pid, nlh->nlmsg_seq,
12902f90b865SAlexander Duyck 		                        nlh->nlmsg_flags);
12912f90b865SAlexander Duyck 		goto out;
1292859ee3c4SAlexander Duyck 	case DCB_CMD_BCN_GCFG:
1293859ee3c4SAlexander Duyck 		ret = dcbnl_bcn_getcfg(netdev, tb, pid, nlh->nlmsg_seq,
1294859ee3c4SAlexander Duyck 		                       nlh->nlmsg_flags);
1295859ee3c4SAlexander Duyck 		goto out;
12962f90b865SAlexander Duyck 	case DCB_CMD_SSTATE:
12972f90b865SAlexander Duyck 		ret = dcbnl_setstate(netdev, tb, pid, nlh->nlmsg_seq,
12982f90b865SAlexander Duyck 		                     nlh->nlmsg_flags);
12992f90b865SAlexander Duyck 		goto out;
13002f90b865SAlexander Duyck 	case DCB_CMD_PFC_SCFG:
13012f90b865SAlexander Duyck 		ret = dcbnl_setpfccfg(netdev, tb, pid, nlh->nlmsg_seq,
13022f90b865SAlexander Duyck 		                      nlh->nlmsg_flags);
13032f90b865SAlexander Duyck 		goto out;
13042f90b865SAlexander Duyck 
13052f90b865SAlexander Duyck 	case DCB_CMD_SET_ALL:
13062f90b865SAlexander Duyck 		ret = dcbnl_setall(netdev, tb, pid, nlh->nlmsg_seq,
13072f90b865SAlexander Duyck 		                   nlh->nlmsg_flags);
13082f90b865SAlexander Duyck 		goto out;
13092f90b865SAlexander Duyck 	case DCB_CMD_PGTX_SCFG:
13102f90b865SAlexander Duyck 		ret = dcbnl_pgtx_setcfg(netdev, tb, pid, nlh->nlmsg_seq,
13112f90b865SAlexander Duyck 		                        nlh->nlmsg_flags);
13122f90b865SAlexander Duyck 		goto out;
13132f90b865SAlexander Duyck 	case DCB_CMD_PGRX_SCFG:
13142f90b865SAlexander Duyck 		ret = dcbnl_pgrx_setcfg(netdev, tb, pid, nlh->nlmsg_seq,
13152f90b865SAlexander Duyck 		                        nlh->nlmsg_flags);
13162f90b865SAlexander Duyck 		goto out;
131746132188SAlexander Duyck 	case DCB_CMD_GCAP:
131846132188SAlexander Duyck 		ret = dcbnl_getcap(netdev, tb, pid, nlh->nlmsg_seq,
131946132188SAlexander Duyck 		                   nlh->nlmsg_flags);
132046132188SAlexander Duyck 		goto out;
132133dbabc4SAlexander Duyck 	case DCB_CMD_GNUMTCS:
132233dbabc4SAlexander Duyck 		ret = dcbnl_getnumtcs(netdev, tb, pid, nlh->nlmsg_seq,
132333dbabc4SAlexander Duyck 		                      nlh->nlmsg_flags);
132433dbabc4SAlexander Duyck 		goto out;
132533dbabc4SAlexander Duyck 	case DCB_CMD_SNUMTCS:
132633dbabc4SAlexander Duyck 		ret = dcbnl_setnumtcs(netdev, tb, pid, nlh->nlmsg_seq,
132733dbabc4SAlexander Duyck 		                      nlh->nlmsg_flags);
132833dbabc4SAlexander Duyck 		goto out;
13290eb3aa9bSAlexander Duyck 	case DCB_CMD_PFC_GSTATE:
13300eb3aa9bSAlexander Duyck 		ret = dcbnl_getpfcstate(netdev, tb, pid, nlh->nlmsg_seq,
13310eb3aa9bSAlexander Duyck 		                        nlh->nlmsg_flags);
13320eb3aa9bSAlexander Duyck 		goto out;
13330eb3aa9bSAlexander Duyck 	case DCB_CMD_PFC_SSTATE:
13340eb3aa9bSAlexander Duyck 		ret = dcbnl_setpfcstate(netdev, tb, pid, nlh->nlmsg_seq,
13350eb3aa9bSAlexander Duyck 		                        nlh->nlmsg_flags);
13360eb3aa9bSAlexander Duyck 		goto out;
1337859ee3c4SAlexander Duyck 	case DCB_CMD_BCN_SCFG:
1338859ee3c4SAlexander Duyck 		ret = dcbnl_bcn_setcfg(netdev, tb, pid, nlh->nlmsg_seq,
1339859ee3c4SAlexander Duyck 		                       nlh->nlmsg_flags);
1340859ee3c4SAlexander Duyck 		goto out;
134157949686SYi Zou 	case DCB_CMD_GAPP:
134257949686SYi Zou 		ret = dcbnl_getapp(netdev, tb, pid, nlh->nlmsg_seq,
134357949686SYi Zou 		                   nlh->nlmsg_flags);
134457949686SYi Zou 		goto out;
134557949686SYi Zou 	case DCB_CMD_SAPP:
134657949686SYi Zou 		ret = dcbnl_setapp(netdev, tb, pid, nlh->nlmsg_seq,
134757949686SYi Zou 		                   nlh->nlmsg_flags);
134857949686SYi Zou 		goto out;
13493e29027aSJohn Fastabend 	case DCB_CMD_IEEE_SET:
13503e29027aSJohn Fastabend 		ret = dcbnl_ieee_set(netdev, tb, pid, nlh->nlmsg_seq,
13513e29027aSJohn Fastabend 				 nlh->nlmsg_flags);
13523e29027aSJohn Fastabend 		goto out;
13533e29027aSJohn Fastabend 	case DCB_CMD_IEEE_GET:
13543e29027aSJohn Fastabend 		ret = dcbnl_ieee_get(netdev, tb, pid, nlh->nlmsg_seq,
13553e29027aSJohn Fastabend 				 nlh->nlmsg_flags);
13563e29027aSJohn Fastabend 		goto out;
13572f90b865SAlexander Duyck 	default:
13582f90b865SAlexander Duyck 		goto errout;
13592f90b865SAlexander Duyck 	}
13602f90b865SAlexander Duyck errout:
13612f90b865SAlexander Duyck 	ret = -EINVAL;
13622f90b865SAlexander Duyck out:
13632f90b865SAlexander Duyck 	dev_put(netdev);
13642f90b865SAlexander Duyck 	return ret;
13652f90b865SAlexander Duyck }
13662f90b865SAlexander Duyck 
13672f90b865SAlexander Duyck static int __init dcbnl_init(void)
13682f90b865SAlexander Duyck {
13692f90b865SAlexander Duyck 	rtnl_register(PF_UNSPEC, RTM_GETDCB, dcb_doit, NULL);
13702f90b865SAlexander Duyck 	rtnl_register(PF_UNSPEC, RTM_SETDCB, dcb_doit, NULL);
13712f90b865SAlexander Duyck 
13722f90b865SAlexander Duyck 	return 0;
13732f90b865SAlexander Duyck }
13742f90b865SAlexander Duyck module_init(dcbnl_init);
13752f90b865SAlexander Duyck 
13762f90b865SAlexander Duyck static void __exit dcbnl_exit(void)
13772f90b865SAlexander Duyck {
13782f90b865SAlexander Duyck 	rtnl_unregister(PF_UNSPEC, RTM_GETDCB);
13792f90b865SAlexander Duyck 	rtnl_unregister(PF_UNSPEC, RTM_SETDCB);
13802f90b865SAlexander Duyck }
13812f90b865SAlexander Duyck module_exit(dcbnl_exit);
13822f90b865SAlexander Duyck 
13832f90b865SAlexander Duyck 
1384