dcbnl.c revision 0eb3aa9bab20217fb42244ccdcb5bf8a002f504c
12f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck/*
22f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck * Copyright (c) 2008, Intel Corporation.
32f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck *
42f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck * This program is free software; you can redistribute it and/or modify it
52f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck * under the terms and conditions of the GNU General Public License,
62f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck * version 2, as published by the Free Software Foundation.
72f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck *
82f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck * This program is distributed in the hope it will be useful, but WITHOUT
92f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
102f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
112f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck * more details.
122f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck *
132f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck * You should have received a copy of the GNU General Public License along with
142f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
152f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck * Place - Suite 330, Boston, MA 02111-1307 USA.
162f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck *
172f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck * Author: Lucy Liu <lucy.liu@intel.com>
182f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck */
192f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
202f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck#include <linux/netdevice.h>
212f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck#include <linux/netlink.h>
222f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck#include <net/netlink.h>
232f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck#include <net/rtnetlink.h>
242f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck#include <linux/dcbnl.h>
252f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck#include <linux/rtnetlink.h>
262f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck#include <net/sock.h>
272f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
282f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck/**
292f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck * Data Center Bridging (DCB) is a collection of Ethernet enhancements
302f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck * intended to allow network traffic with differing requirements
312f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck * (highly reliable, no drops vs. best effort vs. low latency) to operate
322f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck * and co-exist on Ethernet.  Current DCB features are:
332f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck *
342f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck * Enhanced Transmission Selection (aka Priority Grouping [PG]) - provides a
352f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck *   framework for assigning bandwidth guarantees to traffic classes.
362f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck *
372f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck * Priority-based Flow Control (PFC) - provides a flow control mechanism which
382f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck *   can work independently for each 802.1p priority.
392f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck *
402f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck * Congestion Notification - provides a mechanism for end-to-end congestion
412f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck *   control for protocols which do not have built-in congestion management.
422f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck *
432f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck * More information about the emerging standards for these Ethernet features
442f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck * can be found at: http://www.ieee802.org/1/pages/dcbridges.html
452f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck *
462f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck * This file implements an rtnetlink interface to allow configuration of DCB
472f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck * features for capable devices.
482f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck */
492f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
502f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander DuyckMODULE_AUTHOR("Lucy Liu, <lucy.liu@intel.com>");
512f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander DuyckMODULE_DESCRIPTION("Data Center Bridging generic netlink interface");
522f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander DuyckMODULE_LICENSE("GPL");
532f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
542f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck/**************** DCB attribute policies *************************************/
552f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
562f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck/* DCB netlink attributes policy */
572f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyckstatic struct nla_policy dcbnl_rtnl_policy[DCB_ATTR_MAX + 1] = {
582f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	[DCB_ATTR_IFNAME]    = {.type = NLA_STRING, .len = IFNAMSIZ - 1},
592f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	[DCB_ATTR_STATE]     = {.type = NLA_U8},
602f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	[DCB_ATTR_PFC_CFG]   = {.type = NLA_NESTED},
612f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	[DCB_ATTR_PG_CFG]    = {.type = NLA_NESTED},
622f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	[DCB_ATTR_SET_ALL]   = {.type = NLA_U8},
632f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	[DCB_ATTR_PERM_HWADDR] = {.type = NLA_FLAG},
6446132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck	[DCB_ATTR_CAP]       = {.type = NLA_NESTED},
650eb3aa9bab20217fb42244ccdcb5bf8a002f504cAlexander Duyck	[DCB_ATTR_PFC_STATE] = {.type = NLA_U8},
662f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck};
672f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
682f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck/* DCB priority flow control to User Priority nested attributes */
692f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyckstatic struct nla_policy dcbnl_pfc_up_nest[DCB_PFC_UP_ATTR_MAX + 1] = {
702f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	[DCB_PFC_UP_ATTR_0]   = {.type = NLA_U8},
712f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	[DCB_PFC_UP_ATTR_1]   = {.type = NLA_U8},
722f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	[DCB_PFC_UP_ATTR_2]   = {.type = NLA_U8},
732f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	[DCB_PFC_UP_ATTR_3]   = {.type = NLA_U8},
742f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	[DCB_PFC_UP_ATTR_4]   = {.type = NLA_U8},
752f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	[DCB_PFC_UP_ATTR_5]   = {.type = NLA_U8},
762f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	[DCB_PFC_UP_ATTR_6]   = {.type = NLA_U8},
772f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	[DCB_PFC_UP_ATTR_7]   = {.type = NLA_U8},
782f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	[DCB_PFC_UP_ATTR_ALL] = {.type = NLA_FLAG},
792f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck};
802f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
812f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck/* DCB priority grouping nested attributes */
822f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyckstatic struct nla_policy dcbnl_pg_nest[DCB_PG_ATTR_MAX + 1] = {
832f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	[DCB_PG_ATTR_TC_0]      = {.type = NLA_NESTED},
842f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	[DCB_PG_ATTR_TC_1]      = {.type = NLA_NESTED},
852f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	[DCB_PG_ATTR_TC_2]      = {.type = NLA_NESTED},
862f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	[DCB_PG_ATTR_TC_3]      = {.type = NLA_NESTED},
872f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	[DCB_PG_ATTR_TC_4]      = {.type = NLA_NESTED},
882f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	[DCB_PG_ATTR_TC_5]      = {.type = NLA_NESTED},
892f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	[DCB_PG_ATTR_TC_6]      = {.type = NLA_NESTED},
902f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	[DCB_PG_ATTR_TC_7]      = {.type = NLA_NESTED},
912f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	[DCB_PG_ATTR_TC_ALL]    = {.type = NLA_NESTED},
922f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	[DCB_PG_ATTR_BW_ID_0]   = {.type = NLA_U8},
932f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	[DCB_PG_ATTR_BW_ID_1]   = {.type = NLA_U8},
942f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	[DCB_PG_ATTR_BW_ID_2]   = {.type = NLA_U8},
952f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	[DCB_PG_ATTR_BW_ID_3]   = {.type = NLA_U8},
962f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	[DCB_PG_ATTR_BW_ID_4]   = {.type = NLA_U8},
972f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	[DCB_PG_ATTR_BW_ID_5]   = {.type = NLA_U8},
982f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	[DCB_PG_ATTR_BW_ID_6]   = {.type = NLA_U8},
992f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	[DCB_PG_ATTR_BW_ID_7]   = {.type = NLA_U8},
1002f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	[DCB_PG_ATTR_BW_ID_ALL] = {.type = NLA_FLAG},
1012f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck};
1022f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
1032f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck/* DCB traffic class nested attributes. */
1042f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyckstatic struct nla_policy dcbnl_tc_param_nest[DCB_TC_ATTR_PARAM_MAX + 1] = {
1052f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	[DCB_TC_ATTR_PARAM_PGID]            = {.type = NLA_U8},
1062f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	[DCB_TC_ATTR_PARAM_UP_MAPPING]      = {.type = NLA_U8},
1072f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	[DCB_TC_ATTR_PARAM_STRICT_PRIO]     = {.type = NLA_U8},
1082f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	[DCB_TC_ATTR_PARAM_BW_PCT]          = {.type = NLA_U8},
1092f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	[DCB_TC_ATTR_PARAM_ALL]             = {.type = NLA_FLAG},
1102f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck};
1112f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
11246132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck/* DCB capabilities nested attributes. */
11346132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyckstatic struct nla_policy dcbnl_cap_nest[DCB_CAP_ATTR_MAX + 1] = {
11446132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck	[DCB_CAP_ATTR_ALL]     = {.type = NLA_FLAG},
11546132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck	[DCB_CAP_ATTR_PG]      = {.type = NLA_U8},
11646132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck	[DCB_CAP_ATTR_PFC]     = {.type = NLA_U8},
11746132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck	[DCB_CAP_ATTR_UP2TC]   = {.type = NLA_U8},
11846132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck	[DCB_CAP_ATTR_PG_TCS]  = {.type = NLA_U8},
11946132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck	[DCB_CAP_ATTR_PFC_TCS] = {.type = NLA_U8},
12046132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck	[DCB_CAP_ATTR_GSP]     = {.type = NLA_U8},
12146132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck	[DCB_CAP_ATTR_BCN]     = {.type = NLA_U8},
12246132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck};
1232f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
12433dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck/* DCB capabilities nested attributes. */
12533dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyckstatic struct nla_policy dcbnl_numtcs_nest[DCB_NUMTCS_ATTR_MAX + 1] = {
12633dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	[DCB_NUMTCS_ATTR_ALL]     = {.type = NLA_FLAG},
12733dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	[DCB_NUMTCS_ATTR_PG]      = {.type = NLA_U8},
12833dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	[DCB_NUMTCS_ATTR_PFC]     = {.type = NLA_U8},
12933dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck};
13033dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck
1312f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck/* standard netlink reply call */
1322f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyckstatic int dcbnl_reply(u8 value, u8 event, u8 cmd, u8 attr, u32 pid,
1332f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck                       u32 seq, u16 flags)
1342f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck{
1352f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	struct sk_buff *dcbnl_skb;
1362f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	struct dcbmsg *dcb;
1372f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	struct nlmsghdr *nlh;
1382f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	int ret = -EINVAL;
1392f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
1402f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1412f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	if (!dcbnl_skb)
1422f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		return ret;
1432f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
1442f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	nlh = NLMSG_NEW(dcbnl_skb, pid, seq, event, sizeof(*dcb), flags);
1452f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
1462f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	dcb = NLMSG_DATA(nlh);
1472f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	dcb->dcb_family = AF_UNSPEC;
1482f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	dcb->cmd = cmd;
1492f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	dcb->dcb_pad = 0;
1502f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
1512f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	ret = nla_put_u8(dcbnl_skb, attr, value);
1522f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	if (ret)
1532f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		goto err;
1542f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
1552f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	/* end the message, assign the nlmsg_len. */
1562f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	nlmsg_end(dcbnl_skb, nlh);
1572f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
1582f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	if (ret)
1592f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		goto err;
1602f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
1612f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	return 0;
1622f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duycknlmsg_failure:
1632f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyckerr:
1642f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	kfree(dcbnl_skb);
1652f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	return ret;
1662f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck}
1672f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
1682f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyckstatic int dcbnl_getstate(struct net_device *netdev, struct nlattr **tb,
1692f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck                          u32 pid, u32 seq, u16 flags)
1702f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck{
1712f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	int ret = -EINVAL;
1722f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
1732f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	/* if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->getstate) */
1742f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	if (!netdev->dcbnl_ops->getstate)
1752f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		return ret;
1762f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
1772f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	ret = dcbnl_reply(netdev->dcbnl_ops->getstate(netdev), RTM_GETDCB,
1782f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	                  DCB_CMD_GSTATE, DCB_ATTR_STATE, pid, seq, flags);
1792f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
1802f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	return ret;
1812f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck}
1822f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
1832f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyckstatic int dcbnl_getpfccfg(struct net_device *netdev, struct nlattr **tb,
1842f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck                           u32 pid, u32 seq, u16 flags)
1852f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck{
1862f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	struct sk_buff *dcbnl_skb;
1872f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	struct nlmsghdr *nlh;
1882f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	struct dcbmsg *dcb;
1892f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1], *nest;
1902f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	u8 value;
1912f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	int ret = -EINVAL;
1922f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	int i;
1932f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	int getall = 0;
1942f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
1952f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	if (!tb[DCB_ATTR_PFC_CFG] || !netdev->dcbnl_ops->getpfccfg)
1962f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		return ret;
1972f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
1982f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	ret = nla_parse_nested(data, DCB_PFC_UP_ATTR_MAX,
1992f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	                       tb[DCB_ATTR_PFC_CFG],
2002f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	                       dcbnl_pfc_up_nest);
2012f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	if (ret)
2022f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		goto err_out;
2032f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
2042f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
2052f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	if (!dcbnl_skb)
2062f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		goto err_out;
2072f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
2082f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
2092f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
2102f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	dcb = NLMSG_DATA(nlh);
2112f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	dcb->dcb_family = AF_UNSPEC;
2122f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	dcb->cmd = DCB_CMD_PFC_GCFG;
2132f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
2142f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	nest = nla_nest_start(dcbnl_skb, DCB_ATTR_PFC_CFG);
2152f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	if (!nest)
2162f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		goto err;
2172f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
2182f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	if (data[DCB_PFC_UP_ATTR_ALL])
2192f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		getall = 1;
2202f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
2212f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) {
2222f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		if (!getall && !data[i])
2232f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			continue;
2242f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
2252f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		netdev->dcbnl_ops->getpfccfg(netdev, i - DCB_PFC_UP_ATTR_0,
2262f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		                             &value);
2272f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		ret = nla_put_u8(dcbnl_skb, i, value);
2282f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
2292f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		if (ret) {
2302f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			nla_nest_cancel(dcbnl_skb, nest);
2312f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			goto err;
2322f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		}
2332f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	}
2342f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	nla_nest_end(dcbnl_skb, nest);
2352f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
2362f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	nlmsg_end(dcbnl_skb, nlh);
2372f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
2382f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
2392f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	if (ret)
2402f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		goto err;
2412f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
2422f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	return 0;
2432f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duycknlmsg_failure:
2442f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyckerr:
2452f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	kfree(dcbnl_skb);
2462f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyckerr_out:
2472f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	return -EINVAL;
2482f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck}
2492f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
2502f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyckstatic int dcbnl_getperm_hwaddr(struct net_device *netdev, struct nlattr **tb,
2512f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck                                u32 pid, u32 seq, u16 flags)
2522f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck{
2532f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	struct sk_buff *dcbnl_skb;
2542f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	struct nlmsghdr *nlh;
2552f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	struct dcbmsg *dcb;
2562f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	u8 perm_addr[MAX_ADDR_LEN];
2572f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	int ret = -EINVAL;
2582f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
2592f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	if (!netdev->dcbnl_ops->getpermhwaddr)
2602f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		return ret;
2612f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
2622f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
2632f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	if (!dcbnl_skb)
2642f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		goto err_out;
2652f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
2662f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
2672f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
2682f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	dcb = NLMSG_DATA(nlh);
2692f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	dcb->dcb_family = AF_UNSPEC;
2702f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	dcb->cmd = DCB_CMD_GPERM_HWADDR;
2712f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
2722f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	netdev->dcbnl_ops->getpermhwaddr(netdev, perm_addr);
2732f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
2742f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	ret = nla_put(dcbnl_skb, DCB_ATTR_PERM_HWADDR, sizeof(perm_addr),
2752f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	              perm_addr);
2762f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
2772f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	nlmsg_end(dcbnl_skb, nlh);
2782f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
2792f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
2802f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	if (ret)
2812f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		goto err;
2822f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
2832f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	return 0;
2842f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
2852f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duycknlmsg_failure:
2862f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyckerr:
2872f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	kfree(dcbnl_skb);
2882f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyckerr_out:
2892f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	return -EINVAL;
2902f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck}
2912f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
29246132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyckstatic int dcbnl_getcap(struct net_device *netdev, struct nlattr **tb,
29346132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck                        u32 pid, u32 seq, u16 flags)
29446132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck{
29546132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck	struct sk_buff *dcbnl_skb;
29646132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck	struct nlmsghdr *nlh;
29746132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck	struct dcbmsg *dcb;
29846132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck	struct nlattr *data[DCB_CAP_ATTR_MAX + 1], *nest;
29946132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck	u8 value;
30046132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck	int ret = -EINVAL;
30146132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck	int i;
30246132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck	int getall = 0;
30346132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck
30446132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck	if (!tb[DCB_ATTR_CAP] || !netdev->dcbnl_ops->getcap)
30546132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck		return ret;
30646132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck
30746132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck	ret = nla_parse_nested(data, DCB_CAP_ATTR_MAX, tb[DCB_ATTR_CAP],
30846132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck	                       dcbnl_cap_nest);
30946132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck	if (ret)
31046132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck		goto err_out;
31146132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck
31246132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck	dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
31346132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck	if (!dcbnl_skb)
31446132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck		goto err_out;
31546132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck
31646132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck	nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
31746132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck
31846132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck	dcb = NLMSG_DATA(nlh);
31946132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck	dcb->dcb_family = AF_UNSPEC;
32046132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck	dcb->cmd = DCB_CMD_GCAP;
32146132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck
32246132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck	nest = nla_nest_start(dcbnl_skb, DCB_ATTR_CAP);
32346132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck	if (!nest)
32446132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck		goto err;
32546132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck
32646132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck	if (data[DCB_CAP_ATTR_ALL])
32746132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck		getall = 1;
32846132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck
32946132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck	for (i = DCB_CAP_ATTR_ALL+1; i <= DCB_CAP_ATTR_MAX; i++) {
33046132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck		if (!getall && !data[i])
33146132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck			continue;
33246132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck
33346132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck		if (!netdev->dcbnl_ops->getcap(netdev, i, &value)) {
33446132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck			ret = nla_put_u8(dcbnl_skb, i, value);
33546132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck
33646132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck			if (ret) {
33746132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck				nla_nest_cancel(dcbnl_skb, nest);
33846132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck				goto err;
33946132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck			}
34046132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck		}
34146132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck	}
34246132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck	nla_nest_end(dcbnl_skb, nest);
34346132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck
34446132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck	nlmsg_end(dcbnl_skb, nlh);
34546132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck
34646132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck	ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
34746132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck	if (ret)
34846132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck		goto err;
34946132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck
35046132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck	return 0;
35146132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duycknlmsg_failure:
35246132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyckerr:
35346132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck	kfree(dcbnl_skb);
35446132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyckerr_out:
35546132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck	return -EINVAL;
35646132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck}
35746132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck
35833dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyckstatic int dcbnl_getnumtcs(struct net_device *netdev, struct nlattr **tb,
35933dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck                           u32 pid, u32 seq, u16 flags)
36033dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck{
36133dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	struct sk_buff *dcbnl_skb;
36233dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	struct nlmsghdr *nlh;
36333dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	struct dcbmsg *dcb;
36433dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1], *nest;
36533dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	u8 value;
36633dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	int ret = -EINVAL;
36733dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	int i;
36833dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	int getall = 0;
36933dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck
37033dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	if (!tb[DCB_ATTR_NUMTCS] || !netdev->dcbnl_ops->getnumtcs)
37133dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck		return ret;
37233dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck
37333dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	ret = nla_parse_nested(data, DCB_NUMTCS_ATTR_MAX, tb[DCB_ATTR_NUMTCS],
37433dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	                       dcbnl_numtcs_nest);
37533dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	if (ret) {
37633dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck		ret = -EINVAL;
37733dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck		goto err_out;
37833dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	}
37933dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck
38033dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
38133dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	if (!dcbnl_skb) {
38233dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck		ret = -EINVAL;
38333dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck		goto err_out;
38433dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	}
38533dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck
38633dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
38733dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck
38833dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	dcb = NLMSG_DATA(nlh);
38933dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	dcb->dcb_family = AF_UNSPEC;
39033dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	dcb->cmd = DCB_CMD_GNUMTCS;
39133dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck
39233dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	nest = nla_nest_start(dcbnl_skb, DCB_ATTR_NUMTCS);
39333dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	if (!nest) {
39433dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck		ret = -EINVAL;
39533dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck		goto err;
39633dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	}
39733dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck
39833dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	if (data[DCB_NUMTCS_ATTR_ALL])
39933dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck		getall = 1;
40033dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck
40133dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	for (i = DCB_NUMTCS_ATTR_ALL+1; i <= DCB_NUMTCS_ATTR_MAX; i++) {
40233dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck		if (!getall && !data[i])
40333dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck			continue;
40433dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck
40533dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck		ret = netdev->dcbnl_ops->getnumtcs(netdev, i, &value);
40633dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck		if (!ret) {
40733dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck			ret = nla_put_u8(dcbnl_skb, i, value);
40833dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck
40933dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck			if (ret) {
41033dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck				nla_nest_cancel(dcbnl_skb, nest);
41133dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck				ret = -EINVAL;
41233dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck				goto err;
41333dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck			}
41433dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck		} else {
41533dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck			goto err;
41633dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck		}
41733dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	}
41833dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	nla_nest_end(dcbnl_skb, nest);
41933dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck
42033dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	nlmsg_end(dcbnl_skb, nlh);
42133dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck
42233dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
42333dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	if (ret) {
42433dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck		ret = -EINVAL;
42533dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck		goto err;
42633dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	}
42733dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck
42833dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	return 0;
42933dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duycknlmsg_failure:
43033dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyckerr:
43133dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	kfree(dcbnl_skb);
43233dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyckerr_out:
43333dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	return ret;
43433dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck}
43533dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck
43633dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyckstatic int dcbnl_setnumtcs(struct net_device *netdev, struct nlattr **tb,
43733dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck                           u32 pid, u32 seq, u16 flags)
43833dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck{
43933dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1];
44033dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	int ret = -EINVAL;
44133dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	u8 value;
44233dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	int i;
44333dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck
44433dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	if (!tb[DCB_ATTR_NUMTCS] || !netdev->dcbnl_ops->setstate)
44533dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck		return ret;
44633dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck
44733dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	ret = nla_parse_nested(data, DCB_NUMTCS_ATTR_MAX, tb[DCB_ATTR_NUMTCS],
44833dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	                       dcbnl_numtcs_nest);
44933dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck
45033dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	if (ret) {
45133dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck		ret = -EINVAL;
45233dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck		goto err;
45333dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	}
45433dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck
45533dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	for (i = DCB_NUMTCS_ATTR_ALL+1; i <= DCB_NUMTCS_ATTR_MAX; i++) {
45633dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck		if (data[i] == NULL)
45733dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck			continue;
45833dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck
45933dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck		value = nla_get_u8(data[i]);
46033dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck
46133dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck		ret = netdev->dcbnl_ops->setnumtcs(netdev, i, value);
46233dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck
46333dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck		if (ret)
46433dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck			goto operr;
46533dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	}
46633dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck
46733dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyckoperr:
46833dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	ret = dcbnl_reply(!!ret, RTM_SETDCB, DCB_CMD_SNUMTCS,
46933dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	                  DCB_ATTR_NUMTCS, pid, seq, flags);
47033dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck
47133dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyckerr:
47233dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	return ret;
47333dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck}
47433dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck
4750eb3aa9bab20217fb42244ccdcb5bf8a002f504cAlexander Duyckstatic int dcbnl_getpfcstate(struct net_device *netdev, struct nlattr **tb,
4760eb3aa9bab20217fb42244ccdcb5bf8a002f504cAlexander Duyck                             u32 pid, u32 seq, u16 flags)
4770eb3aa9bab20217fb42244ccdcb5bf8a002f504cAlexander Duyck{
4780eb3aa9bab20217fb42244ccdcb5bf8a002f504cAlexander Duyck	int ret = -EINVAL;
4790eb3aa9bab20217fb42244ccdcb5bf8a002f504cAlexander Duyck
4800eb3aa9bab20217fb42244ccdcb5bf8a002f504cAlexander Duyck	if (!netdev->dcbnl_ops->getpfcstate)
4810eb3aa9bab20217fb42244ccdcb5bf8a002f504cAlexander Duyck		return ret;
4820eb3aa9bab20217fb42244ccdcb5bf8a002f504cAlexander Duyck
4830eb3aa9bab20217fb42244ccdcb5bf8a002f504cAlexander Duyck	ret = dcbnl_reply(netdev->dcbnl_ops->getpfcstate(netdev), RTM_GETDCB,
4840eb3aa9bab20217fb42244ccdcb5bf8a002f504cAlexander Duyck	                  DCB_CMD_PFC_GSTATE, DCB_ATTR_PFC_STATE,
4850eb3aa9bab20217fb42244ccdcb5bf8a002f504cAlexander Duyck	                  pid, seq, flags);
4860eb3aa9bab20217fb42244ccdcb5bf8a002f504cAlexander Duyck
4870eb3aa9bab20217fb42244ccdcb5bf8a002f504cAlexander Duyck	return ret;
4880eb3aa9bab20217fb42244ccdcb5bf8a002f504cAlexander Duyck}
4890eb3aa9bab20217fb42244ccdcb5bf8a002f504cAlexander Duyck
4900eb3aa9bab20217fb42244ccdcb5bf8a002f504cAlexander Duyckstatic int dcbnl_setpfcstate(struct net_device *netdev, struct nlattr **tb,
4910eb3aa9bab20217fb42244ccdcb5bf8a002f504cAlexander Duyck                             u32 pid, u32 seq, u16 flags)
4920eb3aa9bab20217fb42244ccdcb5bf8a002f504cAlexander Duyck{
4930eb3aa9bab20217fb42244ccdcb5bf8a002f504cAlexander Duyck	int ret = -EINVAL;
4940eb3aa9bab20217fb42244ccdcb5bf8a002f504cAlexander Duyck	u8 value;
4950eb3aa9bab20217fb42244ccdcb5bf8a002f504cAlexander Duyck
4960eb3aa9bab20217fb42244ccdcb5bf8a002f504cAlexander Duyck	if (!tb[DCB_ATTR_PFC_STATE] || !netdev->dcbnl_ops->setpfcstate)
4970eb3aa9bab20217fb42244ccdcb5bf8a002f504cAlexander Duyck		return ret;
4980eb3aa9bab20217fb42244ccdcb5bf8a002f504cAlexander Duyck
4990eb3aa9bab20217fb42244ccdcb5bf8a002f504cAlexander Duyck	value = nla_get_u8(tb[DCB_ATTR_PFC_STATE]);
5000eb3aa9bab20217fb42244ccdcb5bf8a002f504cAlexander Duyck
5010eb3aa9bab20217fb42244ccdcb5bf8a002f504cAlexander Duyck	netdev->dcbnl_ops->setpfcstate(netdev, value);
5020eb3aa9bab20217fb42244ccdcb5bf8a002f504cAlexander Duyck
5030eb3aa9bab20217fb42244ccdcb5bf8a002f504cAlexander Duyck	ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_PFC_SSTATE, DCB_ATTR_PFC_STATE,
5040eb3aa9bab20217fb42244ccdcb5bf8a002f504cAlexander Duyck	                  pid, seq, flags);
5050eb3aa9bab20217fb42244ccdcb5bf8a002f504cAlexander Duyck
5060eb3aa9bab20217fb42244ccdcb5bf8a002f504cAlexander Duyck	return ret;
5070eb3aa9bab20217fb42244ccdcb5bf8a002f504cAlexander Duyck}
5080eb3aa9bab20217fb42244ccdcb5bf8a002f504cAlexander Duyck
5092f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyckstatic int __dcbnl_pg_getcfg(struct net_device *netdev, struct nlattr **tb,
5102f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck                             u32 pid, u32 seq, u16 flags, int dir)
5112f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck{
5122f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	struct sk_buff *dcbnl_skb;
5132f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	struct nlmsghdr *nlh;
5142f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	struct dcbmsg *dcb;
5152f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	struct nlattr *pg_nest, *param_nest, *data;
5162f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1];
5172f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1];
5182f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	u8 prio, pgid, tc_pct, up_map;
5192f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	int ret  = -EINVAL;
5202f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	int getall = 0;
5212f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	int i;
5222f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
5232f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	if (!tb[DCB_ATTR_PG_CFG] ||
5242f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	    !netdev->dcbnl_ops->getpgtccfgtx ||
5252f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	    !netdev->dcbnl_ops->getpgtccfgrx ||
5262f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	    !netdev->dcbnl_ops->getpgbwgcfgtx ||
5272f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	    !netdev->dcbnl_ops->getpgbwgcfgrx)
5282f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		return ret;
5292f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
5302f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX,
5312f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	                       tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest);
5322f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
5332f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	if (ret)
5342f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		goto err_out;
5352f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
5362f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
5372f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	if (!dcbnl_skb)
5382f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		goto err_out;
5392f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
5402f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
5412f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
5422f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	dcb = NLMSG_DATA(nlh);
5432f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	dcb->dcb_family = AF_UNSPEC;
5442f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	dcb->cmd = (dir) ? DCB_CMD_PGRX_GCFG : DCB_CMD_PGTX_GCFG;
5452f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
5462f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	pg_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_PG_CFG);
5472f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	if (!pg_nest)
5482f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		goto err;
5492f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
5502f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	if (pg_tb[DCB_PG_ATTR_TC_ALL])
5512f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		getall = 1;
5522f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
5532f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) {
5542f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		if (!getall && !pg_tb[i])
5552f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			continue;
5562f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
5572f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		if (pg_tb[DCB_PG_ATTR_TC_ALL])
5582f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			data = pg_tb[DCB_PG_ATTR_TC_ALL];
5592f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		else
5602f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			data = pg_tb[i];
5612f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		ret = nla_parse_nested(param_tb, DCB_TC_ATTR_PARAM_MAX,
5622f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck				       data, dcbnl_tc_param_nest);
5632f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		if (ret)
5642f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			goto err_pg;
5652f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
5662f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		param_nest = nla_nest_start(dcbnl_skb, i);
5672f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		if (!param_nest)
5682f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			goto err_pg;
5692f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
5702f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		pgid = DCB_ATTR_VALUE_UNDEFINED;
5712f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		prio = DCB_ATTR_VALUE_UNDEFINED;
5722f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		tc_pct = DCB_ATTR_VALUE_UNDEFINED;
5732f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		up_map = DCB_ATTR_VALUE_UNDEFINED;
5742f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
5752f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		if (dir) {
5762f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			/* Rx */
5772f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			netdev->dcbnl_ops->getpgtccfgrx(netdev,
5782f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck						i - DCB_PG_ATTR_TC_0, &prio,
5792f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck						&pgid, &tc_pct, &up_map);
5802f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		} else {
5812f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			/* Tx */
5822f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			netdev->dcbnl_ops->getpgtccfgtx(netdev,
5832f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck						i - DCB_PG_ATTR_TC_0, &prio,
5842f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck						&pgid, &tc_pct, &up_map);
5852f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		}
5862f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
5872f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		if (param_tb[DCB_TC_ATTR_PARAM_PGID] ||
5882f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		    param_tb[DCB_TC_ATTR_PARAM_ALL]) {
5892f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			ret = nla_put_u8(dcbnl_skb,
5902f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			                 DCB_TC_ATTR_PARAM_PGID, pgid);
5912f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			if (ret)
5922f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck				goto err_param;
5932f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		}
5942f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING] ||
5952f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		    param_tb[DCB_TC_ATTR_PARAM_ALL]) {
5962f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			ret = nla_put_u8(dcbnl_skb,
5972f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			                 DCB_TC_ATTR_PARAM_UP_MAPPING, up_map);
5982f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			if (ret)
5992f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck				goto err_param;
6002f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		}
6012f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO] ||
6022f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		    param_tb[DCB_TC_ATTR_PARAM_ALL]) {
6032f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			ret = nla_put_u8(dcbnl_skb,
6042f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			                 DCB_TC_ATTR_PARAM_STRICT_PRIO, prio);
6052f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			if (ret)
6062f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck				goto err_param;
6072f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		}
6082f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT] ||
6092f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		    param_tb[DCB_TC_ATTR_PARAM_ALL]) {
6102f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			ret = nla_put_u8(dcbnl_skb, DCB_TC_ATTR_PARAM_BW_PCT,
6112f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			                 tc_pct);
6122f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			if (ret)
6132f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck				goto err_param;
6142f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		}
6152f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		nla_nest_end(dcbnl_skb, param_nest);
6162f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	}
6172f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
6182f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	if (pg_tb[DCB_PG_ATTR_BW_ID_ALL])
6192f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		getall = 1;
6202f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	else
6212f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		getall = 0;
6222f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
6232f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) {
6242f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		if (!getall && !pg_tb[i])
6252f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			continue;
6262f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
6272f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		tc_pct = DCB_ATTR_VALUE_UNDEFINED;
6282f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
6292f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		if (dir) {
6302f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			/* Rx */
6312f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			netdev->dcbnl_ops->getpgbwgcfgrx(netdev,
6322f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck					i - DCB_PG_ATTR_BW_ID_0, &tc_pct);
6332f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		} else {
6342f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			/* Tx */
6352f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			netdev->dcbnl_ops->getpgbwgcfgtx(netdev,
6362f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck					i - DCB_PG_ATTR_BW_ID_0, &tc_pct);
6372f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		}
6382f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		ret = nla_put_u8(dcbnl_skb, i, tc_pct);
6392f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
6402f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		if (ret)
6412f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			goto err_pg;
6422f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	}
6432f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
6442f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	nla_nest_end(dcbnl_skb, pg_nest);
6452f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
6462f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	nlmsg_end(dcbnl_skb, nlh);
6472f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
6482f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
6492f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	if (ret)
6502f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		goto err;
6512f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
6522f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	return 0;
6532f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
6542f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyckerr_param:
6552f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	nla_nest_cancel(dcbnl_skb, param_nest);
6562f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyckerr_pg:
6572f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	nla_nest_cancel(dcbnl_skb, pg_nest);
6582f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duycknlmsg_failure:
6592f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyckerr:
6602f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	kfree(dcbnl_skb);
6612f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyckerr_out:
6622f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	ret  = -EINVAL;
6632f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	return ret;
6642f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck}
6652f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
6662f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyckstatic int dcbnl_pgtx_getcfg(struct net_device *netdev, struct nlattr **tb,
6672f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck                             u32 pid, u32 seq, u16 flags)
6682f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck{
6692f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	return __dcbnl_pg_getcfg(netdev, tb, pid, seq, flags, 0);
6702f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck}
6712f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
6722f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyckstatic int dcbnl_pgrx_getcfg(struct net_device *netdev, struct nlattr **tb,
6732f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck                             u32 pid, u32 seq, u16 flags)
6742f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck{
6752f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	return __dcbnl_pg_getcfg(netdev, tb, pid, seq, flags, 1);
6762f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck}
6772f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
6782f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyckstatic int dcbnl_setstate(struct net_device *netdev, struct nlattr **tb,
6792f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck                          u32 pid, u32 seq, u16 flags)
6802f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck{
6812f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	int ret = -EINVAL;
6822f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	u8 value;
6832f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
6842f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->setstate)
6852f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		return ret;
6862f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
6872f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	value = nla_get_u8(tb[DCB_ATTR_STATE]);
6882f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
6892f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	netdev->dcbnl_ops->setstate(netdev, value);
6902f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
6912f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_SSTATE, DCB_ATTR_STATE,
6922f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	                  pid, seq, flags);
6932f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
6942f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	return ret;
6952f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck}
6962f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
6972f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyckstatic int dcbnl_setpfccfg(struct net_device *netdev, struct nlattr **tb,
6982f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck                           u32 pid, u32 seq, u16 flags)
6992f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck{
7002f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1];
7012f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	int i;
7022f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	int ret = -EINVAL;
7032f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	u8 value;
7042f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
7052f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	if (!tb[DCB_ATTR_PFC_CFG] || !netdev->dcbnl_ops->setpfccfg)
7062f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		return ret;
7072f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
7082f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	ret = nla_parse_nested(data, DCB_PFC_UP_ATTR_MAX,
7092f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	                       tb[DCB_ATTR_PFC_CFG],
7102f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	                       dcbnl_pfc_up_nest);
7112f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	if (ret)
7122f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		goto err;
7132f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
7142f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) {
7152f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		if (data[i] == NULL)
7162f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			continue;
7172f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		value = nla_get_u8(data[i]);
7182f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		netdev->dcbnl_ops->setpfccfg(netdev,
7192f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			data[i]->nla_type - DCB_PFC_UP_ATTR_0, value);
7202f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	}
7212f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
7222f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_PFC_SCFG, DCB_ATTR_PFC_CFG,
7232f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	                  pid, seq, flags);
7242f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyckerr:
7252f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	return ret;
7262f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck}
7272f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
7282f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyckstatic int dcbnl_setall(struct net_device *netdev, struct nlattr **tb,
7292f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck                        u32 pid, u32 seq, u16 flags)
7302f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck{
7312f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	int ret = -EINVAL;
7322f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
7332f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	if (!tb[DCB_ATTR_SET_ALL] || !netdev->dcbnl_ops->setall)
7342f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		return ret;
7352f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
7362f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	ret = dcbnl_reply(netdev->dcbnl_ops->setall(netdev), RTM_SETDCB,
7372f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	                  DCB_CMD_SET_ALL, DCB_ATTR_SET_ALL, pid, seq, flags);
7382f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
7392f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	return ret;
7402f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck}
7412f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
7422f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyckstatic int __dcbnl_pg_setcfg(struct net_device *netdev, struct nlattr **tb,
7432f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck                             u32 pid, u32 seq, u16 flags, int dir)
7442f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck{
7452f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1];
7462f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1];
7472f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	int ret = -EINVAL;
7482f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	int i;
7492f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	u8 pgid;
7502f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	u8 up_map;
7512f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	u8 prio;
7522f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	u8 tc_pct;
7532f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
7542f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	if (!tb[DCB_ATTR_PG_CFG] ||
7552f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	    !netdev->dcbnl_ops->setpgtccfgtx ||
7562f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	    !netdev->dcbnl_ops->setpgtccfgrx ||
7572f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	    !netdev->dcbnl_ops->setpgbwgcfgtx ||
7582f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	    !netdev->dcbnl_ops->setpgbwgcfgrx)
7592f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		return ret;
7602f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
7612f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX,
7622f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	                       tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest);
7632f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	if (ret)
7642f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		goto err;
7652f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
7662f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) {
7672f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		if (!pg_tb[i])
7682f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			continue;
7692f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
7702f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		ret = nla_parse_nested(param_tb, DCB_TC_ATTR_PARAM_MAX,
7712f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		                       pg_tb[i], dcbnl_tc_param_nest);
7722f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		if (ret)
7732f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			goto err;
7742f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
7752f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		pgid = DCB_ATTR_VALUE_UNDEFINED;
7762f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		prio = DCB_ATTR_VALUE_UNDEFINED;
7772f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		tc_pct = DCB_ATTR_VALUE_UNDEFINED;
7782f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		up_map = DCB_ATTR_VALUE_UNDEFINED;
7792f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
7802f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO])
7812f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			prio =
7822f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			    nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO]);
7832f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
7842f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		if (param_tb[DCB_TC_ATTR_PARAM_PGID])
7852f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			pgid = nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_PGID]);
7862f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
7872f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT])
7882f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			tc_pct = nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_BW_PCT]);
7892f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
7902f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING])
7912f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			up_map =
7922f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			     nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING]);
7932f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
7942f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		/* dir: Tx = 0, Rx = 1 */
7952f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		if (dir) {
7962f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			/* Rx */
7972f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			netdev->dcbnl_ops->setpgtccfgrx(netdev,
7982f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck				i - DCB_PG_ATTR_TC_0,
7992f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck				prio, pgid, tc_pct, up_map);
8002f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		} else {
8012f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			/* Tx */
8022f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			netdev->dcbnl_ops->setpgtccfgtx(netdev,
8032f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck				i - DCB_PG_ATTR_TC_0,
8042f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck				prio, pgid, tc_pct, up_map);
8052f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		}
8062f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	}
8072f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
8082f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) {
8092f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		if (!pg_tb[i])
8102f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			continue;
8112f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
8122f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		tc_pct = nla_get_u8(pg_tb[i]);
8132f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
8142f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		/* dir: Tx = 0, Rx = 1 */
8152f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		if (dir) {
8162f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			/* Rx */
8172f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			netdev->dcbnl_ops->setpgbwgcfgrx(netdev,
8182f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck					 i - DCB_PG_ATTR_BW_ID_0, tc_pct);
8192f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		} else {
8202f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			/* Tx */
8212f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			netdev->dcbnl_ops->setpgbwgcfgtx(netdev,
8222f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck					 i - DCB_PG_ATTR_BW_ID_0, tc_pct);
8232f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		}
8242f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	}
8252f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
8262f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	ret = dcbnl_reply(0, RTM_SETDCB,
8272f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			  (dir ? DCB_CMD_PGRX_SCFG : DCB_CMD_PGTX_SCFG),
8282f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			  DCB_ATTR_PG_CFG, pid, seq, flags);
8292f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
8302f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyckerr:
8312f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	return ret;
8322f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck}
8332f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
8342f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyckstatic int dcbnl_pgtx_setcfg(struct net_device *netdev, struct nlattr **tb,
8352f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck                             u32 pid, u32 seq, u16 flags)
8362f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck{
8372f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	return __dcbnl_pg_setcfg(netdev, tb, pid, seq, flags, 0);
8382f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck}
8392f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
8402f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyckstatic int dcbnl_pgrx_setcfg(struct net_device *netdev, struct nlattr **tb,
8412f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck                             u32 pid, u32 seq, u16 flags)
8422f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck{
8432f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	return __dcbnl_pg_setcfg(netdev, tb, pid, seq, flags, 1);
8442f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck}
8452f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
8462f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyckstatic int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
8472f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck{
8482f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	struct net *net = sock_net(skb->sk);
8492f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	struct net_device *netdev;
8502f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	struct dcbmsg  *dcb = (struct dcbmsg *)NLMSG_DATA(nlh);
8512f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	struct nlattr *tb[DCB_ATTR_MAX + 1];
8522f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	u32 pid = skb ? NETLINK_CB(skb).pid : 0;
8532f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	int ret = -EINVAL;
8542f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
8552f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	if (net != &init_net)
8562f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		return -EINVAL;
8572f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
8582f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	ret = nlmsg_parse(nlh, sizeof(*dcb), tb, DCB_ATTR_MAX,
8592f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck			  dcbnl_rtnl_policy);
8602f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	if (ret < 0)
8612f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		return ret;
8622f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
8632f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	if (!tb[DCB_ATTR_IFNAME])
8642f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		return -EINVAL;
8652f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
8662f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	netdev = dev_get_by_name(&init_net, nla_data(tb[DCB_ATTR_IFNAME]));
8672f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	if (!netdev)
8682f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		return -EINVAL;
8692f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
8702f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	if (!netdev->dcbnl_ops)
8712f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		goto errout;
8722f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
8732f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	switch (dcb->cmd) {
8742f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	case DCB_CMD_GSTATE:
8752f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		ret = dcbnl_getstate(netdev, tb, pid, nlh->nlmsg_seq,
8762f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		                     nlh->nlmsg_flags);
8772f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		goto out;
8782f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	case DCB_CMD_PFC_GCFG:
8792f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		ret = dcbnl_getpfccfg(netdev, tb, pid, nlh->nlmsg_seq,
8802f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		                      nlh->nlmsg_flags);
8812f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		goto out;
8822f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	case DCB_CMD_GPERM_HWADDR:
8832f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		ret = dcbnl_getperm_hwaddr(netdev, tb, pid, nlh->nlmsg_seq,
8842f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		                           nlh->nlmsg_flags);
8852f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		goto out;
8862f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	case DCB_CMD_PGTX_GCFG:
8872f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		ret = dcbnl_pgtx_getcfg(netdev, tb, pid, nlh->nlmsg_seq,
8882f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		                        nlh->nlmsg_flags);
8892f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		goto out;
8902f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	case DCB_CMD_PGRX_GCFG:
8912f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		ret = dcbnl_pgrx_getcfg(netdev, tb, pid, nlh->nlmsg_seq,
8922f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		                        nlh->nlmsg_flags);
8932f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		goto out;
8942f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	case DCB_CMD_SSTATE:
8952f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		ret = dcbnl_setstate(netdev, tb, pid, nlh->nlmsg_seq,
8962f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		                     nlh->nlmsg_flags);
8972f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		goto out;
8982f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	case DCB_CMD_PFC_SCFG:
8992f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		ret = dcbnl_setpfccfg(netdev, tb, pid, nlh->nlmsg_seq,
9002f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		                      nlh->nlmsg_flags);
9012f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		goto out;
9022f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
9032f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	case DCB_CMD_SET_ALL:
9042f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		ret = dcbnl_setall(netdev, tb, pid, nlh->nlmsg_seq,
9052f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		                   nlh->nlmsg_flags);
9062f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		goto out;
9072f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	case DCB_CMD_PGTX_SCFG:
9082f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		ret = dcbnl_pgtx_setcfg(netdev, tb, pid, nlh->nlmsg_seq,
9092f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		                        nlh->nlmsg_flags);
9102f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		goto out;
9112f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	case DCB_CMD_PGRX_SCFG:
9122f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		ret = dcbnl_pgrx_setcfg(netdev, tb, pid, nlh->nlmsg_seq,
9132f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		                        nlh->nlmsg_flags);
9142f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		goto out;
91546132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck	case DCB_CMD_GCAP:
91646132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck		ret = dcbnl_getcap(netdev, tb, pid, nlh->nlmsg_seq,
91746132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck		                   nlh->nlmsg_flags);
91846132188bf72e22ef097f16ed5c969ee8cea1e8bAlexander Duyck		goto out;
91933dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	case DCB_CMD_GNUMTCS:
92033dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck		ret = dcbnl_getnumtcs(netdev, tb, pid, nlh->nlmsg_seq,
92133dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck		                      nlh->nlmsg_flags);
92233dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck		goto out;
92333dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck	case DCB_CMD_SNUMTCS:
92433dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck		ret = dcbnl_setnumtcs(netdev, tb, pid, nlh->nlmsg_seq,
92533dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck		                      nlh->nlmsg_flags);
92633dbabc4a7f7bd72313c73a3c199f31f3900336fAlexander Duyck		goto out;
9270eb3aa9bab20217fb42244ccdcb5bf8a002f504cAlexander Duyck	case DCB_CMD_PFC_GSTATE:
9280eb3aa9bab20217fb42244ccdcb5bf8a002f504cAlexander Duyck		ret = dcbnl_getpfcstate(netdev, tb, pid, nlh->nlmsg_seq,
9290eb3aa9bab20217fb42244ccdcb5bf8a002f504cAlexander Duyck		                        nlh->nlmsg_flags);
9300eb3aa9bab20217fb42244ccdcb5bf8a002f504cAlexander Duyck		goto out;
9310eb3aa9bab20217fb42244ccdcb5bf8a002f504cAlexander Duyck	case DCB_CMD_PFC_SSTATE:
9320eb3aa9bab20217fb42244ccdcb5bf8a002f504cAlexander Duyck		ret = dcbnl_setpfcstate(netdev, tb, pid, nlh->nlmsg_seq,
9330eb3aa9bab20217fb42244ccdcb5bf8a002f504cAlexander Duyck		                        nlh->nlmsg_flags);
9340eb3aa9bab20217fb42244ccdcb5bf8a002f504cAlexander Duyck		goto out;
9352f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	default:
9362f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck		goto errout;
9372f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	}
9382f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyckerrout:
9392f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	ret = -EINVAL;
9402f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyckout:
9412f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	dev_put(netdev);
9422f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	return ret;
9432f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck}
9442f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
9452f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyckstatic int __init dcbnl_init(void)
9462f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck{
9472f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	rtnl_register(PF_UNSPEC, RTM_GETDCB, dcb_doit, NULL);
9482f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	rtnl_register(PF_UNSPEC, RTM_SETDCB, dcb_doit, NULL);
9492f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
9502f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	return 0;
9512f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck}
9522f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyckmodule_init(dcbnl_init);
9532f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
9542f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyckstatic void __exit dcbnl_exit(void)
9552f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck{
9562f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	rtnl_unregister(PF_UNSPEC, RTM_GETDCB);
9572f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck	rtnl_unregister(PF_UNSPEC, RTM_SETDCB);
9582f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck}
9592f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyckmodule_exit(dcbnl_exit);
9602f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
9612f90b8657ec942d1880f720e0177ee71df7c8e3cAlexander Duyck
962