12f90b865SAlexander Duyck /* 2698e1d23SMark Rustad * Copyright (c) 2008-2011, 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> 2696b99684SJohn Fastabend #include <net/dcbevent.h> 272f90b865SAlexander Duyck #include <linux/rtnetlink.h> 282f90b865SAlexander Duyck #include <net/sock.h> 292f90b865SAlexander Duyck 302f90b865SAlexander Duyck /** 312f90b865SAlexander Duyck * Data Center Bridging (DCB) is a collection of Ethernet enhancements 322f90b865SAlexander Duyck * intended to allow network traffic with differing requirements 332f90b865SAlexander Duyck * (highly reliable, no drops vs. best effort vs. low latency) to operate 342f90b865SAlexander Duyck * and co-exist on Ethernet. Current DCB features are: 352f90b865SAlexander Duyck * 362f90b865SAlexander Duyck * Enhanced Transmission Selection (aka Priority Grouping [PG]) - provides a 372f90b865SAlexander Duyck * framework for assigning bandwidth guarantees to traffic classes. 382f90b865SAlexander Duyck * 392f90b865SAlexander Duyck * Priority-based Flow Control (PFC) - provides a flow control mechanism which 402f90b865SAlexander Duyck * can work independently for each 802.1p priority. 412f90b865SAlexander Duyck * 422f90b865SAlexander Duyck * Congestion Notification - provides a mechanism for end-to-end congestion 432f90b865SAlexander Duyck * control for protocols which do not have built-in congestion management. 442f90b865SAlexander Duyck * 452f90b865SAlexander Duyck * More information about the emerging standards for these Ethernet features 462f90b865SAlexander Duyck * can be found at: http://www.ieee802.org/1/pages/dcbridges.html 472f90b865SAlexander Duyck * 482f90b865SAlexander Duyck * This file implements an rtnetlink interface to allow configuration of DCB 492f90b865SAlexander Duyck * features for capable devices. 502f90b865SAlexander Duyck */ 512f90b865SAlexander Duyck 522f90b865SAlexander Duyck MODULE_AUTHOR("Lucy Liu, <lucy.liu@intel.com>"); 537a6b6f51SJeff Kirsher MODULE_DESCRIPTION("Data Center Bridging netlink interface"); 542f90b865SAlexander Duyck MODULE_LICENSE("GPL"); 552f90b865SAlexander Duyck 562f90b865SAlexander Duyck /**************** DCB attribute policies *************************************/ 572f90b865SAlexander Duyck 582f90b865SAlexander Duyck /* DCB netlink attributes policy */ 59b54452b0SAlexey Dobriyan static const struct nla_policy dcbnl_rtnl_policy[DCB_ATTR_MAX + 1] = { 60859ee3c4SAlexander Duyck [DCB_ATTR_IFNAME] = {.type = NLA_NUL_STRING, .len = IFNAMSIZ - 1}, 612f90b865SAlexander Duyck [DCB_ATTR_STATE] = {.type = NLA_U8}, 622f90b865SAlexander Duyck [DCB_ATTR_PFC_CFG] = {.type = NLA_NESTED}, 632f90b865SAlexander Duyck [DCB_ATTR_PG_CFG] = {.type = NLA_NESTED}, 642f90b865SAlexander Duyck [DCB_ATTR_SET_ALL] = {.type = NLA_U8}, 652f90b865SAlexander Duyck [DCB_ATTR_PERM_HWADDR] = {.type = NLA_FLAG}, 6646132188SAlexander Duyck [DCB_ATTR_CAP] = {.type = NLA_NESTED}, 670eb3aa9bSAlexander Duyck [DCB_ATTR_PFC_STATE] = {.type = NLA_U8}, 68859ee3c4SAlexander Duyck [DCB_ATTR_BCN] = {.type = NLA_NESTED}, 696fa382afSYi Zou [DCB_ATTR_APP] = {.type = NLA_NESTED}, 703e29027aSJohn Fastabend [DCB_ATTR_IEEE] = {.type = NLA_NESTED}, 716241b625SShmulik Ravid [DCB_ATTR_DCBX] = {.type = NLA_U8}, 72ea45fe4eSShmulik Ravid [DCB_ATTR_FEATCFG] = {.type = NLA_NESTED}, 732f90b865SAlexander Duyck }; 742f90b865SAlexander Duyck 752f90b865SAlexander Duyck /* DCB priority flow control to User Priority nested attributes */ 76b54452b0SAlexey Dobriyan static const struct nla_policy dcbnl_pfc_up_nest[DCB_PFC_UP_ATTR_MAX + 1] = { 772f90b865SAlexander Duyck [DCB_PFC_UP_ATTR_0] = {.type = NLA_U8}, 782f90b865SAlexander Duyck [DCB_PFC_UP_ATTR_1] = {.type = NLA_U8}, 792f90b865SAlexander Duyck [DCB_PFC_UP_ATTR_2] = {.type = NLA_U8}, 802f90b865SAlexander Duyck [DCB_PFC_UP_ATTR_3] = {.type = NLA_U8}, 812f90b865SAlexander Duyck [DCB_PFC_UP_ATTR_4] = {.type = NLA_U8}, 822f90b865SAlexander Duyck [DCB_PFC_UP_ATTR_5] = {.type = NLA_U8}, 832f90b865SAlexander Duyck [DCB_PFC_UP_ATTR_6] = {.type = NLA_U8}, 842f90b865SAlexander Duyck [DCB_PFC_UP_ATTR_7] = {.type = NLA_U8}, 852f90b865SAlexander Duyck [DCB_PFC_UP_ATTR_ALL] = {.type = NLA_FLAG}, 862f90b865SAlexander Duyck }; 872f90b865SAlexander Duyck 882f90b865SAlexander Duyck /* DCB priority grouping nested attributes */ 89b54452b0SAlexey Dobriyan static const struct nla_policy dcbnl_pg_nest[DCB_PG_ATTR_MAX + 1] = { 902f90b865SAlexander Duyck [DCB_PG_ATTR_TC_0] = {.type = NLA_NESTED}, 912f90b865SAlexander Duyck [DCB_PG_ATTR_TC_1] = {.type = NLA_NESTED}, 922f90b865SAlexander Duyck [DCB_PG_ATTR_TC_2] = {.type = NLA_NESTED}, 932f90b865SAlexander Duyck [DCB_PG_ATTR_TC_3] = {.type = NLA_NESTED}, 942f90b865SAlexander Duyck [DCB_PG_ATTR_TC_4] = {.type = NLA_NESTED}, 952f90b865SAlexander Duyck [DCB_PG_ATTR_TC_5] = {.type = NLA_NESTED}, 962f90b865SAlexander Duyck [DCB_PG_ATTR_TC_6] = {.type = NLA_NESTED}, 972f90b865SAlexander Duyck [DCB_PG_ATTR_TC_7] = {.type = NLA_NESTED}, 982f90b865SAlexander Duyck [DCB_PG_ATTR_TC_ALL] = {.type = NLA_NESTED}, 992f90b865SAlexander Duyck [DCB_PG_ATTR_BW_ID_0] = {.type = NLA_U8}, 1002f90b865SAlexander Duyck [DCB_PG_ATTR_BW_ID_1] = {.type = NLA_U8}, 1012f90b865SAlexander Duyck [DCB_PG_ATTR_BW_ID_2] = {.type = NLA_U8}, 1022f90b865SAlexander Duyck [DCB_PG_ATTR_BW_ID_3] = {.type = NLA_U8}, 1032f90b865SAlexander Duyck [DCB_PG_ATTR_BW_ID_4] = {.type = NLA_U8}, 1042f90b865SAlexander Duyck [DCB_PG_ATTR_BW_ID_5] = {.type = NLA_U8}, 1052f90b865SAlexander Duyck [DCB_PG_ATTR_BW_ID_6] = {.type = NLA_U8}, 1062f90b865SAlexander Duyck [DCB_PG_ATTR_BW_ID_7] = {.type = NLA_U8}, 1072f90b865SAlexander Duyck [DCB_PG_ATTR_BW_ID_ALL] = {.type = NLA_FLAG}, 1082f90b865SAlexander Duyck }; 1092f90b865SAlexander Duyck 1102f90b865SAlexander Duyck /* DCB traffic class nested attributes. */ 111b54452b0SAlexey Dobriyan static const struct nla_policy dcbnl_tc_param_nest[DCB_TC_ATTR_PARAM_MAX + 1] = { 1122f90b865SAlexander Duyck [DCB_TC_ATTR_PARAM_PGID] = {.type = NLA_U8}, 1132f90b865SAlexander Duyck [DCB_TC_ATTR_PARAM_UP_MAPPING] = {.type = NLA_U8}, 1142f90b865SAlexander Duyck [DCB_TC_ATTR_PARAM_STRICT_PRIO] = {.type = NLA_U8}, 1152f90b865SAlexander Duyck [DCB_TC_ATTR_PARAM_BW_PCT] = {.type = NLA_U8}, 1162f90b865SAlexander Duyck [DCB_TC_ATTR_PARAM_ALL] = {.type = NLA_FLAG}, 1172f90b865SAlexander Duyck }; 1182f90b865SAlexander Duyck 11946132188SAlexander Duyck /* DCB capabilities nested attributes. */ 120b54452b0SAlexey Dobriyan static const struct nla_policy dcbnl_cap_nest[DCB_CAP_ATTR_MAX + 1] = { 12146132188SAlexander Duyck [DCB_CAP_ATTR_ALL] = {.type = NLA_FLAG}, 12246132188SAlexander Duyck [DCB_CAP_ATTR_PG] = {.type = NLA_U8}, 12346132188SAlexander Duyck [DCB_CAP_ATTR_PFC] = {.type = NLA_U8}, 12446132188SAlexander Duyck [DCB_CAP_ATTR_UP2TC] = {.type = NLA_U8}, 12546132188SAlexander Duyck [DCB_CAP_ATTR_PG_TCS] = {.type = NLA_U8}, 12646132188SAlexander Duyck [DCB_CAP_ATTR_PFC_TCS] = {.type = NLA_U8}, 12746132188SAlexander Duyck [DCB_CAP_ATTR_GSP] = {.type = NLA_U8}, 12846132188SAlexander Duyck [DCB_CAP_ATTR_BCN] = {.type = NLA_U8}, 1296241b625SShmulik Ravid [DCB_CAP_ATTR_DCBX] = {.type = NLA_U8}, 13046132188SAlexander Duyck }; 1312f90b865SAlexander Duyck 13233dbabc4SAlexander Duyck /* DCB capabilities nested attributes. */ 133b54452b0SAlexey Dobriyan static const struct nla_policy dcbnl_numtcs_nest[DCB_NUMTCS_ATTR_MAX + 1] = { 13433dbabc4SAlexander Duyck [DCB_NUMTCS_ATTR_ALL] = {.type = NLA_FLAG}, 13533dbabc4SAlexander Duyck [DCB_NUMTCS_ATTR_PG] = {.type = NLA_U8}, 13633dbabc4SAlexander Duyck [DCB_NUMTCS_ATTR_PFC] = {.type = NLA_U8}, 13733dbabc4SAlexander Duyck }; 13833dbabc4SAlexander Duyck 139859ee3c4SAlexander Duyck /* DCB BCN nested attributes. */ 140b54452b0SAlexey Dobriyan static const struct nla_policy dcbnl_bcn_nest[DCB_BCN_ATTR_MAX + 1] = { 141859ee3c4SAlexander Duyck [DCB_BCN_ATTR_RP_0] = {.type = NLA_U8}, 142859ee3c4SAlexander Duyck [DCB_BCN_ATTR_RP_1] = {.type = NLA_U8}, 143859ee3c4SAlexander Duyck [DCB_BCN_ATTR_RP_2] = {.type = NLA_U8}, 144859ee3c4SAlexander Duyck [DCB_BCN_ATTR_RP_3] = {.type = NLA_U8}, 145859ee3c4SAlexander Duyck [DCB_BCN_ATTR_RP_4] = {.type = NLA_U8}, 146859ee3c4SAlexander Duyck [DCB_BCN_ATTR_RP_5] = {.type = NLA_U8}, 147859ee3c4SAlexander Duyck [DCB_BCN_ATTR_RP_6] = {.type = NLA_U8}, 148859ee3c4SAlexander Duyck [DCB_BCN_ATTR_RP_7] = {.type = NLA_U8}, 149859ee3c4SAlexander Duyck [DCB_BCN_ATTR_RP_ALL] = {.type = NLA_FLAG}, 150f4314e81SDon Skidmore [DCB_BCN_ATTR_BCNA_0] = {.type = NLA_U32}, 151f4314e81SDon Skidmore [DCB_BCN_ATTR_BCNA_1] = {.type = NLA_U32}, 152859ee3c4SAlexander Duyck [DCB_BCN_ATTR_ALPHA] = {.type = NLA_U32}, 153859ee3c4SAlexander Duyck [DCB_BCN_ATTR_BETA] = {.type = NLA_U32}, 154859ee3c4SAlexander Duyck [DCB_BCN_ATTR_GD] = {.type = NLA_U32}, 155859ee3c4SAlexander Duyck [DCB_BCN_ATTR_GI] = {.type = NLA_U32}, 156859ee3c4SAlexander Duyck [DCB_BCN_ATTR_TMAX] = {.type = NLA_U32}, 157859ee3c4SAlexander Duyck [DCB_BCN_ATTR_TD] = {.type = NLA_U32}, 158859ee3c4SAlexander Duyck [DCB_BCN_ATTR_RMIN] = {.type = NLA_U32}, 159859ee3c4SAlexander Duyck [DCB_BCN_ATTR_W] = {.type = NLA_U32}, 160859ee3c4SAlexander Duyck [DCB_BCN_ATTR_RD] = {.type = NLA_U32}, 161859ee3c4SAlexander Duyck [DCB_BCN_ATTR_RU] = {.type = NLA_U32}, 162859ee3c4SAlexander Duyck [DCB_BCN_ATTR_WRTT] = {.type = NLA_U32}, 163859ee3c4SAlexander Duyck [DCB_BCN_ATTR_RI] = {.type = NLA_U32}, 164859ee3c4SAlexander Duyck [DCB_BCN_ATTR_C] = {.type = NLA_U32}, 165859ee3c4SAlexander Duyck [DCB_BCN_ATTR_ALL] = {.type = NLA_FLAG}, 166859ee3c4SAlexander Duyck }; 167859ee3c4SAlexander Duyck 1686fa382afSYi Zou /* DCB APP nested attributes. */ 169b54452b0SAlexey Dobriyan static const struct nla_policy dcbnl_app_nest[DCB_APP_ATTR_MAX + 1] = { 1706fa382afSYi Zou [DCB_APP_ATTR_IDTYPE] = {.type = NLA_U8}, 1716fa382afSYi Zou [DCB_APP_ATTR_ID] = {.type = NLA_U16}, 1726fa382afSYi Zou [DCB_APP_ATTR_PRIORITY] = {.type = NLA_U8}, 1736fa382afSYi Zou }; 1746fa382afSYi Zou 1753e29027aSJohn Fastabend /* IEEE 802.1Qaz nested attributes. */ 1763e29027aSJohn Fastabend static const struct nla_policy dcbnl_ieee_policy[DCB_ATTR_IEEE_MAX + 1] = { 1773e29027aSJohn Fastabend [DCB_ATTR_IEEE_ETS] = {.len = sizeof(struct ieee_ets)}, 1783e29027aSJohn Fastabend [DCB_ATTR_IEEE_PFC] = {.len = sizeof(struct ieee_pfc)}, 1793e29027aSJohn Fastabend [DCB_ATTR_IEEE_APP_TABLE] = {.type = NLA_NESTED}, 1803e29027aSJohn Fastabend }; 1813e29027aSJohn Fastabend 1823e29027aSJohn Fastabend static const struct nla_policy dcbnl_ieee_app[DCB_ATTR_IEEE_APP_MAX + 1] = { 1833e29027aSJohn Fastabend [DCB_ATTR_IEEE_APP] = {.len = sizeof(struct dcb_app)}, 1843e29027aSJohn Fastabend }; 1853e29027aSJohn Fastabend 186ea45fe4eSShmulik Ravid /* DCB number of traffic classes nested attributes. */ 187ea45fe4eSShmulik Ravid static const struct nla_policy dcbnl_featcfg_nest[DCB_FEATCFG_ATTR_MAX + 1] = { 188ea45fe4eSShmulik Ravid [DCB_FEATCFG_ATTR_ALL] = {.type = NLA_FLAG}, 189ea45fe4eSShmulik Ravid [DCB_FEATCFG_ATTR_PG] = {.type = NLA_U8}, 190ea45fe4eSShmulik Ravid [DCB_FEATCFG_ATTR_PFC] = {.type = NLA_U8}, 191ea45fe4eSShmulik Ravid [DCB_FEATCFG_ATTR_APP] = {.type = NLA_U8}, 192ea45fe4eSShmulik Ravid }; 193ea45fe4eSShmulik Ravid 1949ab933abSJohn Fastabend static LIST_HEAD(dcb_app_list); 1959ab933abSJohn Fastabend static DEFINE_SPINLOCK(dcb_lock); 1969ab933abSJohn Fastabend 1972f90b865SAlexander Duyck /* standard netlink reply call */ 1982f90b865SAlexander Duyck static int dcbnl_reply(u8 value, u8 event, u8 cmd, u8 attr, u32 pid, 1992f90b865SAlexander Duyck u32 seq, u16 flags) 2002f90b865SAlexander Duyck { 2012f90b865SAlexander Duyck struct sk_buff *dcbnl_skb; 2022f90b865SAlexander Duyck struct dcbmsg *dcb; 2032f90b865SAlexander Duyck struct nlmsghdr *nlh; 2042f90b865SAlexander Duyck int ret = -EINVAL; 2052f90b865SAlexander Duyck 2062f90b865SAlexander Duyck dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 2072f90b865SAlexander Duyck if (!dcbnl_skb) 2082f90b865SAlexander Duyck return ret; 2092f90b865SAlexander Duyck 2102f90b865SAlexander Duyck nlh = NLMSG_NEW(dcbnl_skb, pid, seq, event, sizeof(*dcb), flags); 2112f90b865SAlexander Duyck 2122f90b865SAlexander Duyck dcb = NLMSG_DATA(nlh); 2132f90b865SAlexander Duyck dcb->dcb_family = AF_UNSPEC; 2142f90b865SAlexander Duyck dcb->cmd = cmd; 2152f90b865SAlexander Duyck dcb->dcb_pad = 0; 2162f90b865SAlexander Duyck 2172f90b865SAlexander Duyck ret = nla_put_u8(dcbnl_skb, attr, value); 2182f90b865SAlexander Duyck if (ret) 2192f90b865SAlexander Duyck goto err; 2202f90b865SAlexander Duyck 2212f90b865SAlexander Duyck /* end the message, assign the nlmsg_len. */ 2222f90b865SAlexander Duyck nlmsg_end(dcbnl_skb, nlh); 2232f90b865SAlexander Duyck ret = rtnl_unicast(dcbnl_skb, &init_net, pid); 2242f90b865SAlexander Duyck if (ret) 2257eaf5077SJohn Fastabend return -EINVAL; 2262f90b865SAlexander Duyck 2272f90b865SAlexander Duyck return 0; 2282f90b865SAlexander Duyck nlmsg_failure: 2292f90b865SAlexander Duyck err: 230858eb711SRoel Kluin kfree_skb(dcbnl_skb); 2312f90b865SAlexander Duyck return ret; 2322f90b865SAlexander Duyck } 2332f90b865SAlexander Duyck 2342f90b865SAlexander Duyck static int dcbnl_getstate(struct net_device *netdev, struct nlattr **tb, 2352f90b865SAlexander Duyck u32 pid, u32 seq, u16 flags) 2362f90b865SAlexander Duyck { 2372f90b865SAlexander Duyck int ret = -EINVAL; 2382f90b865SAlexander Duyck 2392f90b865SAlexander Duyck /* if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->getstate) */ 2402f90b865SAlexander Duyck if (!netdev->dcbnl_ops->getstate) 2412f90b865SAlexander Duyck return ret; 2422f90b865SAlexander Duyck 2432f90b865SAlexander Duyck ret = dcbnl_reply(netdev->dcbnl_ops->getstate(netdev), RTM_GETDCB, 2442f90b865SAlexander Duyck DCB_CMD_GSTATE, DCB_ATTR_STATE, pid, seq, flags); 2452f90b865SAlexander Duyck 2462f90b865SAlexander Duyck return ret; 2472f90b865SAlexander Duyck } 2482f90b865SAlexander Duyck 2492f90b865SAlexander Duyck static int dcbnl_getpfccfg(struct net_device *netdev, struct nlattr **tb, 2502f90b865SAlexander Duyck u32 pid, u32 seq, u16 flags) 2512f90b865SAlexander Duyck { 2522f90b865SAlexander Duyck struct sk_buff *dcbnl_skb; 2532f90b865SAlexander Duyck struct nlmsghdr *nlh; 2542f90b865SAlexander Duyck struct dcbmsg *dcb; 2552f90b865SAlexander Duyck struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1], *nest; 2562f90b865SAlexander Duyck u8 value; 2572f90b865SAlexander Duyck int ret = -EINVAL; 2582f90b865SAlexander Duyck int i; 2592f90b865SAlexander Duyck int getall = 0; 2602f90b865SAlexander Duyck 2612f90b865SAlexander Duyck if (!tb[DCB_ATTR_PFC_CFG] || !netdev->dcbnl_ops->getpfccfg) 2622f90b865SAlexander Duyck return ret; 2632f90b865SAlexander Duyck 2642f90b865SAlexander Duyck ret = nla_parse_nested(data, DCB_PFC_UP_ATTR_MAX, 2652f90b865SAlexander Duyck tb[DCB_ATTR_PFC_CFG], 2662f90b865SAlexander Duyck dcbnl_pfc_up_nest); 2672f90b865SAlexander Duyck if (ret) 2682f90b865SAlexander Duyck goto err_out; 2692f90b865SAlexander Duyck 2702f90b865SAlexander Duyck dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 2712f90b865SAlexander Duyck if (!dcbnl_skb) 2722f90b865SAlexander Duyck goto err_out; 2732f90b865SAlexander Duyck 2742f90b865SAlexander Duyck nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); 2752f90b865SAlexander Duyck 2762f90b865SAlexander Duyck dcb = NLMSG_DATA(nlh); 2772f90b865SAlexander Duyck dcb->dcb_family = AF_UNSPEC; 2782f90b865SAlexander Duyck dcb->cmd = DCB_CMD_PFC_GCFG; 2792f90b865SAlexander Duyck 2802f90b865SAlexander Duyck nest = nla_nest_start(dcbnl_skb, DCB_ATTR_PFC_CFG); 2812f90b865SAlexander Duyck if (!nest) 2822f90b865SAlexander Duyck goto err; 2832f90b865SAlexander Duyck 2842f90b865SAlexander Duyck if (data[DCB_PFC_UP_ATTR_ALL]) 2852f90b865SAlexander Duyck getall = 1; 2862f90b865SAlexander Duyck 2872f90b865SAlexander Duyck for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) { 2882f90b865SAlexander Duyck if (!getall && !data[i]) 2892f90b865SAlexander Duyck continue; 2902f90b865SAlexander Duyck 2912f90b865SAlexander Duyck netdev->dcbnl_ops->getpfccfg(netdev, i - DCB_PFC_UP_ATTR_0, 2922f90b865SAlexander Duyck &value); 2932f90b865SAlexander Duyck ret = nla_put_u8(dcbnl_skb, i, value); 2942f90b865SAlexander Duyck 2952f90b865SAlexander Duyck if (ret) { 2962f90b865SAlexander Duyck nla_nest_cancel(dcbnl_skb, nest); 2972f90b865SAlexander Duyck goto err; 2982f90b865SAlexander Duyck } 2992f90b865SAlexander Duyck } 3002f90b865SAlexander Duyck nla_nest_end(dcbnl_skb, nest); 3012f90b865SAlexander Duyck 3022f90b865SAlexander Duyck nlmsg_end(dcbnl_skb, nlh); 3032f90b865SAlexander Duyck 3042f90b865SAlexander Duyck ret = rtnl_unicast(dcbnl_skb, &init_net, pid); 3052f90b865SAlexander Duyck if (ret) 3067eaf5077SJohn Fastabend goto err_out; 3072f90b865SAlexander Duyck 3082f90b865SAlexander Duyck return 0; 3092f90b865SAlexander Duyck nlmsg_failure: 3102f90b865SAlexander Duyck err: 311858eb711SRoel Kluin kfree_skb(dcbnl_skb); 3122f90b865SAlexander Duyck err_out: 3132f90b865SAlexander Duyck return -EINVAL; 3142f90b865SAlexander Duyck } 3152f90b865SAlexander Duyck 3162f90b865SAlexander Duyck static int dcbnl_getperm_hwaddr(struct net_device *netdev, struct nlattr **tb, 3172f90b865SAlexander Duyck u32 pid, u32 seq, u16 flags) 3182f90b865SAlexander Duyck { 3192f90b865SAlexander Duyck struct sk_buff *dcbnl_skb; 3202f90b865SAlexander Duyck struct nlmsghdr *nlh; 3212f90b865SAlexander Duyck struct dcbmsg *dcb; 3222f90b865SAlexander Duyck u8 perm_addr[MAX_ADDR_LEN]; 3232f90b865SAlexander Duyck int ret = -EINVAL; 3242f90b865SAlexander Duyck 3252f90b865SAlexander Duyck if (!netdev->dcbnl_ops->getpermhwaddr) 3262f90b865SAlexander Duyck return ret; 3272f90b865SAlexander Duyck 3282f90b865SAlexander Duyck dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 3292f90b865SAlexander Duyck if (!dcbnl_skb) 3302f90b865SAlexander Duyck goto err_out; 3312f90b865SAlexander Duyck 3322f90b865SAlexander Duyck nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); 3332f90b865SAlexander Duyck 3342f90b865SAlexander Duyck dcb = NLMSG_DATA(nlh); 3352f90b865SAlexander Duyck dcb->dcb_family = AF_UNSPEC; 3362f90b865SAlexander Duyck dcb->cmd = DCB_CMD_GPERM_HWADDR; 3372f90b865SAlexander Duyck 3382f90b865SAlexander Duyck netdev->dcbnl_ops->getpermhwaddr(netdev, perm_addr); 3392f90b865SAlexander Duyck 3402f90b865SAlexander Duyck ret = nla_put(dcbnl_skb, DCB_ATTR_PERM_HWADDR, sizeof(perm_addr), 3412f90b865SAlexander Duyck perm_addr); 3422f90b865SAlexander Duyck 3432f90b865SAlexander Duyck nlmsg_end(dcbnl_skb, nlh); 3442f90b865SAlexander Duyck 3452f90b865SAlexander Duyck ret = rtnl_unicast(dcbnl_skb, &init_net, pid); 3462f90b865SAlexander Duyck if (ret) 3477eaf5077SJohn Fastabend goto err_out; 3482f90b865SAlexander Duyck 3492f90b865SAlexander Duyck return 0; 3502f90b865SAlexander Duyck 3512f90b865SAlexander Duyck nlmsg_failure: 352858eb711SRoel Kluin kfree_skb(dcbnl_skb); 3532f90b865SAlexander Duyck err_out: 3542f90b865SAlexander Duyck return -EINVAL; 3552f90b865SAlexander Duyck } 3562f90b865SAlexander Duyck 35746132188SAlexander Duyck static int dcbnl_getcap(struct net_device *netdev, struct nlattr **tb, 35846132188SAlexander Duyck u32 pid, u32 seq, u16 flags) 35946132188SAlexander Duyck { 36046132188SAlexander Duyck struct sk_buff *dcbnl_skb; 36146132188SAlexander Duyck struct nlmsghdr *nlh; 36246132188SAlexander Duyck struct dcbmsg *dcb; 36346132188SAlexander Duyck struct nlattr *data[DCB_CAP_ATTR_MAX + 1], *nest; 36446132188SAlexander Duyck u8 value; 36546132188SAlexander Duyck int ret = -EINVAL; 36646132188SAlexander Duyck int i; 36746132188SAlexander Duyck int getall = 0; 36846132188SAlexander Duyck 36946132188SAlexander Duyck if (!tb[DCB_ATTR_CAP] || !netdev->dcbnl_ops->getcap) 37046132188SAlexander Duyck return ret; 37146132188SAlexander Duyck 37246132188SAlexander Duyck ret = nla_parse_nested(data, DCB_CAP_ATTR_MAX, tb[DCB_ATTR_CAP], 37346132188SAlexander Duyck dcbnl_cap_nest); 37446132188SAlexander Duyck if (ret) 37546132188SAlexander Duyck goto err_out; 37646132188SAlexander Duyck 37746132188SAlexander Duyck dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 37846132188SAlexander Duyck if (!dcbnl_skb) 37946132188SAlexander Duyck goto err_out; 38046132188SAlexander Duyck 38146132188SAlexander Duyck nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); 38246132188SAlexander Duyck 38346132188SAlexander Duyck dcb = NLMSG_DATA(nlh); 38446132188SAlexander Duyck dcb->dcb_family = AF_UNSPEC; 38546132188SAlexander Duyck dcb->cmd = DCB_CMD_GCAP; 38646132188SAlexander Duyck 38746132188SAlexander Duyck nest = nla_nest_start(dcbnl_skb, DCB_ATTR_CAP); 38846132188SAlexander Duyck if (!nest) 38946132188SAlexander Duyck goto err; 39046132188SAlexander Duyck 39146132188SAlexander Duyck if (data[DCB_CAP_ATTR_ALL]) 39246132188SAlexander Duyck getall = 1; 39346132188SAlexander Duyck 39446132188SAlexander Duyck for (i = DCB_CAP_ATTR_ALL+1; i <= DCB_CAP_ATTR_MAX; i++) { 39546132188SAlexander Duyck if (!getall && !data[i]) 39646132188SAlexander Duyck continue; 39746132188SAlexander Duyck 39846132188SAlexander Duyck if (!netdev->dcbnl_ops->getcap(netdev, i, &value)) { 39946132188SAlexander Duyck ret = nla_put_u8(dcbnl_skb, i, value); 40046132188SAlexander Duyck 40146132188SAlexander Duyck if (ret) { 40246132188SAlexander Duyck nla_nest_cancel(dcbnl_skb, nest); 40346132188SAlexander Duyck goto err; 40446132188SAlexander Duyck } 40546132188SAlexander Duyck } 40646132188SAlexander Duyck } 40746132188SAlexander Duyck nla_nest_end(dcbnl_skb, nest); 40846132188SAlexander Duyck 40946132188SAlexander Duyck nlmsg_end(dcbnl_skb, nlh); 41046132188SAlexander Duyck 41146132188SAlexander Duyck ret = rtnl_unicast(dcbnl_skb, &init_net, pid); 41246132188SAlexander Duyck if (ret) 4137eaf5077SJohn Fastabend goto err_out; 41446132188SAlexander Duyck 41546132188SAlexander Duyck return 0; 41646132188SAlexander Duyck nlmsg_failure: 41746132188SAlexander Duyck err: 418858eb711SRoel Kluin kfree_skb(dcbnl_skb); 41946132188SAlexander Duyck err_out: 42046132188SAlexander Duyck return -EINVAL; 42146132188SAlexander Duyck } 42246132188SAlexander Duyck 42333dbabc4SAlexander Duyck static int dcbnl_getnumtcs(struct net_device *netdev, struct nlattr **tb, 42433dbabc4SAlexander Duyck u32 pid, u32 seq, u16 flags) 42533dbabc4SAlexander Duyck { 42633dbabc4SAlexander Duyck struct sk_buff *dcbnl_skb; 42733dbabc4SAlexander Duyck struct nlmsghdr *nlh; 42833dbabc4SAlexander Duyck struct dcbmsg *dcb; 42933dbabc4SAlexander Duyck struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1], *nest; 43033dbabc4SAlexander Duyck u8 value; 43133dbabc4SAlexander Duyck int ret = -EINVAL; 43233dbabc4SAlexander Duyck int i; 43333dbabc4SAlexander Duyck int getall = 0; 43433dbabc4SAlexander Duyck 43533dbabc4SAlexander Duyck if (!tb[DCB_ATTR_NUMTCS] || !netdev->dcbnl_ops->getnumtcs) 43633dbabc4SAlexander Duyck return ret; 43733dbabc4SAlexander Duyck 43833dbabc4SAlexander Duyck ret = nla_parse_nested(data, DCB_NUMTCS_ATTR_MAX, tb[DCB_ATTR_NUMTCS], 43933dbabc4SAlexander Duyck dcbnl_numtcs_nest); 44033dbabc4SAlexander Duyck if (ret) { 44133dbabc4SAlexander Duyck ret = -EINVAL; 44233dbabc4SAlexander Duyck goto err_out; 44333dbabc4SAlexander Duyck } 44433dbabc4SAlexander Duyck 44533dbabc4SAlexander Duyck dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 44633dbabc4SAlexander Duyck if (!dcbnl_skb) { 44733dbabc4SAlexander Duyck ret = -EINVAL; 44833dbabc4SAlexander Duyck goto err_out; 44933dbabc4SAlexander Duyck } 45033dbabc4SAlexander Duyck 45133dbabc4SAlexander Duyck nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); 45233dbabc4SAlexander Duyck 45333dbabc4SAlexander Duyck dcb = NLMSG_DATA(nlh); 45433dbabc4SAlexander Duyck dcb->dcb_family = AF_UNSPEC; 45533dbabc4SAlexander Duyck dcb->cmd = DCB_CMD_GNUMTCS; 45633dbabc4SAlexander Duyck 45733dbabc4SAlexander Duyck nest = nla_nest_start(dcbnl_skb, DCB_ATTR_NUMTCS); 45833dbabc4SAlexander Duyck if (!nest) { 45933dbabc4SAlexander Duyck ret = -EINVAL; 46033dbabc4SAlexander Duyck goto err; 46133dbabc4SAlexander Duyck } 46233dbabc4SAlexander Duyck 46333dbabc4SAlexander Duyck if (data[DCB_NUMTCS_ATTR_ALL]) 46433dbabc4SAlexander Duyck getall = 1; 46533dbabc4SAlexander Duyck 46633dbabc4SAlexander Duyck for (i = DCB_NUMTCS_ATTR_ALL+1; i <= DCB_NUMTCS_ATTR_MAX; i++) { 46733dbabc4SAlexander Duyck if (!getall && !data[i]) 46833dbabc4SAlexander Duyck continue; 46933dbabc4SAlexander Duyck 47033dbabc4SAlexander Duyck ret = netdev->dcbnl_ops->getnumtcs(netdev, i, &value); 47133dbabc4SAlexander Duyck if (!ret) { 47233dbabc4SAlexander Duyck ret = nla_put_u8(dcbnl_skb, i, value); 47333dbabc4SAlexander Duyck 47433dbabc4SAlexander Duyck if (ret) { 47533dbabc4SAlexander Duyck nla_nest_cancel(dcbnl_skb, nest); 47633dbabc4SAlexander Duyck ret = -EINVAL; 47733dbabc4SAlexander Duyck goto err; 47833dbabc4SAlexander Duyck } 47933dbabc4SAlexander Duyck } else { 48033dbabc4SAlexander Duyck goto err; 48133dbabc4SAlexander Duyck } 48233dbabc4SAlexander Duyck } 48333dbabc4SAlexander Duyck nla_nest_end(dcbnl_skb, nest); 48433dbabc4SAlexander Duyck 48533dbabc4SAlexander Duyck nlmsg_end(dcbnl_skb, nlh); 48633dbabc4SAlexander Duyck 48733dbabc4SAlexander Duyck ret = rtnl_unicast(dcbnl_skb, &init_net, pid); 48833dbabc4SAlexander Duyck if (ret) { 48933dbabc4SAlexander Duyck ret = -EINVAL; 4907eaf5077SJohn Fastabend goto err_out; 49133dbabc4SAlexander Duyck } 49233dbabc4SAlexander Duyck 49333dbabc4SAlexander Duyck return 0; 49433dbabc4SAlexander Duyck nlmsg_failure: 49533dbabc4SAlexander Duyck err: 496858eb711SRoel Kluin kfree_skb(dcbnl_skb); 49733dbabc4SAlexander Duyck err_out: 49833dbabc4SAlexander Duyck return ret; 49933dbabc4SAlexander Duyck } 50033dbabc4SAlexander Duyck 50133dbabc4SAlexander Duyck static int dcbnl_setnumtcs(struct net_device *netdev, struct nlattr **tb, 50233dbabc4SAlexander Duyck u32 pid, u32 seq, u16 flags) 50333dbabc4SAlexander Duyck { 50433dbabc4SAlexander Duyck struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1]; 50533dbabc4SAlexander Duyck int ret = -EINVAL; 50633dbabc4SAlexander Duyck u8 value; 50733dbabc4SAlexander Duyck int i; 50833dbabc4SAlexander Duyck 5098b124a8eSDon Skidmore if (!tb[DCB_ATTR_NUMTCS] || !netdev->dcbnl_ops->setnumtcs) 51033dbabc4SAlexander Duyck return ret; 51133dbabc4SAlexander Duyck 51233dbabc4SAlexander Duyck ret = nla_parse_nested(data, DCB_NUMTCS_ATTR_MAX, tb[DCB_ATTR_NUMTCS], 51333dbabc4SAlexander Duyck dcbnl_numtcs_nest); 51433dbabc4SAlexander Duyck 51533dbabc4SAlexander Duyck if (ret) { 51633dbabc4SAlexander Duyck ret = -EINVAL; 51733dbabc4SAlexander Duyck goto err; 51833dbabc4SAlexander Duyck } 51933dbabc4SAlexander Duyck 52033dbabc4SAlexander Duyck for (i = DCB_NUMTCS_ATTR_ALL+1; i <= DCB_NUMTCS_ATTR_MAX; i++) { 52133dbabc4SAlexander Duyck if (data[i] == NULL) 52233dbabc4SAlexander Duyck continue; 52333dbabc4SAlexander Duyck 52433dbabc4SAlexander Duyck value = nla_get_u8(data[i]); 52533dbabc4SAlexander Duyck 52633dbabc4SAlexander Duyck ret = netdev->dcbnl_ops->setnumtcs(netdev, i, value); 52733dbabc4SAlexander Duyck 52833dbabc4SAlexander Duyck if (ret) 52933dbabc4SAlexander Duyck goto operr; 53033dbabc4SAlexander Duyck } 53133dbabc4SAlexander Duyck 53233dbabc4SAlexander Duyck operr: 53333dbabc4SAlexander Duyck ret = dcbnl_reply(!!ret, RTM_SETDCB, DCB_CMD_SNUMTCS, 53433dbabc4SAlexander Duyck DCB_ATTR_NUMTCS, pid, seq, flags); 53533dbabc4SAlexander Duyck 53633dbabc4SAlexander Duyck err: 53733dbabc4SAlexander Duyck return ret; 53833dbabc4SAlexander Duyck } 53933dbabc4SAlexander Duyck 5400eb3aa9bSAlexander Duyck static int dcbnl_getpfcstate(struct net_device *netdev, struct nlattr **tb, 5410eb3aa9bSAlexander Duyck u32 pid, u32 seq, u16 flags) 5420eb3aa9bSAlexander Duyck { 5430eb3aa9bSAlexander Duyck int ret = -EINVAL; 5440eb3aa9bSAlexander Duyck 5450eb3aa9bSAlexander Duyck if (!netdev->dcbnl_ops->getpfcstate) 5460eb3aa9bSAlexander Duyck return ret; 5470eb3aa9bSAlexander Duyck 5480eb3aa9bSAlexander Duyck ret = dcbnl_reply(netdev->dcbnl_ops->getpfcstate(netdev), RTM_GETDCB, 5490eb3aa9bSAlexander Duyck DCB_CMD_PFC_GSTATE, DCB_ATTR_PFC_STATE, 5500eb3aa9bSAlexander Duyck pid, seq, flags); 5510eb3aa9bSAlexander Duyck 5520eb3aa9bSAlexander Duyck return ret; 5530eb3aa9bSAlexander Duyck } 5540eb3aa9bSAlexander Duyck 5550eb3aa9bSAlexander Duyck static int dcbnl_setpfcstate(struct net_device *netdev, struct nlattr **tb, 5560eb3aa9bSAlexander Duyck u32 pid, u32 seq, u16 flags) 5570eb3aa9bSAlexander Duyck { 5580eb3aa9bSAlexander Duyck int ret = -EINVAL; 5590eb3aa9bSAlexander Duyck u8 value; 5600eb3aa9bSAlexander Duyck 5610eb3aa9bSAlexander Duyck if (!tb[DCB_ATTR_PFC_STATE] || !netdev->dcbnl_ops->setpfcstate) 5620eb3aa9bSAlexander Duyck return ret; 5630eb3aa9bSAlexander Duyck 5640eb3aa9bSAlexander Duyck value = nla_get_u8(tb[DCB_ATTR_PFC_STATE]); 5650eb3aa9bSAlexander Duyck 5660eb3aa9bSAlexander Duyck netdev->dcbnl_ops->setpfcstate(netdev, value); 5670eb3aa9bSAlexander Duyck 5680eb3aa9bSAlexander Duyck ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_PFC_SSTATE, DCB_ATTR_PFC_STATE, 5690eb3aa9bSAlexander Duyck pid, seq, flags); 5700eb3aa9bSAlexander Duyck 5710eb3aa9bSAlexander Duyck return ret; 5720eb3aa9bSAlexander Duyck } 5730eb3aa9bSAlexander Duyck 57457949686SYi Zou static int dcbnl_getapp(struct net_device *netdev, struct nlattr **tb, 57557949686SYi Zou u32 pid, u32 seq, u16 flags) 57657949686SYi Zou { 57757949686SYi Zou struct sk_buff *dcbnl_skb; 57857949686SYi Zou struct nlmsghdr *nlh; 57957949686SYi Zou struct dcbmsg *dcb; 58057949686SYi Zou struct nlattr *app_nest; 58157949686SYi Zou struct nlattr *app_tb[DCB_APP_ATTR_MAX + 1]; 58257949686SYi Zou u16 id; 58357949686SYi Zou u8 up, idtype; 58457949686SYi Zou int ret = -EINVAL; 58557949686SYi Zou 5863dce38a0SJohn Fastabend if (!tb[DCB_ATTR_APP]) 58757949686SYi Zou goto out; 58857949686SYi Zou 58957949686SYi Zou ret = nla_parse_nested(app_tb, DCB_APP_ATTR_MAX, tb[DCB_ATTR_APP], 59057949686SYi Zou dcbnl_app_nest); 59157949686SYi Zou if (ret) 59257949686SYi Zou goto out; 59357949686SYi Zou 59457949686SYi Zou ret = -EINVAL; 59557949686SYi Zou /* all must be non-null */ 59657949686SYi Zou if ((!app_tb[DCB_APP_ATTR_IDTYPE]) || 59757949686SYi Zou (!app_tb[DCB_APP_ATTR_ID])) 59857949686SYi Zou goto out; 59957949686SYi Zou 60057949686SYi Zou /* either by eth type or by socket number */ 60157949686SYi Zou idtype = nla_get_u8(app_tb[DCB_APP_ATTR_IDTYPE]); 60257949686SYi Zou if ((idtype != DCB_APP_IDTYPE_ETHTYPE) && 60357949686SYi Zou (idtype != DCB_APP_IDTYPE_PORTNUM)) 60457949686SYi Zou goto out; 60557949686SYi Zou 60657949686SYi Zou id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]); 6073dce38a0SJohn Fastabend 6083dce38a0SJohn Fastabend if (netdev->dcbnl_ops->getapp) { 60957949686SYi Zou up = netdev->dcbnl_ops->getapp(netdev, idtype, id); 6103dce38a0SJohn Fastabend } else { 6113dce38a0SJohn Fastabend struct dcb_app app = { 6123dce38a0SJohn Fastabend .selector = idtype, 6133dce38a0SJohn Fastabend .protocol = id, 6143dce38a0SJohn Fastabend }; 6153dce38a0SJohn Fastabend up = dcb_getapp(netdev, &app); 6163dce38a0SJohn Fastabend } 61757949686SYi Zou 61857949686SYi Zou /* send this back */ 61957949686SYi Zou dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 62057949686SYi Zou if (!dcbnl_skb) 62157949686SYi Zou goto out; 62257949686SYi Zou 62357949686SYi Zou nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); 62457949686SYi Zou dcb = NLMSG_DATA(nlh); 62557949686SYi Zou dcb->dcb_family = AF_UNSPEC; 62657949686SYi Zou dcb->cmd = DCB_CMD_GAPP; 62757949686SYi Zou 62857949686SYi Zou app_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_APP); 629d3337de5SJesper Juhl if (!app_nest) 630d3337de5SJesper Juhl goto out_cancel; 631d3337de5SJesper Juhl 63257949686SYi Zou ret = nla_put_u8(dcbnl_skb, DCB_APP_ATTR_IDTYPE, idtype); 63357949686SYi Zou if (ret) 63457949686SYi Zou goto out_cancel; 63557949686SYi Zou 63657949686SYi Zou ret = nla_put_u16(dcbnl_skb, DCB_APP_ATTR_ID, id); 63757949686SYi Zou if (ret) 63857949686SYi Zou goto out_cancel; 63957949686SYi Zou 64057949686SYi Zou ret = nla_put_u8(dcbnl_skb, DCB_APP_ATTR_PRIORITY, up); 64157949686SYi Zou if (ret) 64257949686SYi Zou goto out_cancel; 64357949686SYi Zou 64457949686SYi Zou nla_nest_end(dcbnl_skb, app_nest); 64557949686SYi Zou nlmsg_end(dcbnl_skb, nlh); 64657949686SYi Zou 64757949686SYi Zou ret = rtnl_unicast(dcbnl_skb, &init_net, pid); 64857949686SYi Zou if (ret) 64957949686SYi Zou goto nlmsg_failure; 65057949686SYi Zou 65157949686SYi Zou goto out; 65257949686SYi Zou 65357949686SYi Zou out_cancel: 65457949686SYi Zou nla_nest_cancel(dcbnl_skb, app_nest); 65557949686SYi Zou nlmsg_failure: 65657949686SYi Zou kfree_skb(dcbnl_skb); 65757949686SYi Zou out: 65857949686SYi Zou return ret; 65957949686SYi Zou } 66057949686SYi Zou 66157949686SYi Zou static int dcbnl_setapp(struct net_device *netdev, struct nlattr **tb, 66257949686SYi Zou u32 pid, u32 seq, u16 flags) 66357949686SYi Zou { 6649ab933abSJohn Fastabend int err, ret = -EINVAL; 66557949686SYi Zou u16 id; 66657949686SYi Zou u8 up, idtype; 66757949686SYi Zou struct nlattr *app_tb[DCB_APP_ATTR_MAX + 1]; 66857949686SYi Zou 6699ab933abSJohn Fastabend if (!tb[DCB_ATTR_APP]) 67057949686SYi Zou goto out; 67157949686SYi Zou 67257949686SYi Zou ret = nla_parse_nested(app_tb, DCB_APP_ATTR_MAX, tb[DCB_ATTR_APP], 67357949686SYi Zou dcbnl_app_nest); 67457949686SYi Zou if (ret) 67557949686SYi Zou goto out; 67657949686SYi Zou 67757949686SYi Zou ret = -EINVAL; 67857949686SYi Zou /* all must be non-null */ 67957949686SYi Zou if ((!app_tb[DCB_APP_ATTR_IDTYPE]) || 68057949686SYi Zou (!app_tb[DCB_APP_ATTR_ID]) || 68157949686SYi Zou (!app_tb[DCB_APP_ATTR_PRIORITY])) 68257949686SYi Zou goto out; 68357949686SYi Zou 68457949686SYi Zou /* either by eth type or by socket number */ 68557949686SYi Zou idtype = nla_get_u8(app_tb[DCB_APP_ATTR_IDTYPE]); 68657949686SYi Zou if ((idtype != DCB_APP_IDTYPE_ETHTYPE) && 68757949686SYi Zou (idtype != DCB_APP_IDTYPE_PORTNUM)) 68857949686SYi Zou goto out; 68957949686SYi Zou 69057949686SYi Zou id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]); 69157949686SYi Zou up = nla_get_u8(app_tb[DCB_APP_ATTR_PRIORITY]); 69257949686SYi Zou 6939ab933abSJohn Fastabend if (netdev->dcbnl_ops->setapp) { 6949ab933abSJohn Fastabend err = netdev->dcbnl_ops->setapp(netdev, idtype, id, up); 6959ab933abSJohn Fastabend } else { 6969ab933abSJohn Fastabend struct dcb_app app; 6979ab933abSJohn Fastabend app.selector = idtype; 6989ab933abSJohn Fastabend app.protocol = id; 6999ab933abSJohn Fastabend app.priority = up; 7009ab933abSJohn Fastabend err = dcb_setapp(netdev, &app); 7019ab933abSJohn Fastabend } 7029ab933abSJohn Fastabend 7039ab933abSJohn Fastabend ret = dcbnl_reply(err, RTM_SETDCB, DCB_CMD_SAPP, DCB_ATTR_APP, 70457949686SYi Zou pid, seq, flags); 70557949686SYi Zou out: 70657949686SYi Zou return ret; 70757949686SYi Zou } 70857949686SYi Zou 7092f90b865SAlexander Duyck static int __dcbnl_pg_getcfg(struct net_device *netdev, struct nlattr **tb, 7102f90b865SAlexander Duyck u32 pid, u32 seq, u16 flags, int dir) 7112f90b865SAlexander Duyck { 7122f90b865SAlexander Duyck struct sk_buff *dcbnl_skb; 7132f90b865SAlexander Duyck struct nlmsghdr *nlh; 7142f90b865SAlexander Duyck struct dcbmsg *dcb; 7152f90b865SAlexander Duyck struct nlattr *pg_nest, *param_nest, *data; 7162f90b865SAlexander Duyck struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1]; 7172f90b865SAlexander Duyck struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1]; 7182f90b865SAlexander Duyck u8 prio, pgid, tc_pct, up_map; 7192f90b865SAlexander Duyck int ret = -EINVAL; 7202f90b865SAlexander Duyck int getall = 0; 7212f90b865SAlexander Duyck int i; 7222f90b865SAlexander Duyck 7232f90b865SAlexander Duyck if (!tb[DCB_ATTR_PG_CFG] || 7242f90b865SAlexander Duyck !netdev->dcbnl_ops->getpgtccfgtx || 7252f90b865SAlexander Duyck !netdev->dcbnl_ops->getpgtccfgrx || 7262f90b865SAlexander Duyck !netdev->dcbnl_ops->getpgbwgcfgtx || 7272f90b865SAlexander Duyck !netdev->dcbnl_ops->getpgbwgcfgrx) 7282f90b865SAlexander Duyck return ret; 7292f90b865SAlexander Duyck 7302f90b865SAlexander Duyck ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX, 7312f90b865SAlexander Duyck tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest); 7322f90b865SAlexander Duyck 7332f90b865SAlexander Duyck if (ret) 7342f90b865SAlexander Duyck goto err_out; 7352f90b865SAlexander Duyck 7362f90b865SAlexander Duyck dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 7372f90b865SAlexander Duyck if (!dcbnl_skb) 7382f90b865SAlexander Duyck goto err_out; 7392f90b865SAlexander Duyck 7402f90b865SAlexander Duyck nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); 7412f90b865SAlexander Duyck 7422f90b865SAlexander Duyck dcb = NLMSG_DATA(nlh); 7432f90b865SAlexander Duyck dcb->dcb_family = AF_UNSPEC; 7442f90b865SAlexander Duyck dcb->cmd = (dir) ? DCB_CMD_PGRX_GCFG : DCB_CMD_PGTX_GCFG; 7452f90b865SAlexander Duyck 7462f90b865SAlexander Duyck pg_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_PG_CFG); 7472f90b865SAlexander Duyck if (!pg_nest) 7482f90b865SAlexander Duyck goto err; 7492f90b865SAlexander Duyck 7502f90b865SAlexander Duyck if (pg_tb[DCB_PG_ATTR_TC_ALL]) 7512f90b865SAlexander Duyck getall = 1; 7522f90b865SAlexander Duyck 7532f90b865SAlexander Duyck for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) { 7542f90b865SAlexander Duyck if (!getall && !pg_tb[i]) 7552f90b865SAlexander Duyck continue; 7562f90b865SAlexander Duyck 7572f90b865SAlexander Duyck if (pg_tb[DCB_PG_ATTR_TC_ALL]) 7582f90b865SAlexander Duyck data = pg_tb[DCB_PG_ATTR_TC_ALL]; 7592f90b865SAlexander Duyck else 7602f90b865SAlexander Duyck data = pg_tb[i]; 7612f90b865SAlexander Duyck ret = nla_parse_nested(param_tb, DCB_TC_ATTR_PARAM_MAX, 7622f90b865SAlexander Duyck data, dcbnl_tc_param_nest); 7632f90b865SAlexander Duyck if (ret) 7642f90b865SAlexander Duyck goto err_pg; 7652f90b865SAlexander Duyck 7662f90b865SAlexander Duyck param_nest = nla_nest_start(dcbnl_skb, i); 7672f90b865SAlexander Duyck if (!param_nest) 7682f90b865SAlexander Duyck goto err_pg; 7692f90b865SAlexander Duyck 7702f90b865SAlexander Duyck pgid = DCB_ATTR_VALUE_UNDEFINED; 7712f90b865SAlexander Duyck prio = DCB_ATTR_VALUE_UNDEFINED; 7722f90b865SAlexander Duyck tc_pct = DCB_ATTR_VALUE_UNDEFINED; 7732f90b865SAlexander Duyck up_map = DCB_ATTR_VALUE_UNDEFINED; 7742f90b865SAlexander Duyck 7752f90b865SAlexander Duyck if (dir) { 7762f90b865SAlexander Duyck /* Rx */ 7772f90b865SAlexander Duyck netdev->dcbnl_ops->getpgtccfgrx(netdev, 7782f90b865SAlexander Duyck i - DCB_PG_ATTR_TC_0, &prio, 7792f90b865SAlexander Duyck &pgid, &tc_pct, &up_map); 7802f90b865SAlexander Duyck } else { 7812f90b865SAlexander Duyck /* Tx */ 7822f90b865SAlexander Duyck netdev->dcbnl_ops->getpgtccfgtx(netdev, 7832f90b865SAlexander Duyck i - DCB_PG_ATTR_TC_0, &prio, 7842f90b865SAlexander Duyck &pgid, &tc_pct, &up_map); 7852f90b865SAlexander Duyck } 7862f90b865SAlexander Duyck 7872f90b865SAlexander Duyck if (param_tb[DCB_TC_ATTR_PARAM_PGID] || 7882f90b865SAlexander Duyck param_tb[DCB_TC_ATTR_PARAM_ALL]) { 7892f90b865SAlexander Duyck ret = nla_put_u8(dcbnl_skb, 7902f90b865SAlexander Duyck DCB_TC_ATTR_PARAM_PGID, pgid); 7912f90b865SAlexander Duyck if (ret) 7922f90b865SAlexander Duyck goto err_param; 7932f90b865SAlexander Duyck } 7942f90b865SAlexander Duyck if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING] || 7952f90b865SAlexander Duyck param_tb[DCB_TC_ATTR_PARAM_ALL]) { 7962f90b865SAlexander Duyck ret = nla_put_u8(dcbnl_skb, 7972f90b865SAlexander Duyck DCB_TC_ATTR_PARAM_UP_MAPPING, up_map); 7982f90b865SAlexander Duyck if (ret) 7992f90b865SAlexander Duyck goto err_param; 8002f90b865SAlexander Duyck } 8012f90b865SAlexander Duyck if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO] || 8022f90b865SAlexander Duyck param_tb[DCB_TC_ATTR_PARAM_ALL]) { 8032f90b865SAlexander Duyck ret = nla_put_u8(dcbnl_skb, 8042f90b865SAlexander Duyck DCB_TC_ATTR_PARAM_STRICT_PRIO, prio); 8052f90b865SAlexander Duyck if (ret) 8062f90b865SAlexander Duyck goto err_param; 8072f90b865SAlexander Duyck } 8082f90b865SAlexander Duyck if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT] || 8092f90b865SAlexander Duyck param_tb[DCB_TC_ATTR_PARAM_ALL]) { 8102f90b865SAlexander Duyck ret = nla_put_u8(dcbnl_skb, DCB_TC_ATTR_PARAM_BW_PCT, 8112f90b865SAlexander Duyck tc_pct); 8122f90b865SAlexander Duyck if (ret) 8132f90b865SAlexander Duyck goto err_param; 8142f90b865SAlexander Duyck } 8152f90b865SAlexander Duyck nla_nest_end(dcbnl_skb, param_nest); 8162f90b865SAlexander Duyck } 8172f90b865SAlexander Duyck 8182f90b865SAlexander Duyck if (pg_tb[DCB_PG_ATTR_BW_ID_ALL]) 8192f90b865SAlexander Duyck getall = 1; 8202f90b865SAlexander Duyck else 8212f90b865SAlexander Duyck getall = 0; 8222f90b865SAlexander Duyck 8232f90b865SAlexander Duyck for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) { 8242f90b865SAlexander Duyck if (!getall && !pg_tb[i]) 8252f90b865SAlexander Duyck continue; 8262f90b865SAlexander Duyck 8272f90b865SAlexander Duyck tc_pct = DCB_ATTR_VALUE_UNDEFINED; 8282f90b865SAlexander Duyck 8292f90b865SAlexander Duyck if (dir) { 8302f90b865SAlexander Duyck /* Rx */ 8312f90b865SAlexander Duyck netdev->dcbnl_ops->getpgbwgcfgrx(netdev, 8322f90b865SAlexander Duyck i - DCB_PG_ATTR_BW_ID_0, &tc_pct); 8332f90b865SAlexander Duyck } else { 8342f90b865SAlexander Duyck /* Tx */ 8352f90b865SAlexander Duyck netdev->dcbnl_ops->getpgbwgcfgtx(netdev, 8362f90b865SAlexander Duyck i - DCB_PG_ATTR_BW_ID_0, &tc_pct); 8372f90b865SAlexander Duyck } 8382f90b865SAlexander Duyck ret = nla_put_u8(dcbnl_skb, i, tc_pct); 8392f90b865SAlexander Duyck 8402f90b865SAlexander Duyck if (ret) 8412f90b865SAlexander Duyck goto err_pg; 8422f90b865SAlexander Duyck } 8432f90b865SAlexander Duyck 8442f90b865SAlexander Duyck nla_nest_end(dcbnl_skb, pg_nest); 8452f90b865SAlexander Duyck 8462f90b865SAlexander Duyck nlmsg_end(dcbnl_skb, nlh); 8472f90b865SAlexander Duyck 8482f90b865SAlexander Duyck ret = rtnl_unicast(dcbnl_skb, &init_net, pid); 8492f90b865SAlexander Duyck if (ret) 8507eaf5077SJohn Fastabend goto err_out; 8512f90b865SAlexander Duyck 8522f90b865SAlexander Duyck return 0; 8532f90b865SAlexander Duyck 8542f90b865SAlexander Duyck err_param: 8552f90b865SAlexander Duyck nla_nest_cancel(dcbnl_skb, param_nest); 8562f90b865SAlexander Duyck err_pg: 8572f90b865SAlexander Duyck nla_nest_cancel(dcbnl_skb, pg_nest); 8582f90b865SAlexander Duyck nlmsg_failure: 8592f90b865SAlexander Duyck err: 860858eb711SRoel Kluin kfree_skb(dcbnl_skb); 8612f90b865SAlexander Duyck err_out: 8622f90b865SAlexander Duyck ret = -EINVAL; 8632f90b865SAlexander Duyck return ret; 8642f90b865SAlexander Duyck } 8652f90b865SAlexander Duyck 8662f90b865SAlexander Duyck static int dcbnl_pgtx_getcfg(struct net_device *netdev, struct nlattr **tb, 8672f90b865SAlexander Duyck u32 pid, u32 seq, u16 flags) 8682f90b865SAlexander Duyck { 8692f90b865SAlexander Duyck return __dcbnl_pg_getcfg(netdev, tb, pid, seq, flags, 0); 8702f90b865SAlexander Duyck } 8712f90b865SAlexander Duyck 8722f90b865SAlexander Duyck static int dcbnl_pgrx_getcfg(struct net_device *netdev, struct nlattr **tb, 8732f90b865SAlexander Duyck u32 pid, u32 seq, u16 flags) 8742f90b865SAlexander Duyck { 8752f90b865SAlexander Duyck return __dcbnl_pg_getcfg(netdev, tb, pid, seq, flags, 1); 8762f90b865SAlexander Duyck } 8772f90b865SAlexander Duyck 8782f90b865SAlexander Duyck static int dcbnl_setstate(struct net_device *netdev, struct nlattr **tb, 8792f90b865SAlexander Duyck u32 pid, u32 seq, u16 flags) 8802f90b865SAlexander Duyck { 8812f90b865SAlexander Duyck int ret = -EINVAL; 8822f90b865SAlexander Duyck u8 value; 8832f90b865SAlexander Duyck 8842f90b865SAlexander Duyck if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->setstate) 8852f90b865SAlexander Duyck return ret; 8862f90b865SAlexander Duyck 8872f90b865SAlexander Duyck value = nla_get_u8(tb[DCB_ATTR_STATE]); 8882f90b865SAlexander Duyck 8891486a61eSDon Skidmore ret = dcbnl_reply(netdev->dcbnl_ops->setstate(netdev, value), 8901486a61eSDon Skidmore RTM_SETDCB, DCB_CMD_SSTATE, DCB_ATTR_STATE, 8912f90b865SAlexander Duyck pid, seq, flags); 8922f90b865SAlexander Duyck 8932f90b865SAlexander Duyck return ret; 8942f90b865SAlexander Duyck } 8952f90b865SAlexander Duyck 8962f90b865SAlexander Duyck static int dcbnl_setpfccfg(struct net_device *netdev, struct nlattr **tb, 8972f90b865SAlexander Duyck u32 pid, u32 seq, u16 flags) 8982f90b865SAlexander Duyck { 8992f90b865SAlexander Duyck struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1]; 9002f90b865SAlexander Duyck int i; 9012f90b865SAlexander Duyck int ret = -EINVAL; 9022f90b865SAlexander Duyck u8 value; 9032f90b865SAlexander Duyck 9042f90b865SAlexander Duyck if (!tb[DCB_ATTR_PFC_CFG] || !netdev->dcbnl_ops->setpfccfg) 9052f90b865SAlexander Duyck return ret; 9062f90b865SAlexander Duyck 9072f90b865SAlexander Duyck ret = nla_parse_nested(data, DCB_PFC_UP_ATTR_MAX, 9082f90b865SAlexander Duyck tb[DCB_ATTR_PFC_CFG], 9092f90b865SAlexander Duyck dcbnl_pfc_up_nest); 9102f90b865SAlexander Duyck if (ret) 9112f90b865SAlexander Duyck goto err; 9122f90b865SAlexander Duyck 9132f90b865SAlexander Duyck for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) { 9142f90b865SAlexander Duyck if (data[i] == NULL) 9152f90b865SAlexander Duyck continue; 9162f90b865SAlexander Duyck value = nla_get_u8(data[i]); 9172f90b865SAlexander Duyck netdev->dcbnl_ops->setpfccfg(netdev, 9182f90b865SAlexander Duyck data[i]->nla_type - DCB_PFC_UP_ATTR_0, value); 9192f90b865SAlexander Duyck } 9202f90b865SAlexander Duyck 9212f90b865SAlexander Duyck ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_PFC_SCFG, DCB_ATTR_PFC_CFG, 9222f90b865SAlexander Duyck pid, seq, flags); 9232f90b865SAlexander Duyck err: 9242f90b865SAlexander Duyck return ret; 9252f90b865SAlexander Duyck } 9262f90b865SAlexander Duyck 9272f90b865SAlexander Duyck static int dcbnl_setall(struct net_device *netdev, struct nlattr **tb, 9282f90b865SAlexander Duyck u32 pid, u32 seq, u16 flags) 9292f90b865SAlexander Duyck { 9302f90b865SAlexander Duyck int ret = -EINVAL; 9312f90b865SAlexander Duyck 9322f90b865SAlexander Duyck if (!tb[DCB_ATTR_SET_ALL] || !netdev->dcbnl_ops->setall) 9332f90b865SAlexander Duyck return ret; 9342f90b865SAlexander Duyck 9352f90b865SAlexander Duyck ret = dcbnl_reply(netdev->dcbnl_ops->setall(netdev), RTM_SETDCB, 9362f90b865SAlexander Duyck DCB_CMD_SET_ALL, DCB_ATTR_SET_ALL, pid, seq, flags); 9372f90b865SAlexander Duyck 9382f90b865SAlexander Duyck return ret; 9392f90b865SAlexander Duyck } 9402f90b865SAlexander Duyck 9412f90b865SAlexander Duyck static int __dcbnl_pg_setcfg(struct net_device *netdev, struct nlattr **tb, 9422f90b865SAlexander Duyck u32 pid, u32 seq, u16 flags, int dir) 9432f90b865SAlexander Duyck { 9442f90b865SAlexander Duyck struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1]; 9452f90b865SAlexander Duyck struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1]; 9462f90b865SAlexander Duyck int ret = -EINVAL; 9472f90b865SAlexander Duyck int i; 9482f90b865SAlexander Duyck u8 pgid; 9492f90b865SAlexander Duyck u8 up_map; 9502f90b865SAlexander Duyck u8 prio; 9512f90b865SAlexander Duyck u8 tc_pct; 9522f90b865SAlexander Duyck 9532f90b865SAlexander Duyck if (!tb[DCB_ATTR_PG_CFG] || 9542f90b865SAlexander Duyck !netdev->dcbnl_ops->setpgtccfgtx || 9552f90b865SAlexander Duyck !netdev->dcbnl_ops->setpgtccfgrx || 9562f90b865SAlexander Duyck !netdev->dcbnl_ops->setpgbwgcfgtx || 9572f90b865SAlexander Duyck !netdev->dcbnl_ops->setpgbwgcfgrx) 9582f90b865SAlexander Duyck return ret; 9592f90b865SAlexander Duyck 9602f90b865SAlexander Duyck ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX, 9612f90b865SAlexander Duyck tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest); 9622f90b865SAlexander Duyck if (ret) 9632f90b865SAlexander Duyck goto err; 9642f90b865SAlexander Duyck 9652f90b865SAlexander Duyck for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) { 9662f90b865SAlexander Duyck if (!pg_tb[i]) 9672f90b865SAlexander Duyck continue; 9682f90b865SAlexander Duyck 9692f90b865SAlexander Duyck ret = nla_parse_nested(param_tb, DCB_TC_ATTR_PARAM_MAX, 9702f90b865SAlexander Duyck pg_tb[i], dcbnl_tc_param_nest); 9712f90b865SAlexander Duyck if (ret) 9722f90b865SAlexander Duyck goto err; 9732f90b865SAlexander Duyck 9742f90b865SAlexander Duyck pgid = DCB_ATTR_VALUE_UNDEFINED; 9752f90b865SAlexander Duyck prio = DCB_ATTR_VALUE_UNDEFINED; 9762f90b865SAlexander Duyck tc_pct = DCB_ATTR_VALUE_UNDEFINED; 9772f90b865SAlexander Duyck up_map = DCB_ATTR_VALUE_UNDEFINED; 9782f90b865SAlexander Duyck 9792f90b865SAlexander Duyck if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO]) 9802f90b865SAlexander Duyck prio = 9812f90b865SAlexander Duyck nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO]); 9822f90b865SAlexander Duyck 9832f90b865SAlexander Duyck if (param_tb[DCB_TC_ATTR_PARAM_PGID]) 9842f90b865SAlexander Duyck pgid = nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_PGID]); 9852f90b865SAlexander Duyck 9862f90b865SAlexander Duyck if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT]) 9872f90b865SAlexander Duyck tc_pct = nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_BW_PCT]); 9882f90b865SAlexander Duyck 9892f90b865SAlexander Duyck if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING]) 9902f90b865SAlexander Duyck up_map = 9912f90b865SAlexander Duyck nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING]); 9922f90b865SAlexander Duyck 9932f90b865SAlexander Duyck /* dir: Tx = 0, Rx = 1 */ 9942f90b865SAlexander Duyck if (dir) { 9952f90b865SAlexander Duyck /* Rx */ 9962f90b865SAlexander Duyck netdev->dcbnl_ops->setpgtccfgrx(netdev, 9972f90b865SAlexander Duyck i - DCB_PG_ATTR_TC_0, 9982f90b865SAlexander Duyck prio, pgid, tc_pct, up_map); 9992f90b865SAlexander Duyck } else { 10002f90b865SAlexander Duyck /* Tx */ 10012f90b865SAlexander Duyck netdev->dcbnl_ops->setpgtccfgtx(netdev, 10022f90b865SAlexander Duyck i - DCB_PG_ATTR_TC_0, 10032f90b865SAlexander Duyck prio, pgid, tc_pct, up_map); 10042f90b865SAlexander Duyck } 10052f90b865SAlexander Duyck } 10062f90b865SAlexander Duyck 10072f90b865SAlexander Duyck for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) { 10082f90b865SAlexander Duyck if (!pg_tb[i]) 10092f90b865SAlexander Duyck continue; 10102f90b865SAlexander Duyck 10112f90b865SAlexander Duyck tc_pct = nla_get_u8(pg_tb[i]); 10122f90b865SAlexander Duyck 10132f90b865SAlexander Duyck /* dir: Tx = 0, Rx = 1 */ 10142f90b865SAlexander Duyck if (dir) { 10152f90b865SAlexander Duyck /* Rx */ 10162f90b865SAlexander Duyck netdev->dcbnl_ops->setpgbwgcfgrx(netdev, 10172f90b865SAlexander Duyck i - DCB_PG_ATTR_BW_ID_0, tc_pct); 10182f90b865SAlexander Duyck } else { 10192f90b865SAlexander Duyck /* Tx */ 10202f90b865SAlexander Duyck netdev->dcbnl_ops->setpgbwgcfgtx(netdev, 10212f90b865SAlexander Duyck i - DCB_PG_ATTR_BW_ID_0, tc_pct); 10222f90b865SAlexander Duyck } 10232f90b865SAlexander Duyck } 10242f90b865SAlexander Duyck 10252f90b865SAlexander Duyck ret = dcbnl_reply(0, RTM_SETDCB, 10262f90b865SAlexander Duyck (dir ? DCB_CMD_PGRX_SCFG : DCB_CMD_PGTX_SCFG), 10272f90b865SAlexander Duyck DCB_ATTR_PG_CFG, pid, seq, flags); 10282f90b865SAlexander Duyck 10292f90b865SAlexander Duyck err: 10302f90b865SAlexander Duyck return ret; 10312f90b865SAlexander Duyck } 10322f90b865SAlexander Duyck 10332f90b865SAlexander Duyck static int dcbnl_pgtx_setcfg(struct net_device *netdev, struct nlattr **tb, 10342f90b865SAlexander Duyck u32 pid, u32 seq, u16 flags) 10352f90b865SAlexander Duyck { 10362f90b865SAlexander Duyck return __dcbnl_pg_setcfg(netdev, tb, pid, seq, flags, 0); 10372f90b865SAlexander Duyck } 10382f90b865SAlexander Duyck 10392f90b865SAlexander Duyck static int dcbnl_pgrx_setcfg(struct net_device *netdev, struct nlattr **tb, 10402f90b865SAlexander Duyck u32 pid, u32 seq, u16 flags) 10412f90b865SAlexander Duyck { 10422f90b865SAlexander Duyck return __dcbnl_pg_setcfg(netdev, tb, pid, seq, flags, 1); 10432f90b865SAlexander Duyck } 10442f90b865SAlexander Duyck 1045859ee3c4SAlexander Duyck static int dcbnl_bcn_getcfg(struct net_device *netdev, struct nlattr **tb, 1046859ee3c4SAlexander Duyck u32 pid, u32 seq, u16 flags) 1047859ee3c4SAlexander Duyck { 1048859ee3c4SAlexander Duyck struct sk_buff *dcbnl_skb; 1049859ee3c4SAlexander Duyck struct nlmsghdr *nlh; 1050859ee3c4SAlexander Duyck struct dcbmsg *dcb; 1051859ee3c4SAlexander Duyck struct nlattr *bcn_nest; 1052859ee3c4SAlexander Duyck struct nlattr *bcn_tb[DCB_BCN_ATTR_MAX + 1]; 1053859ee3c4SAlexander Duyck u8 value_byte; 1054859ee3c4SAlexander Duyck u32 value_integer; 1055859ee3c4SAlexander Duyck int ret = -EINVAL; 1056859ee3c4SAlexander Duyck bool getall = false; 1057859ee3c4SAlexander Duyck int i; 1058859ee3c4SAlexander Duyck 1059859ee3c4SAlexander Duyck if (!tb[DCB_ATTR_BCN] || !netdev->dcbnl_ops->getbcnrp || 1060859ee3c4SAlexander Duyck !netdev->dcbnl_ops->getbcncfg) 1061859ee3c4SAlexander Duyck return ret; 1062859ee3c4SAlexander Duyck 1063859ee3c4SAlexander Duyck ret = nla_parse_nested(bcn_tb, DCB_BCN_ATTR_MAX, 1064859ee3c4SAlexander Duyck tb[DCB_ATTR_BCN], dcbnl_bcn_nest); 1065859ee3c4SAlexander Duyck 1066859ee3c4SAlexander Duyck if (ret) 1067859ee3c4SAlexander Duyck goto err_out; 1068859ee3c4SAlexander Duyck 1069859ee3c4SAlexander Duyck dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 1070859ee3c4SAlexander Duyck if (!dcbnl_skb) 1071859ee3c4SAlexander Duyck goto err_out; 1072859ee3c4SAlexander Duyck 1073859ee3c4SAlexander Duyck nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); 1074859ee3c4SAlexander Duyck 1075859ee3c4SAlexander Duyck dcb = NLMSG_DATA(nlh); 1076859ee3c4SAlexander Duyck dcb->dcb_family = AF_UNSPEC; 1077859ee3c4SAlexander Duyck dcb->cmd = DCB_CMD_BCN_GCFG; 1078859ee3c4SAlexander Duyck 1079859ee3c4SAlexander Duyck bcn_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_BCN); 1080859ee3c4SAlexander Duyck if (!bcn_nest) 1081859ee3c4SAlexander Duyck goto err; 1082859ee3c4SAlexander Duyck 1083859ee3c4SAlexander Duyck if (bcn_tb[DCB_BCN_ATTR_ALL]) 1084859ee3c4SAlexander Duyck getall = true; 1085859ee3c4SAlexander Duyck 1086859ee3c4SAlexander Duyck for (i = DCB_BCN_ATTR_RP_0; i <= DCB_BCN_ATTR_RP_7; i++) { 1087859ee3c4SAlexander Duyck if (!getall && !bcn_tb[i]) 1088859ee3c4SAlexander Duyck continue; 1089859ee3c4SAlexander Duyck 1090859ee3c4SAlexander Duyck netdev->dcbnl_ops->getbcnrp(netdev, i - DCB_BCN_ATTR_RP_0, 1091859ee3c4SAlexander Duyck &value_byte); 1092859ee3c4SAlexander Duyck ret = nla_put_u8(dcbnl_skb, i, value_byte); 1093859ee3c4SAlexander Duyck if (ret) 1094859ee3c4SAlexander Duyck goto err_bcn; 1095859ee3c4SAlexander Duyck } 1096859ee3c4SAlexander Duyck 1097f4314e81SDon Skidmore for (i = DCB_BCN_ATTR_BCNA_0; i <= DCB_BCN_ATTR_RI; i++) { 1098859ee3c4SAlexander Duyck if (!getall && !bcn_tb[i]) 1099859ee3c4SAlexander Duyck continue; 1100859ee3c4SAlexander Duyck 1101859ee3c4SAlexander Duyck netdev->dcbnl_ops->getbcncfg(netdev, i, 1102859ee3c4SAlexander Duyck &value_integer); 1103859ee3c4SAlexander Duyck ret = nla_put_u32(dcbnl_skb, i, value_integer); 1104859ee3c4SAlexander Duyck if (ret) 1105859ee3c4SAlexander Duyck goto err_bcn; 1106859ee3c4SAlexander Duyck } 1107859ee3c4SAlexander Duyck 1108859ee3c4SAlexander Duyck nla_nest_end(dcbnl_skb, bcn_nest); 1109859ee3c4SAlexander Duyck 1110859ee3c4SAlexander Duyck nlmsg_end(dcbnl_skb, nlh); 1111859ee3c4SAlexander Duyck 1112859ee3c4SAlexander Duyck ret = rtnl_unicast(dcbnl_skb, &init_net, pid); 1113859ee3c4SAlexander Duyck if (ret) 11147eaf5077SJohn Fastabend goto err_out; 1115859ee3c4SAlexander Duyck 1116859ee3c4SAlexander Duyck return 0; 1117859ee3c4SAlexander Duyck 1118859ee3c4SAlexander Duyck err_bcn: 1119859ee3c4SAlexander Duyck nla_nest_cancel(dcbnl_skb, bcn_nest); 1120859ee3c4SAlexander Duyck nlmsg_failure: 1121859ee3c4SAlexander Duyck err: 1122858eb711SRoel Kluin kfree_skb(dcbnl_skb); 1123859ee3c4SAlexander Duyck err_out: 1124859ee3c4SAlexander Duyck ret = -EINVAL; 1125859ee3c4SAlexander Duyck return ret; 1126859ee3c4SAlexander Duyck } 1127859ee3c4SAlexander Duyck 1128859ee3c4SAlexander Duyck static int dcbnl_bcn_setcfg(struct net_device *netdev, struct nlattr **tb, 1129859ee3c4SAlexander Duyck u32 pid, u32 seq, u16 flags) 1130859ee3c4SAlexander Duyck { 1131859ee3c4SAlexander Duyck struct nlattr *data[DCB_BCN_ATTR_MAX + 1]; 1132859ee3c4SAlexander Duyck int i; 1133859ee3c4SAlexander Duyck int ret = -EINVAL; 1134859ee3c4SAlexander Duyck u8 value_byte; 1135859ee3c4SAlexander Duyck u32 value_int; 1136859ee3c4SAlexander Duyck 1137f64f9e71SJoe Perches if (!tb[DCB_ATTR_BCN] || !netdev->dcbnl_ops->setbcncfg || 1138f64f9e71SJoe Perches !netdev->dcbnl_ops->setbcnrp) 1139859ee3c4SAlexander Duyck return ret; 1140859ee3c4SAlexander Duyck 1141859ee3c4SAlexander Duyck ret = nla_parse_nested(data, DCB_BCN_ATTR_MAX, 1142859ee3c4SAlexander Duyck tb[DCB_ATTR_BCN], 1143859ee3c4SAlexander Duyck dcbnl_pfc_up_nest); 1144859ee3c4SAlexander Duyck if (ret) 1145859ee3c4SAlexander Duyck goto err; 1146859ee3c4SAlexander Duyck 1147859ee3c4SAlexander Duyck for (i = DCB_BCN_ATTR_RP_0; i <= DCB_BCN_ATTR_RP_7; i++) { 1148859ee3c4SAlexander Duyck if (data[i] == NULL) 1149859ee3c4SAlexander Duyck continue; 1150859ee3c4SAlexander Duyck value_byte = nla_get_u8(data[i]); 1151859ee3c4SAlexander Duyck netdev->dcbnl_ops->setbcnrp(netdev, 1152859ee3c4SAlexander Duyck data[i]->nla_type - DCB_BCN_ATTR_RP_0, value_byte); 1153859ee3c4SAlexander Duyck } 1154859ee3c4SAlexander Duyck 1155f4314e81SDon Skidmore for (i = DCB_BCN_ATTR_BCNA_0; i <= DCB_BCN_ATTR_RI; i++) { 1156859ee3c4SAlexander Duyck if (data[i] == NULL) 1157859ee3c4SAlexander Duyck continue; 1158859ee3c4SAlexander Duyck value_int = nla_get_u32(data[i]); 1159859ee3c4SAlexander Duyck netdev->dcbnl_ops->setbcncfg(netdev, 1160859ee3c4SAlexander Duyck i, value_int); 1161859ee3c4SAlexander Duyck } 1162859ee3c4SAlexander Duyck 1163859ee3c4SAlexander Duyck ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_BCN_SCFG, DCB_ATTR_BCN, 1164859ee3c4SAlexander Duyck pid, seq, flags); 1165859ee3c4SAlexander Duyck err: 1166859ee3c4SAlexander Duyck return ret; 1167859ee3c4SAlexander Duyck } 1168859ee3c4SAlexander Duyck 1169dc6ed1dfSShmulik Ravid static int dcbnl_build_peer_app(struct net_device *netdev, struct sk_buff* skb, 1170dc6ed1dfSShmulik Ravid int app_nested_type, int app_info_type, 1171dc6ed1dfSShmulik Ravid int app_entry_type) 1172eed84713SShmulik Ravid { 1173eed84713SShmulik Ravid struct dcb_peer_app_info info; 1174eed84713SShmulik Ravid struct dcb_app *table = NULL; 1175eed84713SShmulik Ravid const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; 1176eed84713SShmulik Ravid u16 app_count; 1177eed84713SShmulik Ravid int err; 1178eed84713SShmulik Ravid 1179eed84713SShmulik Ravid 1180eed84713SShmulik Ravid /** 1181eed84713SShmulik Ravid * retrieve the peer app configuration form the driver. If the driver 1182eed84713SShmulik Ravid * handlers fail exit without doing anything 1183eed84713SShmulik Ravid */ 1184eed84713SShmulik Ravid err = ops->peer_getappinfo(netdev, &info, &app_count); 1185eed84713SShmulik Ravid if (!err && app_count) { 1186eed84713SShmulik Ravid table = kmalloc(sizeof(struct dcb_app) * app_count, GFP_KERNEL); 1187eed84713SShmulik Ravid if (!table) 1188eed84713SShmulik Ravid return -ENOMEM; 1189eed84713SShmulik Ravid 1190eed84713SShmulik Ravid err = ops->peer_getapptable(netdev, table); 1191eed84713SShmulik Ravid } 1192eed84713SShmulik Ravid 1193eed84713SShmulik Ravid if (!err) { 1194eed84713SShmulik Ravid u16 i; 1195eed84713SShmulik Ravid struct nlattr *app; 1196eed84713SShmulik Ravid 1197eed84713SShmulik Ravid /** 1198eed84713SShmulik Ravid * build the message, from here on the only possible failure 1199eed84713SShmulik Ravid * is due to the skb size 1200eed84713SShmulik Ravid */ 1201eed84713SShmulik Ravid err = -EMSGSIZE; 1202eed84713SShmulik Ravid 1203dc6ed1dfSShmulik Ravid app = nla_nest_start(skb, app_nested_type); 1204eed84713SShmulik Ravid if (!app) 1205eed84713SShmulik Ravid goto nla_put_failure; 1206eed84713SShmulik Ravid 1207dc6ed1dfSShmulik Ravid if (app_info_type) 1208dc6ed1dfSShmulik Ravid NLA_PUT(skb, app_info_type, sizeof(info), &info); 1209dc6ed1dfSShmulik Ravid 1210eed84713SShmulik Ravid for (i = 0; i < app_count; i++) 1211dc6ed1dfSShmulik Ravid NLA_PUT(skb, app_entry_type, sizeof(struct dcb_app), 1212eed84713SShmulik Ravid &table[i]); 1213eed84713SShmulik Ravid 1214eed84713SShmulik Ravid nla_nest_end(skb, app); 1215eed84713SShmulik Ravid } 1216eed84713SShmulik Ravid err = 0; 1217eed84713SShmulik Ravid 1218eed84713SShmulik Ravid nla_put_failure: 1219eed84713SShmulik Ravid kfree(table); 1220eed84713SShmulik Ravid return err; 1221eed84713SShmulik Ravid } 12223e29027aSJohn Fastabend 12233e29027aSJohn Fastabend /* Handle IEEE 802.1Qaz GET commands. */ 1224314b4778SJohn Fastabend static int dcbnl_ieee_fill(struct sk_buff *skb, struct net_device *netdev) 12253e29027aSJohn Fastabend { 12269ab933abSJohn Fastabend struct nlattr *ieee, *app; 12279ab933abSJohn Fastabend struct dcb_app_type *itr; 12283e29027aSJohn Fastabend const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; 1229c7797bafSJohn Fastabend int dcbx; 1230314b4778SJohn Fastabend int err = -EMSGSIZE; 12313e29027aSJohn Fastabend 12323e29027aSJohn Fastabend NLA_PUT_STRING(skb, DCB_ATTR_IFNAME, netdev->name); 12333e29027aSJohn Fastabend 12343e29027aSJohn Fastabend ieee = nla_nest_start(skb, DCB_ATTR_IEEE); 12353e29027aSJohn Fastabend if (!ieee) 12363e29027aSJohn Fastabend goto nla_put_failure; 12373e29027aSJohn Fastabend 12383e29027aSJohn Fastabend if (ops->ieee_getets) { 12393e29027aSJohn Fastabend struct ieee_ets ets; 12403e29027aSJohn Fastabend err = ops->ieee_getets(netdev, &ets); 12413e29027aSJohn Fastabend if (!err) 12423e29027aSJohn Fastabend NLA_PUT(skb, DCB_ATTR_IEEE_ETS, sizeof(ets), &ets); 12433e29027aSJohn Fastabend } 12443e29027aSJohn Fastabend 12453e29027aSJohn Fastabend if (ops->ieee_getpfc) { 12463e29027aSJohn Fastabend struct ieee_pfc pfc; 12473e29027aSJohn Fastabend err = ops->ieee_getpfc(netdev, &pfc); 12483e29027aSJohn Fastabend if (!err) 12493e29027aSJohn Fastabend NLA_PUT(skb, DCB_ATTR_IEEE_PFC, sizeof(pfc), &pfc); 12503e29027aSJohn Fastabend } 12513e29027aSJohn Fastabend 12529ab933abSJohn Fastabend app = nla_nest_start(skb, DCB_ATTR_IEEE_APP_TABLE); 12539ab933abSJohn Fastabend if (!app) 12549ab933abSJohn Fastabend goto nla_put_failure; 12559ab933abSJohn Fastabend 12569ab933abSJohn Fastabend spin_lock(&dcb_lock); 12579ab933abSJohn Fastabend list_for_each_entry(itr, &dcb_app_list, list) { 125870bfa2d2SDan Carpenter if (strncmp(itr->name, netdev->name, IFNAMSIZ) == 0) { 125970bfa2d2SDan Carpenter err = nla_put(skb, DCB_ATTR_IEEE_APP, sizeof(itr->app), 126070bfa2d2SDan Carpenter &itr->app); 126170bfa2d2SDan Carpenter if (err) { 126270bfa2d2SDan Carpenter spin_unlock(&dcb_lock); 126370bfa2d2SDan Carpenter goto nla_put_failure; 126470bfa2d2SDan Carpenter } 126570bfa2d2SDan Carpenter } 12669ab933abSJohn Fastabend } 1267c7797bafSJohn Fastabend 1268c7797bafSJohn Fastabend if (netdev->dcbnl_ops->getdcbx) 1269c7797bafSJohn Fastabend dcbx = netdev->dcbnl_ops->getdcbx(netdev); 1270c7797bafSJohn Fastabend else 1271c7797bafSJohn Fastabend dcbx = -EOPNOTSUPP; 1272c7797bafSJohn Fastabend 12739ab933abSJohn Fastabend spin_unlock(&dcb_lock); 12749ab933abSJohn Fastabend nla_nest_end(skb, app); 12759ab933abSJohn Fastabend 1276eed84713SShmulik Ravid /* get peer info if available */ 1277eed84713SShmulik Ravid if (ops->ieee_peer_getets) { 1278eed84713SShmulik Ravid struct ieee_ets ets; 1279eed84713SShmulik Ravid err = ops->ieee_peer_getets(netdev, &ets); 1280eed84713SShmulik Ravid if (!err) 1281eed84713SShmulik Ravid NLA_PUT(skb, DCB_ATTR_IEEE_PEER_ETS, sizeof(ets), &ets); 1282eed84713SShmulik Ravid } 1283eed84713SShmulik Ravid 1284eed84713SShmulik Ravid if (ops->ieee_peer_getpfc) { 1285eed84713SShmulik Ravid struct ieee_pfc pfc; 1286eed84713SShmulik Ravid err = ops->ieee_peer_getpfc(netdev, &pfc); 1287eed84713SShmulik Ravid if (!err) 1288eed84713SShmulik Ravid NLA_PUT(skb, DCB_ATTR_IEEE_PEER_PFC, sizeof(pfc), &pfc); 1289eed84713SShmulik Ravid } 1290eed84713SShmulik Ravid 1291eed84713SShmulik Ravid if (ops->peer_getappinfo && ops->peer_getapptable) { 1292dc6ed1dfSShmulik Ravid err = dcbnl_build_peer_app(netdev, skb, 1293dc6ed1dfSShmulik Ravid DCB_ATTR_IEEE_PEER_APP, 1294dc6ed1dfSShmulik Ravid DCB_ATTR_IEEE_APP_UNSPEC, 1295dc6ed1dfSShmulik Ravid DCB_ATTR_IEEE_APP); 1296eed84713SShmulik Ravid if (err) 1297eed84713SShmulik Ravid goto nla_put_failure; 1298eed84713SShmulik Ravid } 1299eed84713SShmulik Ravid 13003e29027aSJohn Fastabend nla_nest_end(skb, ieee); 1301c7797bafSJohn Fastabend if (dcbx >= 0) { 1302c7797bafSJohn Fastabend err = nla_put_u8(skb, DCB_ATTR_DCBX, dcbx); 1303c7797bafSJohn Fastabend if (err) 1304c7797bafSJohn Fastabend goto nla_put_failure; 1305c7797bafSJohn Fastabend } 13063e29027aSJohn Fastabend 1307314b4778SJohn Fastabend return 0; 1308314b4778SJohn Fastabend 13093e29027aSJohn Fastabend nla_put_failure: 1310314b4778SJohn Fastabend return err; 13113e29027aSJohn Fastabend } 13123e29027aSJohn Fastabend 1313314b4778SJohn Fastabend int dcbnl_notify(struct net_device *dev, int event, int cmd, 1314314b4778SJohn Fastabend u32 seq, u32 pid) 1315314b4778SJohn Fastabend { 1316314b4778SJohn Fastabend struct net *net = dev_net(dev); 1317314b4778SJohn Fastabend struct sk_buff *skb; 1318314b4778SJohn Fastabend struct nlmsghdr *nlh; 1319314b4778SJohn Fastabend struct dcbmsg *dcb; 1320314b4778SJohn Fastabend const struct dcbnl_rtnl_ops *ops = dev->dcbnl_ops; 1321314b4778SJohn Fastabend int err; 1322314b4778SJohn Fastabend 1323314b4778SJohn Fastabend if (!ops) 1324314b4778SJohn Fastabend return -EOPNOTSUPP; 1325314b4778SJohn Fastabend 1326314b4778SJohn Fastabend skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 1327314b4778SJohn Fastabend if (!skb) 1328314b4778SJohn Fastabend return -ENOBUFS; 1329314b4778SJohn Fastabend 1330314b4778SJohn Fastabend nlh = nlmsg_put(skb, pid, 0, event, sizeof(*dcb), 0); 1331314b4778SJohn Fastabend if (nlh == NULL) { 1332314b4778SJohn Fastabend kfree(skb); 1333314b4778SJohn Fastabend return -EMSGSIZE; 1334314b4778SJohn Fastabend } 1335314b4778SJohn Fastabend 1336314b4778SJohn Fastabend dcb = NLMSG_DATA(nlh); 1337314b4778SJohn Fastabend dcb->dcb_family = AF_UNSPEC; 1338314b4778SJohn Fastabend dcb->cmd = cmd; 1339314b4778SJohn Fastabend 1340314b4778SJohn Fastabend err = dcbnl_ieee_fill(skb, dev); 1341314b4778SJohn Fastabend if (err < 0) { 1342314b4778SJohn Fastabend /* Report error to broadcast listeners */ 1343314b4778SJohn Fastabend nlmsg_cancel(skb, nlh); 1344314b4778SJohn Fastabend kfree_skb(skb); 1345314b4778SJohn Fastabend rtnl_set_sk_err(net, RTNLGRP_DCB, err); 1346314b4778SJohn Fastabend } else { 1347314b4778SJohn Fastabend /* End nlmsg and notify broadcast listeners */ 1348314b4778SJohn Fastabend nlmsg_end(skb, nlh); 1349314b4778SJohn Fastabend rtnl_notify(skb, net, 0, RTNLGRP_DCB, NULL, GFP_KERNEL); 1350314b4778SJohn Fastabend } 1351314b4778SJohn Fastabend 1352314b4778SJohn Fastabend return err; 1353314b4778SJohn Fastabend } 1354314b4778SJohn Fastabend EXPORT_SYMBOL(dcbnl_notify); 1355314b4778SJohn Fastabend 1356314b4778SJohn Fastabend /* Handle IEEE 802.1Qaz SET commands. If any requested operation can not 1357314b4778SJohn Fastabend * be completed the entire msg is aborted and error value is returned. 1358314b4778SJohn Fastabend * No attempt is made to reconcile the case where only part of the 1359314b4778SJohn Fastabend * cmd can be completed. 1360314b4778SJohn Fastabend */ 1361314b4778SJohn Fastabend static int dcbnl_ieee_set(struct net_device *netdev, struct nlattr **tb, 1362314b4778SJohn Fastabend u32 pid, u32 seq, u16 flags) 1363314b4778SJohn Fastabend { 1364314b4778SJohn Fastabend const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; 1365314b4778SJohn Fastabend struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1]; 1366314b4778SJohn Fastabend int err = -EOPNOTSUPP; 1367314b4778SJohn Fastabend 1368314b4778SJohn Fastabend if (!ops) 1369314b4778SJohn Fastabend return err; 1370314b4778SJohn Fastabend 1371314b4778SJohn Fastabend err = nla_parse_nested(ieee, DCB_ATTR_IEEE_MAX, 1372314b4778SJohn Fastabend tb[DCB_ATTR_IEEE], dcbnl_ieee_policy); 1373314b4778SJohn Fastabend if (err) 1374314b4778SJohn Fastabend return err; 1375314b4778SJohn Fastabend 1376314b4778SJohn Fastabend if (ieee[DCB_ATTR_IEEE_ETS] && ops->ieee_setets) { 1377314b4778SJohn Fastabend struct ieee_ets *ets = nla_data(ieee[DCB_ATTR_IEEE_ETS]); 1378314b4778SJohn Fastabend err = ops->ieee_setets(netdev, ets); 1379314b4778SJohn Fastabend if (err) 1380314b4778SJohn Fastabend goto err; 1381314b4778SJohn Fastabend } 1382314b4778SJohn Fastabend 1383314b4778SJohn Fastabend if (ieee[DCB_ATTR_IEEE_PFC] && ops->ieee_setpfc) { 1384314b4778SJohn Fastabend struct ieee_pfc *pfc = nla_data(ieee[DCB_ATTR_IEEE_PFC]); 1385314b4778SJohn Fastabend err = ops->ieee_setpfc(netdev, pfc); 1386314b4778SJohn Fastabend if (err) 1387314b4778SJohn Fastabend goto err; 1388314b4778SJohn Fastabend } 1389314b4778SJohn Fastabend 1390314b4778SJohn Fastabend if (ieee[DCB_ATTR_IEEE_APP_TABLE]) { 1391314b4778SJohn Fastabend struct nlattr *attr; 1392314b4778SJohn Fastabend int rem; 1393314b4778SJohn Fastabend 1394314b4778SJohn Fastabend nla_for_each_nested(attr, ieee[DCB_ATTR_IEEE_APP_TABLE], rem) { 1395314b4778SJohn Fastabend struct dcb_app *app_data; 1396314b4778SJohn Fastabend if (nla_type(attr) != DCB_ATTR_IEEE_APP) 1397314b4778SJohn Fastabend continue; 1398314b4778SJohn Fastabend app_data = nla_data(attr); 1399314b4778SJohn Fastabend if (ops->ieee_setapp) 1400314b4778SJohn Fastabend err = ops->ieee_setapp(netdev, app_data); 1401314b4778SJohn Fastabend else 1402b6db2174SJohn Fastabend err = dcb_ieee_setapp(netdev, app_data); 1403314b4778SJohn Fastabend if (err) 1404314b4778SJohn Fastabend goto err; 1405314b4778SJohn Fastabend } 1406314b4778SJohn Fastabend } 1407314b4778SJohn Fastabend 1408314b4778SJohn Fastabend err: 1409314b4778SJohn Fastabend dcbnl_reply(err, RTM_SETDCB, DCB_CMD_IEEE_SET, DCB_ATTR_IEEE, 1410314b4778SJohn Fastabend pid, seq, flags); 1411314b4778SJohn Fastabend dcbnl_notify(netdev, RTM_SETDCB, DCB_CMD_IEEE_SET, seq, 0); 1412314b4778SJohn Fastabend return err; 1413314b4778SJohn Fastabend } 1414314b4778SJohn Fastabend 1415314b4778SJohn Fastabend static int dcbnl_ieee_get(struct net_device *netdev, struct nlattr **tb, 1416314b4778SJohn Fastabend u32 pid, u32 seq, u16 flags) 1417314b4778SJohn Fastabend { 1418314b4778SJohn Fastabend struct net *net = dev_net(netdev); 1419314b4778SJohn Fastabend struct sk_buff *skb; 1420314b4778SJohn Fastabend struct nlmsghdr *nlh; 1421314b4778SJohn Fastabend struct dcbmsg *dcb; 1422314b4778SJohn Fastabend const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; 1423314b4778SJohn Fastabend int err; 1424314b4778SJohn Fastabend 1425314b4778SJohn Fastabend if (!ops) 1426314b4778SJohn Fastabend return -EOPNOTSUPP; 1427314b4778SJohn Fastabend 1428314b4778SJohn Fastabend skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 1429314b4778SJohn Fastabend if (!skb) 1430314b4778SJohn Fastabend return -ENOBUFS; 1431314b4778SJohn Fastabend 1432314b4778SJohn Fastabend nlh = nlmsg_put(skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); 1433314b4778SJohn Fastabend if (nlh == NULL) { 1434314b4778SJohn Fastabend kfree(skb); 1435314b4778SJohn Fastabend return -EMSGSIZE; 1436314b4778SJohn Fastabend } 1437314b4778SJohn Fastabend 1438314b4778SJohn Fastabend dcb = NLMSG_DATA(nlh); 1439314b4778SJohn Fastabend dcb->dcb_family = AF_UNSPEC; 1440314b4778SJohn Fastabend dcb->cmd = DCB_CMD_IEEE_GET; 1441314b4778SJohn Fastabend 1442314b4778SJohn Fastabend err = dcbnl_ieee_fill(skb, netdev); 1443314b4778SJohn Fastabend 1444314b4778SJohn Fastabend if (err < 0) { 1445314b4778SJohn Fastabend nlmsg_cancel(skb, nlh); 1446314b4778SJohn Fastabend kfree_skb(skb); 1447314b4778SJohn Fastabend } else { 1448314b4778SJohn Fastabend nlmsg_end(skb, nlh); 1449314b4778SJohn Fastabend err = rtnl_unicast(skb, net, pid); 1450314b4778SJohn Fastabend } 1451314b4778SJohn Fastabend 1452314b4778SJohn Fastabend return err; 1453314b4778SJohn Fastabend } 1454f9ae7e4bSJohn Fastabend 1455f9ae7e4bSJohn Fastabend static int dcbnl_ieee_del(struct net_device *netdev, struct nlattr **tb, 1456f9ae7e4bSJohn Fastabend u32 pid, u32 seq, u16 flags) 1457f9ae7e4bSJohn Fastabend { 1458f9ae7e4bSJohn Fastabend const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; 1459f9ae7e4bSJohn Fastabend struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1]; 1460f9ae7e4bSJohn Fastabend int err = -EOPNOTSUPP; 1461f9ae7e4bSJohn Fastabend 1462f9ae7e4bSJohn Fastabend if (!ops) 1463f9ae7e4bSJohn Fastabend return -EOPNOTSUPP; 1464f9ae7e4bSJohn Fastabend 1465f9ae7e4bSJohn Fastabend if (!tb[DCB_ATTR_IEEE]) 1466f9ae7e4bSJohn Fastabend return -EINVAL; 1467f9ae7e4bSJohn Fastabend 1468f9ae7e4bSJohn Fastabend err = nla_parse_nested(ieee, DCB_ATTR_IEEE_MAX, 1469f9ae7e4bSJohn Fastabend tb[DCB_ATTR_IEEE], dcbnl_ieee_policy); 1470f9ae7e4bSJohn Fastabend if (err) 1471f9ae7e4bSJohn Fastabend return err; 1472f9ae7e4bSJohn Fastabend 1473f9ae7e4bSJohn Fastabend if (ieee[DCB_ATTR_IEEE_APP_TABLE]) { 1474f9ae7e4bSJohn Fastabend struct nlattr *attr; 1475f9ae7e4bSJohn Fastabend int rem; 1476f9ae7e4bSJohn Fastabend 1477f9ae7e4bSJohn Fastabend nla_for_each_nested(attr, ieee[DCB_ATTR_IEEE_APP_TABLE], rem) { 1478f9ae7e4bSJohn Fastabend struct dcb_app *app_data; 1479f9ae7e4bSJohn Fastabend 1480f9ae7e4bSJohn Fastabend if (nla_type(attr) != DCB_ATTR_IEEE_APP) 1481f9ae7e4bSJohn Fastabend continue; 1482f9ae7e4bSJohn Fastabend app_data = nla_data(attr); 1483f9ae7e4bSJohn Fastabend if (ops->ieee_delapp) 1484f9ae7e4bSJohn Fastabend err = ops->ieee_delapp(netdev, app_data); 1485f9ae7e4bSJohn Fastabend else 1486f9ae7e4bSJohn Fastabend err = dcb_ieee_delapp(netdev, app_data); 1487f9ae7e4bSJohn Fastabend if (err) 1488f9ae7e4bSJohn Fastabend goto err; 1489f9ae7e4bSJohn Fastabend } 1490f9ae7e4bSJohn Fastabend } 1491f9ae7e4bSJohn Fastabend 1492f9ae7e4bSJohn Fastabend err: 1493f9ae7e4bSJohn Fastabend dcbnl_reply(err, RTM_SETDCB, DCB_CMD_IEEE_DEL, DCB_ATTR_IEEE, 1494f9ae7e4bSJohn Fastabend pid, seq, flags); 1495f9ae7e4bSJohn Fastabend dcbnl_notify(netdev, RTM_SETDCB, DCB_CMD_IEEE_DEL, seq, 0); 1496f9ae7e4bSJohn Fastabend return err; 1497f9ae7e4bSJohn Fastabend } 1498f9ae7e4bSJohn Fastabend 1499f9ae7e4bSJohn Fastabend 15006241b625SShmulik Ravid /* DCBX configuration */ 15016241b625SShmulik Ravid static int dcbnl_getdcbx(struct net_device *netdev, struct nlattr **tb, 15026241b625SShmulik Ravid u32 pid, u32 seq, u16 flags) 15036241b625SShmulik Ravid { 15047f891cf1SShmulik Ravid int ret; 15056241b625SShmulik Ravid 15066241b625SShmulik Ravid if (!netdev->dcbnl_ops->getdcbx) 15077f891cf1SShmulik Ravid return -EOPNOTSUPP; 15086241b625SShmulik Ravid 15096241b625SShmulik Ravid ret = dcbnl_reply(netdev->dcbnl_ops->getdcbx(netdev), RTM_GETDCB, 15106241b625SShmulik Ravid DCB_CMD_GDCBX, DCB_ATTR_DCBX, pid, seq, flags); 15116241b625SShmulik Ravid 15126241b625SShmulik Ravid return ret; 15136241b625SShmulik Ravid } 15146241b625SShmulik Ravid 15156241b625SShmulik Ravid static int dcbnl_setdcbx(struct net_device *netdev, struct nlattr **tb, 15166241b625SShmulik Ravid u32 pid, u32 seq, u16 flags) 15176241b625SShmulik Ravid { 15187f891cf1SShmulik Ravid int ret; 15196241b625SShmulik Ravid u8 value; 15206241b625SShmulik Ravid 15217f891cf1SShmulik Ravid if (!netdev->dcbnl_ops->setdcbx) 15227f891cf1SShmulik Ravid return -EOPNOTSUPP; 15237f891cf1SShmulik Ravid 15247f891cf1SShmulik Ravid if (!tb[DCB_ATTR_DCBX]) 15257f891cf1SShmulik Ravid return -EINVAL; 15266241b625SShmulik Ravid 15276241b625SShmulik Ravid value = nla_get_u8(tb[DCB_ATTR_DCBX]); 15286241b625SShmulik Ravid 15296241b625SShmulik Ravid ret = dcbnl_reply(netdev->dcbnl_ops->setdcbx(netdev, value), 15306241b625SShmulik Ravid RTM_SETDCB, DCB_CMD_SDCBX, DCB_ATTR_DCBX, 15316241b625SShmulik Ravid pid, seq, flags); 15326241b625SShmulik Ravid 15336241b625SShmulik Ravid return ret; 15346241b625SShmulik Ravid } 15356241b625SShmulik Ravid 1536ea45fe4eSShmulik Ravid static int dcbnl_getfeatcfg(struct net_device *netdev, struct nlattr **tb, 1537ea45fe4eSShmulik Ravid u32 pid, u32 seq, u16 flags) 1538ea45fe4eSShmulik Ravid { 1539ea45fe4eSShmulik Ravid struct sk_buff *dcbnl_skb; 1540ea45fe4eSShmulik Ravid struct nlmsghdr *nlh; 1541ea45fe4eSShmulik Ravid struct dcbmsg *dcb; 1542ea45fe4eSShmulik Ravid struct nlattr *data[DCB_FEATCFG_ATTR_MAX + 1], *nest; 1543ea45fe4eSShmulik Ravid u8 value; 15447f891cf1SShmulik Ravid int ret, i; 1545ea45fe4eSShmulik Ravid int getall = 0; 1546ea45fe4eSShmulik Ravid 15477f891cf1SShmulik Ravid if (!netdev->dcbnl_ops->getfeatcfg) 15487f891cf1SShmulik Ravid return -EOPNOTSUPP; 15497f891cf1SShmulik Ravid 15507f891cf1SShmulik Ravid if (!tb[DCB_ATTR_FEATCFG]) 15517f891cf1SShmulik Ravid return -EINVAL; 1552ea45fe4eSShmulik Ravid 1553ea45fe4eSShmulik Ravid ret = nla_parse_nested(data, DCB_FEATCFG_ATTR_MAX, tb[DCB_ATTR_FEATCFG], 1554ea45fe4eSShmulik Ravid dcbnl_featcfg_nest); 15557f891cf1SShmulik Ravid if (ret) 1556ea45fe4eSShmulik Ravid goto err_out; 1557ea45fe4eSShmulik Ravid 1558ea45fe4eSShmulik Ravid dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 1559ea45fe4eSShmulik Ravid if (!dcbnl_skb) { 15607f891cf1SShmulik Ravid ret = -ENOBUFS; 1561ea45fe4eSShmulik Ravid goto err_out; 1562ea45fe4eSShmulik Ravid } 1563ea45fe4eSShmulik Ravid 1564ea45fe4eSShmulik Ravid nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); 1565ea45fe4eSShmulik Ravid 1566ea45fe4eSShmulik Ravid dcb = NLMSG_DATA(nlh); 1567ea45fe4eSShmulik Ravid dcb->dcb_family = AF_UNSPEC; 1568ea45fe4eSShmulik Ravid dcb->cmd = DCB_CMD_GFEATCFG; 1569ea45fe4eSShmulik Ravid 1570ea45fe4eSShmulik Ravid nest = nla_nest_start(dcbnl_skb, DCB_ATTR_FEATCFG); 1571ea45fe4eSShmulik Ravid if (!nest) { 15727f891cf1SShmulik Ravid ret = -EMSGSIZE; 15737f891cf1SShmulik Ravid goto nla_put_failure; 1574ea45fe4eSShmulik Ravid } 1575ea45fe4eSShmulik Ravid 1576ea45fe4eSShmulik Ravid if (data[DCB_FEATCFG_ATTR_ALL]) 1577ea45fe4eSShmulik Ravid getall = 1; 1578ea45fe4eSShmulik Ravid 1579ea45fe4eSShmulik Ravid for (i = DCB_FEATCFG_ATTR_ALL+1; i <= DCB_FEATCFG_ATTR_MAX; i++) { 1580ea45fe4eSShmulik Ravid if (!getall && !data[i]) 1581ea45fe4eSShmulik Ravid continue; 1582ea45fe4eSShmulik Ravid 1583ea45fe4eSShmulik Ravid ret = netdev->dcbnl_ops->getfeatcfg(netdev, i, &value); 15847f891cf1SShmulik Ravid if (!ret) 1585ea45fe4eSShmulik Ravid ret = nla_put_u8(dcbnl_skb, i, value); 1586ea45fe4eSShmulik Ravid 1587ea45fe4eSShmulik Ravid if (ret) { 1588ea45fe4eSShmulik Ravid nla_nest_cancel(dcbnl_skb, nest); 15897f891cf1SShmulik Ravid goto nla_put_failure; 1590ea45fe4eSShmulik Ravid } 1591ea45fe4eSShmulik Ravid } 1592ea45fe4eSShmulik Ravid nla_nest_end(dcbnl_skb, nest); 1593ea45fe4eSShmulik Ravid 1594ea45fe4eSShmulik Ravid nlmsg_end(dcbnl_skb, nlh); 1595ea45fe4eSShmulik Ravid 15967f891cf1SShmulik Ravid return rtnl_unicast(dcbnl_skb, &init_net, pid); 15977f891cf1SShmulik Ravid nla_put_failure: 15987f891cf1SShmulik Ravid nlmsg_cancel(dcbnl_skb, nlh); 1599ea45fe4eSShmulik Ravid nlmsg_failure: 1600ea45fe4eSShmulik Ravid kfree_skb(dcbnl_skb); 1601ea45fe4eSShmulik Ravid err_out: 1602ea45fe4eSShmulik Ravid return ret; 1603ea45fe4eSShmulik Ravid } 1604ea45fe4eSShmulik Ravid 1605ea45fe4eSShmulik Ravid static int dcbnl_setfeatcfg(struct net_device *netdev, struct nlattr **tb, 1606ea45fe4eSShmulik Ravid u32 pid, u32 seq, u16 flags) 1607ea45fe4eSShmulik Ravid { 1608ea45fe4eSShmulik Ravid struct nlattr *data[DCB_FEATCFG_ATTR_MAX + 1]; 16097f891cf1SShmulik Ravid int ret, i; 1610ea45fe4eSShmulik Ravid u8 value; 1611ea45fe4eSShmulik Ravid 16127f891cf1SShmulik Ravid if (!netdev->dcbnl_ops->setfeatcfg) 16137f891cf1SShmulik Ravid return -ENOTSUPP; 16147f891cf1SShmulik Ravid 16157f891cf1SShmulik Ravid if (!tb[DCB_ATTR_FEATCFG]) 16167f891cf1SShmulik Ravid return -EINVAL; 1617ea45fe4eSShmulik Ravid 1618ea45fe4eSShmulik Ravid ret = nla_parse_nested(data, DCB_FEATCFG_ATTR_MAX, tb[DCB_ATTR_FEATCFG], 1619ea45fe4eSShmulik Ravid dcbnl_featcfg_nest); 1620ea45fe4eSShmulik Ravid 16217f891cf1SShmulik Ravid if (ret) 1622ea45fe4eSShmulik Ravid goto err; 1623ea45fe4eSShmulik Ravid 1624ea45fe4eSShmulik Ravid for (i = DCB_FEATCFG_ATTR_ALL+1; i <= DCB_FEATCFG_ATTR_MAX; i++) { 1625ea45fe4eSShmulik Ravid if (data[i] == NULL) 1626ea45fe4eSShmulik Ravid continue; 1627ea45fe4eSShmulik Ravid 1628ea45fe4eSShmulik Ravid value = nla_get_u8(data[i]); 1629ea45fe4eSShmulik Ravid 1630ea45fe4eSShmulik Ravid ret = netdev->dcbnl_ops->setfeatcfg(netdev, i, value); 1631ea45fe4eSShmulik Ravid 1632ea45fe4eSShmulik Ravid if (ret) 16337f891cf1SShmulik Ravid goto err; 1634ea45fe4eSShmulik Ravid } 1635ea45fe4eSShmulik Ravid err: 16367f891cf1SShmulik Ravid dcbnl_reply(ret, RTM_SETDCB, DCB_CMD_SFEATCFG, DCB_ATTR_FEATCFG, 16377f891cf1SShmulik Ravid pid, seq, flags); 16387f891cf1SShmulik Ravid 1639ea45fe4eSShmulik Ravid return ret; 1640ea45fe4eSShmulik Ravid } 1641ea45fe4eSShmulik Ravid 1642dc6ed1dfSShmulik Ravid /* Handle CEE DCBX GET commands. */ 1643dc6ed1dfSShmulik Ravid static int dcbnl_cee_get(struct net_device *netdev, struct nlattr **tb, 1644dc6ed1dfSShmulik Ravid u32 pid, u32 seq, u16 flags) 1645dc6ed1dfSShmulik Ravid { 1646dc6ed1dfSShmulik Ravid struct sk_buff *skb; 1647dc6ed1dfSShmulik Ravid struct nlmsghdr *nlh; 1648dc6ed1dfSShmulik Ravid struct dcbmsg *dcb; 1649dc6ed1dfSShmulik Ravid struct nlattr *cee; 1650dc6ed1dfSShmulik Ravid const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; 1651dc6ed1dfSShmulik Ravid int err; 1652dc6ed1dfSShmulik Ravid 1653dc6ed1dfSShmulik Ravid if (!ops) 1654dc6ed1dfSShmulik Ravid return -EOPNOTSUPP; 1655dc6ed1dfSShmulik Ravid 1656dc6ed1dfSShmulik Ravid skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 1657dc6ed1dfSShmulik Ravid if (!skb) 1658dc6ed1dfSShmulik Ravid return -ENOBUFS; 1659dc6ed1dfSShmulik Ravid 1660dc6ed1dfSShmulik Ravid nlh = NLMSG_NEW(skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); 1661dc6ed1dfSShmulik Ravid 1662dc6ed1dfSShmulik Ravid dcb = NLMSG_DATA(nlh); 1663dc6ed1dfSShmulik Ravid dcb->dcb_family = AF_UNSPEC; 1664dc6ed1dfSShmulik Ravid dcb->cmd = DCB_CMD_CEE_GET; 1665dc6ed1dfSShmulik Ravid 1666dc6ed1dfSShmulik Ravid NLA_PUT_STRING(skb, DCB_ATTR_IFNAME, netdev->name); 1667dc6ed1dfSShmulik Ravid 1668dc6ed1dfSShmulik Ravid cee = nla_nest_start(skb, DCB_ATTR_CEE); 1669dc6ed1dfSShmulik Ravid if (!cee) 1670dc6ed1dfSShmulik Ravid goto nla_put_failure; 1671dc6ed1dfSShmulik Ravid 1672dc6ed1dfSShmulik Ravid /* get peer info if available */ 1673dc6ed1dfSShmulik Ravid if (ops->cee_peer_getpg) { 1674dc6ed1dfSShmulik Ravid struct cee_pg pg; 1675dc6ed1dfSShmulik Ravid err = ops->cee_peer_getpg(netdev, &pg); 1676dc6ed1dfSShmulik Ravid if (!err) 1677dc6ed1dfSShmulik Ravid NLA_PUT(skb, DCB_ATTR_CEE_PEER_PG, sizeof(pg), &pg); 1678dc6ed1dfSShmulik Ravid } 1679dc6ed1dfSShmulik Ravid 1680dc6ed1dfSShmulik Ravid if (ops->cee_peer_getpfc) { 1681dc6ed1dfSShmulik Ravid struct cee_pfc pfc; 1682dc6ed1dfSShmulik Ravid err = ops->cee_peer_getpfc(netdev, &pfc); 1683dc6ed1dfSShmulik Ravid if (!err) 1684dc6ed1dfSShmulik Ravid NLA_PUT(skb, DCB_ATTR_CEE_PEER_PFC, sizeof(pfc), &pfc); 1685dc6ed1dfSShmulik Ravid } 1686dc6ed1dfSShmulik Ravid 1687dc6ed1dfSShmulik Ravid if (ops->peer_getappinfo && ops->peer_getapptable) { 1688dc6ed1dfSShmulik Ravid err = dcbnl_build_peer_app(netdev, skb, 1689dc6ed1dfSShmulik Ravid DCB_ATTR_CEE_PEER_APP_TABLE, 1690dc6ed1dfSShmulik Ravid DCB_ATTR_CEE_PEER_APP_INFO, 1691dc6ed1dfSShmulik Ravid DCB_ATTR_CEE_PEER_APP); 1692dc6ed1dfSShmulik Ravid if (err) 1693dc6ed1dfSShmulik Ravid goto nla_put_failure; 1694dc6ed1dfSShmulik Ravid } 1695dc6ed1dfSShmulik Ravid 1696dc6ed1dfSShmulik Ravid nla_nest_end(skb, cee); 1697dc6ed1dfSShmulik Ravid nlmsg_end(skb, nlh); 1698dc6ed1dfSShmulik Ravid 1699dc6ed1dfSShmulik Ravid return rtnl_unicast(skb, &init_net, pid); 1700dc6ed1dfSShmulik Ravid nla_put_failure: 1701dc6ed1dfSShmulik Ravid nlmsg_cancel(skb, nlh); 1702dc6ed1dfSShmulik Ravid nlmsg_failure: 1703dc6ed1dfSShmulik Ravid kfree_skb(skb); 1704dc6ed1dfSShmulik Ravid return -1; 1705dc6ed1dfSShmulik Ravid } 1706dc6ed1dfSShmulik Ravid 17072f90b865SAlexander Duyck static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) 17082f90b865SAlexander Duyck { 17092f90b865SAlexander Duyck struct net *net = sock_net(skb->sk); 17102f90b865SAlexander Duyck struct net_device *netdev; 17112f90b865SAlexander Duyck struct dcbmsg *dcb = (struct dcbmsg *)NLMSG_DATA(nlh); 17122f90b865SAlexander Duyck struct nlattr *tb[DCB_ATTR_MAX + 1]; 17132f90b865SAlexander Duyck u32 pid = skb ? NETLINK_CB(skb).pid : 0; 17142f90b865SAlexander Duyck int ret = -EINVAL; 17152f90b865SAlexander Duyck 171609ad9bc7SOctavian Purdila if (!net_eq(net, &init_net)) 17172f90b865SAlexander Duyck return -EINVAL; 17182f90b865SAlexander Duyck 17192f90b865SAlexander Duyck ret = nlmsg_parse(nlh, sizeof(*dcb), tb, DCB_ATTR_MAX, 17202f90b865SAlexander Duyck dcbnl_rtnl_policy); 17212f90b865SAlexander Duyck if (ret < 0) 17222f90b865SAlexander Duyck return ret; 17232f90b865SAlexander Duyck 17242f90b865SAlexander Duyck if (!tb[DCB_ATTR_IFNAME]) 17252f90b865SAlexander Duyck return -EINVAL; 17262f90b865SAlexander Duyck 17272f90b865SAlexander Duyck netdev = dev_get_by_name(&init_net, nla_data(tb[DCB_ATTR_IFNAME])); 17282f90b865SAlexander Duyck if (!netdev) 17292f90b865SAlexander Duyck return -EINVAL; 17302f90b865SAlexander Duyck 17312f90b865SAlexander Duyck if (!netdev->dcbnl_ops) 17322f90b865SAlexander Duyck goto errout; 17332f90b865SAlexander Duyck 17342f90b865SAlexander Duyck switch (dcb->cmd) { 17352f90b865SAlexander Duyck case DCB_CMD_GSTATE: 17362f90b865SAlexander Duyck ret = dcbnl_getstate(netdev, tb, pid, nlh->nlmsg_seq, 17372f90b865SAlexander Duyck nlh->nlmsg_flags); 17382f90b865SAlexander Duyck goto out; 17392f90b865SAlexander Duyck case DCB_CMD_PFC_GCFG: 17402f90b865SAlexander Duyck ret = dcbnl_getpfccfg(netdev, tb, pid, nlh->nlmsg_seq, 17412f90b865SAlexander Duyck nlh->nlmsg_flags); 17422f90b865SAlexander Duyck goto out; 17432f90b865SAlexander Duyck case DCB_CMD_GPERM_HWADDR: 17442f90b865SAlexander Duyck ret = dcbnl_getperm_hwaddr(netdev, tb, pid, nlh->nlmsg_seq, 17452f90b865SAlexander Duyck nlh->nlmsg_flags); 17462f90b865SAlexander Duyck goto out; 17472f90b865SAlexander Duyck case DCB_CMD_PGTX_GCFG: 17482f90b865SAlexander Duyck ret = dcbnl_pgtx_getcfg(netdev, tb, pid, nlh->nlmsg_seq, 17492f90b865SAlexander Duyck nlh->nlmsg_flags); 17502f90b865SAlexander Duyck goto out; 17512f90b865SAlexander Duyck case DCB_CMD_PGRX_GCFG: 17522f90b865SAlexander Duyck ret = dcbnl_pgrx_getcfg(netdev, tb, pid, nlh->nlmsg_seq, 17532f90b865SAlexander Duyck nlh->nlmsg_flags); 17542f90b865SAlexander Duyck goto out; 1755859ee3c4SAlexander Duyck case DCB_CMD_BCN_GCFG: 1756859ee3c4SAlexander Duyck ret = dcbnl_bcn_getcfg(netdev, tb, pid, nlh->nlmsg_seq, 1757859ee3c4SAlexander Duyck nlh->nlmsg_flags); 1758859ee3c4SAlexander Duyck goto out; 17592f90b865SAlexander Duyck case DCB_CMD_SSTATE: 17602f90b865SAlexander Duyck ret = dcbnl_setstate(netdev, tb, pid, nlh->nlmsg_seq, 17612f90b865SAlexander Duyck nlh->nlmsg_flags); 17622f90b865SAlexander Duyck goto out; 17632f90b865SAlexander Duyck case DCB_CMD_PFC_SCFG: 17642f90b865SAlexander Duyck ret = dcbnl_setpfccfg(netdev, tb, pid, nlh->nlmsg_seq, 17652f90b865SAlexander Duyck nlh->nlmsg_flags); 17662f90b865SAlexander Duyck goto out; 17672f90b865SAlexander Duyck 17682f90b865SAlexander Duyck case DCB_CMD_SET_ALL: 17692f90b865SAlexander Duyck ret = dcbnl_setall(netdev, tb, pid, nlh->nlmsg_seq, 17702f90b865SAlexander Duyck nlh->nlmsg_flags); 17712f90b865SAlexander Duyck goto out; 17722f90b865SAlexander Duyck case DCB_CMD_PGTX_SCFG: 17732f90b865SAlexander Duyck ret = dcbnl_pgtx_setcfg(netdev, tb, pid, nlh->nlmsg_seq, 17742f90b865SAlexander Duyck nlh->nlmsg_flags); 17752f90b865SAlexander Duyck goto out; 17762f90b865SAlexander Duyck case DCB_CMD_PGRX_SCFG: 17772f90b865SAlexander Duyck ret = dcbnl_pgrx_setcfg(netdev, tb, pid, nlh->nlmsg_seq, 17782f90b865SAlexander Duyck nlh->nlmsg_flags); 17792f90b865SAlexander Duyck goto out; 178046132188SAlexander Duyck case DCB_CMD_GCAP: 178146132188SAlexander Duyck ret = dcbnl_getcap(netdev, tb, pid, nlh->nlmsg_seq, 178246132188SAlexander Duyck nlh->nlmsg_flags); 178346132188SAlexander Duyck goto out; 178433dbabc4SAlexander Duyck case DCB_CMD_GNUMTCS: 178533dbabc4SAlexander Duyck ret = dcbnl_getnumtcs(netdev, tb, pid, nlh->nlmsg_seq, 178633dbabc4SAlexander Duyck nlh->nlmsg_flags); 178733dbabc4SAlexander Duyck goto out; 178833dbabc4SAlexander Duyck case DCB_CMD_SNUMTCS: 178933dbabc4SAlexander Duyck ret = dcbnl_setnumtcs(netdev, tb, pid, nlh->nlmsg_seq, 179033dbabc4SAlexander Duyck nlh->nlmsg_flags); 179133dbabc4SAlexander Duyck goto out; 17920eb3aa9bSAlexander Duyck case DCB_CMD_PFC_GSTATE: 17930eb3aa9bSAlexander Duyck ret = dcbnl_getpfcstate(netdev, tb, pid, nlh->nlmsg_seq, 17940eb3aa9bSAlexander Duyck nlh->nlmsg_flags); 17950eb3aa9bSAlexander Duyck goto out; 17960eb3aa9bSAlexander Duyck case DCB_CMD_PFC_SSTATE: 17970eb3aa9bSAlexander Duyck ret = dcbnl_setpfcstate(netdev, tb, pid, nlh->nlmsg_seq, 17980eb3aa9bSAlexander Duyck nlh->nlmsg_flags); 17990eb3aa9bSAlexander Duyck goto out; 1800859ee3c4SAlexander Duyck case DCB_CMD_BCN_SCFG: 1801859ee3c4SAlexander Duyck ret = dcbnl_bcn_setcfg(netdev, tb, pid, nlh->nlmsg_seq, 1802859ee3c4SAlexander Duyck nlh->nlmsg_flags); 1803859ee3c4SAlexander Duyck goto out; 180457949686SYi Zou case DCB_CMD_GAPP: 180557949686SYi Zou ret = dcbnl_getapp(netdev, tb, pid, nlh->nlmsg_seq, 180657949686SYi Zou nlh->nlmsg_flags); 180757949686SYi Zou goto out; 180857949686SYi Zou case DCB_CMD_SAPP: 180957949686SYi Zou ret = dcbnl_setapp(netdev, tb, pid, nlh->nlmsg_seq, 181057949686SYi Zou nlh->nlmsg_flags); 181157949686SYi Zou goto out; 18123e29027aSJohn Fastabend case DCB_CMD_IEEE_SET: 18133e29027aSJohn Fastabend ret = dcbnl_ieee_set(netdev, tb, pid, nlh->nlmsg_seq, 18143e29027aSJohn Fastabend nlh->nlmsg_flags); 18153e29027aSJohn Fastabend goto out; 18163e29027aSJohn Fastabend case DCB_CMD_IEEE_GET: 18173e29027aSJohn Fastabend ret = dcbnl_ieee_get(netdev, tb, pid, nlh->nlmsg_seq, 18183e29027aSJohn Fastabend nlh->nlmsg_flags); 18193e29027aSJohn Fastabend goto out; 1820f9ae7e4bSJohn Fastabend case DCB_CMD_IEEE_DEL: 1821f9ae7e4bSJohn Fastabend ret = dcbnl_ieee_del(netdev, tb, pid, nlh->nlmsg_seq, 1822f9ae7e4bSJohn Fastabend nlh->nlmsg_flags); 1823f9ae7e4bSJohn Fastabend goto out; 18246241b625SShmulik Ravid case DCB_CMD_GDCBX: 18256241b625SShmulik Ravid ret = dcbnl_getdcbx(netdev, tb, pid, nlh->nlmsg_seq, 18266241b625SShmulik Ravid nlh->nlmsg_flags); 18276241b625SShmulik Ravid goto out; 18286241b625SShmulik Ravid case DCB_CMD_SDCBX: 18296241b625SShmulik Ravid ret = dcbnl_setdcbx(netdev, tb, pid, nlh->nlmsg_seq, 18306241b625SShmulik Ravid nlh->nlmsg_flags); 18316241b625SShmulik Ravid goto out; 1832ea45fe4eSShmulik Ravid case DCB_CMD_GFEATCFG: 1833ea45fe4eSShmulik Ravid ret = dcbnl_getfeatcfg(netdev, tb, pid, nlh->nlmsg_seq, 1834ea45fe4eSShmulik Ravid nlh->nlmsg_flags); 1835ea45fe4eSShmulik Ravid goto out; 1836ea45fe4eSShmulik Ravid case DCB_CMD_SFEATCFG: 1837ea45fe4eSShmulik Ravid ret = dcbnl_setfeatcfg(netdev, tb, pid, nlh->nlmsg_seq, 1838ea45fe4eSShmulik Ravid nlh->nlmsg_flags); 1839ea45fe4eSShmulik Ravid goto out; 1840dc6ed1dfSShmulik Ravid case DCB_CMD_CEE_GET: 1841dc6ed1dfSShmulik Ravid ret = dcbnl_cee_get(netdev, tb, pid, nlh->nlmsg_seq, 1842dc6ed1dfSShmulik Ravid nlh->nlmsg_flags); 1843dc6ed1dfSShmulik Ravid goto out; 18442f90b865SAlexander Duyck default: 18452f90b865SAlexander Duyck goto errout; 18462f90b865SAlexander Duyck } 18472f90b865SAlexander Duyck errout: 18482f90b865SAlexander Duyck ret = -EINVAL; 18492f90b865SAlexander Duyck out: 18502f90b865SAlexander Duyck dev_put(netdev); 18512f90b865SAlexander Duyck return ret; 18522f90b865SAlexander Duyck } 18532f90b865SAlexander Duyck 18549ab933abSJohn Fastabend /** 18559ab933abSJohn Fastabend * dcb_getapp - retrieve the DCBX application user priority 18569ab933abSJohn Fastabend * 18579ab933abSJohn Fastabend * On success returns a non-zero 802.1p user priority bitmap 18589ab933abSJohn Fastabend * otherwise returns 0 as the invalid user priority bitmap to 18599ab933abSJohn Fastabend * indicate an error. 18609ab933abSJohn Fastabend */ 18619ab933abSJohn Fastabend u8 dcb_getapp(struct net_device *dev, struct dcb_app *app) 18629ab933abSJohn Fastabend { 18639ab933abSJohn Fastabend struct dcb_app_type *itr; 18649ab933abSJohn Fastabend u8 prio = 0; 18659ab933abSJohn Fastabend 18669ab933abSJohn Fastabend spin_lock(&dcb_lock); 18679ab933abSJohn Fastabend list_for_each_entry(itr, &dcb_app_list, list) { 18689ab933abSJohn Fastabend if (itr->app.selector == app->selector && 18699ab933abSJohn Fastabend itr->app.protocol == app->protocol && 18709ab933abSJohn Fastabend (strncmp(itr->name, dev->name, IFNAMSIZ) == 0)) { 18719ab933abSJohn Fastabend prio = itr->app.priority; 18729ab933abSJohn Fastabend break; 18739ab933abSJohn Fastabend } 18749ab933abSJohn Fastabend } 18759ab933abSJohn Fastabend spin_unlock(&dcb_lock); 18769ab933abSJohn Fastabend 18779ab933abSJohn Fastabend return prio; 18789ab933abSJohn Fastabend } 18799ab933abSJohn Fastabend EXPORT_SYMBOL(dcb_getapp); 18809ab933abSJohn Fastabend 18819ab933abSJohn Fastabend /** 1882b6db2174SJohn Fastabend * dcb_setapp - add CEE dcb application data to app list 18839ab933abSJohn Fastabend * 1884b6db2174SJohn Fastabend * Priority 0 is an invalid priority in CEE spec. This routine 1885b6db2174SJohn Fastabend * removes applications from the app list if the priority is 1886b6db2174SJohn Fastabend * set to zero. 18879ab933abSJohn Fastabend */ 18889ab933abSJohn Fastabend u8 dcb_setapp(struct net_device *dev, struct dcb_app *new) 18899ab933abSJohn Fastabend { 18909ab933abSJohn Fastabend struct dcb_app_type *itr; 18917ec79270SJohn Fastabend struct dcb_app_type event; 18927ec79270SJohn Fastabend 18937ec79270SJohn Fastabend memcpy(&event.name, dev->name, sizeof(event.name)); 18947ec79270SJohn Fastabend memcpy(&event.app, new, sizeof(event.app)); 18959ab933abSJohn Fastabend 18969ab933abSJohn Fastabend spin_lock(&dcb_lock); 18979ab933abSJohn Fastabend /* Search for existing match and replace */ 18989ab933abSJohn Fastabend list_for_each_entry(itr, &dcb_app_list, list) { 18999ab933abSJohn Fastabend if (itr->app.selector == new->selector && 19009ab933abSJohn Fastabend itr->app.protocol == new->protocol && 19019ab933abSJohn Fastabend (strncmp(itr->name, dev->name, IFNAMSIZ) == 0)) { 19029ab933abSJohn Fastabend if (new->priority) 19039ab933abSJohn Fastabend itr->app.priority = new->priority; 19049ab933abSJohn Fastabend else { 19059ab933abSJohn Fastabend list_del(&itr->list); 19069ab933abSJohn Fastabend kfree(itr); 19079ab933abSJohn Fastabend } 19089ab933abSJohn Fastabend goto out; 19099ab933abSJohn Fastabend } 19109ab933abSJohn Fastabend } 19119ab933abSJohn Fastabend /* App type does not exist add new application type */ 19129ab933abSJohn Fastabend if (new->priority) { 19139ab933abSJohn Fastabend struct dcb_app_type *entry; 19149ab933abSJohn Fastabend entry = kmalloc(sizeof(struct dcb_app_type), GFP_ATOMIC); 19159ab933abSJohn Fastabend if (!entry) { 19169ab933abSJohn Fastabend spin_unlock(&dcb_lock); 19179ab933abSJohn Fastabend return -ENOMEM; 19189ab933abSJohn Fastabend } 19199ab933abSJohn Fastabend 19209ab933abSJohn Fastabend memcpy(&entry->app, new, sizeof(*new)); 19219ab933abSJohn Fastabend strncpy(entry->name, dev->name, IFNAMSIZ); 19229ab933abSJohn Fastabend list_add(&entry->list, &dcb_app_list); 19239ab933abSJohn Fastabend } 19249ab933abSJohn Fastabend out: 19259ab933abSJohn Fastabend spin_unlock(&dcb_lock); 19267ec79270SJohn Fastabend call_dcbevent_notifiers(DCB_APP_EVENT, &event); 19279ab933abSJohn Fastabend return 0; 19289ab933abSJohn Fastabend } 19299ab933abSJohn Fastabend EXPORT_SYMBOL(dcb_setapp); 19309ab933abSJohn Fastabend 1931b6db2174SJohn Fastabend /** 1932a364c8cfSJohn Fastabend * dcb_ieee_getapp_mask - retrieve the IEEE DCB application priority 1933a364c8cfSJohn Fastabend * 1934a364c8cfSJohn Fastabend * Helper routine which on success returns a non-zero 802.1Qaz user 1935a364c8cfSJohn Fastabend * priority bitmap otherwise returns 0 to indicate the dcb_app was 1936a364c8cfSJohn Fastabend * not found in APP list. 1937a364c8cfSJohn Fastabend */ 1938a364c8cfSJohn Fastabend u8 dcb_ieee_getapp_mask(struct net_device *dev, struct dcb_app *app) 1939a364c8cfSJohn Fastabend { 1940a364c8cfSJohn Fastabend struct dcb_app_type *itr; 1941a364c8cfSJohn Fastabend u8 prio = 0; 1942a364c8cfSJohn Fastabend 1943a364c8cfSJohn Fastabend spin_lock(&dcb_lock); 1944a364c8cfSJohn Fastabend list_for_each_entry(itr, &dcb_app_list, list) { 1945a364c8cfSJohn Fastabend if (itr->app.selector == app->selector && 1946a364c8cfSJohn Fastabend itr->app.protocol == app->protocol && 1947a364c8cfSJohn Fastabend (strncmp(itr->name, dev->name, IFNAMSIZ) == 0)) { 1948a364c8cfSJohn Fastabend prio |= 1 << itr->app.priority; 1949a364c8cfSJohn Fastabend } 1950a364c8cfSJohn Fastabend } 1951a364c8cfSJohn Fastabend spin_unlock(&dcb_lock); 1952a364c8cfSJohn Fastabend 1953a364c8cfSJohn Fastabend return prio; 1954a364c8cfSJohn Fastabend } 1955a364c8cfSJohn Fastabend EXPORT_SYMBOL(dcb_ieee_getapp_mask); 1956a364c8cfSJohn Fastabend 1957a364c8cfSJohn Fastabend /** 1958b6db2174SJohn Fastabend * dcb_ieee_setapp - add IEEE dcb application data to app list 1959b6db2174SJohn Fastabend * 1960b6db2174SJohn Fastabend * This adds Application data to the list. Multiple application 1961b6db2174SJohn Fastabend * entries may exists for the same selector and protocol as long 1962b6db2174SJohn Fastabend * as the priorities are different. 1963b6db2174SJohn Fastabend */ 1964b6db2174SJohn Fastabend int dcb_ieee_setapp(struct net_device *dev, struct dcb_app *new) 1965b6db2174SJohn Fastabend { 1966b6db2174SJohn Fastabend struct dcb_app_type *itr, *entry; 1967b6db2174SJohn Fastabend struct dcb_app_type event; 1968b6db2174SJohn Fastabend int err = 0; 1969b6db2174SJohn Fastabend 1970b6db2174SJohn Fastabend memcpy(&event.name, dev->name, sizeof(event.name)); 1971b6db2174SJohn Fastabend memcpy(&event.app, new, sizeof(event.app)); 1972b6db2174SJohn Fastabend 1973b6db2174SJohn Fastabend spin_lock(&dcb_lock); 1974b6db2174SJohn Fastabend /* Search for existing match and abort if found */ 1975b6db2174SJohn Fastabend list_for_each_entry(itr, &dcb_app_list, list) { 1976b6db2174SJohn Fastabend if (itr->app.selector == new->selector && 1977b6db2174SJohn Fastabend itr->app.protocol == new->protocol && 1978b6db2174SJohn Fastabend itr->app.priority == new->priority && 1979b6db2174SJohn Fastabend (strncmp(itr->name, dev->name, IFNAMSIZ) == 0)) { 1980b6db2174SJohn Fastabend err = -EEXIST; 1981b6db2174SJohn Fastabend goto out; 1982b6db2174SJohn Fastabend } 1983b6db2174SJohn Fastabend } 1984b6db2174SJohn Fastabend 1985b6db2174SJohn Fastabend /* App entry does not exist add new entry */ 1986b6db2174SJohn Fastabend entry = kmalloc(sizeof(struct dcb_app_type), GFP_ATOMIC); 1987b6db2174SJohn Fastabend if (!entry) { 1988b6db2174SJohn Fastabend err = -ENOMEM; 1989b6db2174SJohn Fastabend goto out; 1990b6db2174SJohn Fastabend } 1991b6db2174SJohn Fastabend 1992b6db2174SJohn Fastabend memcpy(&entry->app, new, sizeof(*new)); 1993b6db2174SJohn Fastabend strncpy(entry->name, dev->name, IFNAMSIZ); 1994b6db2174SJohn Fastabend list_add(&entry->list, &dcb_app_list); 1995b6db2174SJohn Fastabend out: 1996b6db2174SJohn Fastabend spin_unlock(&dcb_lock); 1997b6db2174SJohn Fastabend if (!err) 1998b6db2174SJohn Fastabend call_dcbevent_notifiers(DCB_APP_EVENT, &event); 1999b6db2174SJohn Fastabend return err; 2000b6db2174SJohn Fastabend } 2001b6db2174SJohn Fastabend EXPORT_SYMBOL(dcb_ieee_setapp); 2002b6db2174SJohn Fastabend 2003f9ae7e4bSJohn Fastabend /** 2004f9ae7e4bSJohn Fastabend * dcb_ieee_delapp - delete IEEE dcb application data from list 2005f9ae7e4bSJohn Fastabend * 2006f9ae7e4bSJohn Fastabend * This removes a matching APP data from the APP list 2007f9ae7e4bSJohn Fastabend */ 2008f9ae7e4bSJohn Fastabend int dcb_ieee_delapp(struct net_device *dev, struct dcb_app *del) 2009f9ae7e4bSJohn Fastabend { 2010f9ae7e4bSJohn Fastabend struct dcb_app_type *itr; 2011f9ae7e4bSJohn Fastabend struct dcb_app_type event; 2012f9ae7e4bSJohn Fastabend int err = -ENOENT; 2013f9ae7e4bSJohn Fastabend 2014f9ae7e4bSJohn Fastabend memcpy(&event.name, dev->name, sizeof(event.name)); 2015f9ae7e4bSJohn Fastabend memcpy(&event.app, del, sizeof(event.app)); 2016f9ae7e4bSJohn Fastabend 2017f9ae7e4bSJohn Fastabend spin_lock(&dcb_lock); 2018f9ae7e4bSJohn Fastabend /* Search for existing match and remove it. */ 2019f9ae7e4bSJohn Fastabend list_for_each_entry(itr, &dcb_app_list, list) { 2020f9ae7e4bSJohn Fastabend if (itr->app.selector == del->selector && 2021f9ae7e4bSJohn Fastabend itr->app.protocol == del->protocol && 2022f9ae7e4bSJohn Fastabend itr->app.priority == del->priority && 2023f9ae7e4bSJohn Fastabend (strncmp(itr->name, dev->name, IFNAMSIZ) == 0)) { 2024f9ae7e4bSJohn Fastabend list_del(&itr->list); 2025f9ae7e4bSJohn Fastabend kfree(itr); 2026f9ae7e4bSJohn Fastabend err = 0; 2027f9ae7e4bSJohn Fastabend goto out; 2028f9ae7e4bSJohn Fastabend } 2029f9ae7e4bSJohn Fastabend } 2030f9ae7e4bSJohn Fastabend 2031f9ae7e4bSJohn Fastabend out: 2032f9ae7e4bSJohn Fastabend spin_unlock(&dcb_lock); 2033f9ae7e4bSJohn Fastabend if (!err) 2034f9ae7e4bSJohn Fastabend call_dcbevent_notifiers(DCB_APP_EVENT, &event); 2035f9ae7e4bSJohn Fastabend return err; 2036f9ae7e4bSJohn Fastabend } 2037f9ae7e4bSJohn Fastabend EXPORT_SYMBOL(dcb_ieee_delapp); 2038f9ae7e4bSJohn Fastabend 20397c14c3f1SShmulik Ravid static void dcb_flushapp(void) 20409ab933abSJohn Fastabend { 20419ab933abSJohn Fastabend struct dcb_app_type *app; 20422a8fe003SDan Carpenter struct dcb_app_type *tmp; 20439ab933abSJohn Fastabend 20449ab933abSJohn Fastabend spin_lock(&dcb_lock); 20452a8fe003SDan Carpenter list_for_each_entry_safe(app, tmp, &dcb_app_list, list) { 20469ab933abSJohn Fastabend list_del(&app->list); 20479ab933abSJohn Fastabend kfree(app); 20489ab933abSJohn Fastabend } 20499ab933abSJohn Fastabend spin_unlock(&dcb_lock); 20509ab933abSJohn Fastabend } 20519ab933abSJohn Fastabend 20522f90b865SAlexander Duyck static int __init dcbnl_init(void) 20532f90b865SAlexander Duyck { 20549ab933abSJohn Fastabend INIT_LIST_HEAD(&dcb_app_list); 20559ab933abSJohn Fastabend 2056c7ac8679SGreg Rose rtnl_register(PF_UNSPEC, RTM_GETDCB, dcb_doit, NULL, NULL); 2057c7ac8679SGreg Rose rtnl_register(PF_UNSPEC, RTM_SETDCB, dcb_doit, NULL, NULL); 20582f90b865SAlexander Duyck 20592f90b865SAlexander Duyck return 0; 20602f90b865SAlexander Duyck } 20612f90b865SAlexander Duyck module_init(dcbnl_init); 20622f90b865SAlexander Duyck 20632f90b865SAlexander Duyck static void __exit dcbnl_exit(void) 20642f90b865SAlexander Duyck { 20652f90b865SAlexander Duyck rtnl_unregister(PF_UNSPEC, RTM_GETDCB); 20662f90b865SAlexander Duyck rtnl_unregister(PF_UNSPEC, RTM_SETDCB); 20679ab933abSJohn Fastabend dcb_flushapp(); 20682f90b865SAlexander Duyck } 20692f90b865SAlexander Duyck module_exit(dcbnl_exit); 2070