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