~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/dcb/dcbnl.c

Version: ~ [ linux-5.1-rc5 ] ~ [ linux-5.0.7 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.34 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.111 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.168 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.178 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.138 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.65 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.39.4 ] ~ [ linux-2.6.38.8 ] ~ [ linux-2.6.37.6 ] ~ [ linux-2.6.36.4 ] ~ [ linux-2.6.35.14 ] ~ [ linux-2.6.34.15 ] ~ [ linux-2.6.33.20 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * Copyright (c) 2008-2011, Intel Corporation.
  3  *
  4  * This program is free software; you can redistribute it and/or modify it
  5  * under the terms and conditions of the GNU General Public License,
  6  * version 2, as published by the Free Software Foundation.
  7  *
  8  * This program is distributed in the hope it will be useful, but WITHOUT
  9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 10  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 11  * more details.
 12  *
 13  * You should have received a copy of the GNU General Public License along with
 14  * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 15  * Place - Suite 330, Boston, MA 02111-1307 USA.
 16  *
 17  * Author: Lucy Liu <lucy.liu@intel.com>
 18  */
 19 
 20 #include <linux/netdevice.h>
 21 #include <linux/netlink.h>
 22 #include <linux/slab.h>
 23 #include <net/netlink.h>
 24 #include <net/rtnetlink.h>
 25 #include <linux/dcbnl.h>
 26 #include <net/dcbevent.h>
 27 #include <linux/rtnetlink.h>
 28 #include <net/sock.h>
 29 
 30 /**
 31  * Data Center Bridging (DCB) is a collection of Ethernet enhancements
 32  * intended to allow network traffic with differing requirements
 33  * (highly reliable, no drops vs. best effort vs. low latency) to operate
 34  * and co-exist on Ethernet.  Current DCB features are:
 35  *
 36  * Enhanced Transmission Selection (aka Priority Grouping [PG]) - provides a
 37  *   framework for assigning bandwidth guarantees to traffic classes.
 38  *
 39  * Priority-based Flow Control (PFC) - provides a flow control mechanism which
 40  *   can work independently for each 802.1p priority.
 41  *
 42  * Congestion Notification - provides a mechanism for end-to-end congestion
 43  *   control for protocols which do not have built-in congestion management.
 44  *
 45  * More information about the emerging standards for these Ethernet features
 46  * can be found at: http://www.ieee802.org/1/pages/dcbridges.html
 47  *
 48  * This file implements an rtnetlink interface to allow configuration of DCB
 49  * features for capable devices.
 50  */
 51 
 52 MODULE_AUTHOR("Lucy Liu, <lucy.liu@intel.com>");
 53 MODULE_DESCRIPTION("Data Center Bridging netlink interface");
 54 MODULE_LICENSE("GPL");
 55 
 56 /**************** DCB attribute policies *************************************/
 57 
 58 /* DCB netlink attributes policy */
 59 static const struct nla_policy dcbnl_rtnl_policy[DCB_ATTR_MAX + 1] = {
 60         [DCB_ATTR_IFNAME]      = {.type = NLA_NUL_STRING, .len = IFNAMSIZ - 1},
 61         [DCB_ATTR_STATE]       = {.type = NLA_U8},
 62         [DCB_ATTR_PFC_CFG]     = {.type = NLA_NESTED},
 63         [DCB_ATTR_PG_CFG]      = {.type = NLA_NESTED},
 64         [DCB_ATTR_SET_ALL]     = {.type = NLA_U8},
 65         [DCB_ATTR_PERM_HWADDR] = {.type = NLA_FLAG},
 66         [DCB_ATTR_CAP]         = {.type = NLA_NESTED},
 67         [DCB_ATTR_PFC_STATE]   = {.type = NLA_U8},
 68         [DCB_ATTR_BCN]         = {.type = NLA_NESTED},
 69         [DCB_ATTR_APP]         = {.type = NLA_NESTED},
 70         [DCB_ATTR_IEEE]        = {.type = NLA_NESTED},
 71         [DCB_ATTR_DCBX]        = {.type = NLA_U8},
 72         [DCB_ATTR_FEATCFG]     = {.type = NLA_NESTED},
 73 };
 74 
 75 /* DCB priority flow control to User Priority nested attributes */
 76 static const struct nla_policy dcbnl_pfc_up_nest[DCB_PFC_UP_ATTR_MAX + 1] = {
 77         [DCB_PFC_UP_ATTR_0]   = {.type = NLA_U8},
 78         [DCB_PFC_UP_ATTR_1]   = {.type = NLA_U8},
 79         [DCB_PFC_UP_ATTR_2]   = {.type = NLA_U8},
 80         [DCB_PFC_UP_ATTR_3]   = {.type = NLA_U8},
 81         [DCB_PFC_UP_ATTR_4]   = {.type = NLA_U8},
 82         [DCB_PFC_UP_ATTR_5]   = {.type = NLA_U8},
 83         [DCB_PFC_UP_ATTR_6]   = {.type = NLA_U8},
 84         [DCB_PFC_UP_ATTR_7]   = {.type = NLA_U8},
 85         [DCB_PFC_UP_ATTR_ALL] = {.type = NLA_FLAG},
 86 };
 87 
 88 /* DCB priority grouping nested attributes */
 89 static const struct nla_policy dcbnl_pg_nest[DCB_PG_ATTR_MAX + 1] = {
 90         [DCB_PG_ATTR_TC_0]      = {.type = NLA_NESTED},
 91         [DCB_PG_ATTR_TC_1]      = {.type = NLA_NESTED},
 92         [DCB_PG_ATTR_TC_2]      = {.type = NLA_NESTED},
 93         [DCB_PG_ATTR_TC_3]      = {.type = NLA_NESTED},
 94         [DCB_PG_ATTR_TC_4]      = {.type = NLA_NESTED},
 95         [DCB_PG_ATTR_TC_5]      = {.type = NLA_NESTED},
 96         [DCB_PG_ATTR_TC_6]      = {.type = NLA_NESTED},
 97         [DCB_PG_ATTR_TC_7]      = {.type = NLA_NESTED},
 98         [DCB_PG_ATTR_TC_ALL]    = {.type = NLA_NESTED},
 99         [DCB_PG_ATTR_BW_ID_0]   = {.type = NLA_U8},
100         [DCB_PG_ATTR_BW_ID_1]   = {.type = NLA_U8},
101         [DCB_PG_ATTR_BW_ID_2]   = {.type = NLA_U8},
102         [DCB_PG_ATTR_BW_ID_3]   = {.type = NLA_U8},
103         [DCB_PG_ATTR_BW_ID_4]   = {.type = NLA_U8},
104         [DCB_PG_ATTR_BW_ID_5]   = {.type = NLA_U8},
105         [DCB_PG_ATTR_BW_ID_6]   = {.type = NLA_U8},
106         [DCB_PG_ATTR_BW_ID_7]   = {.type = NLA_U8},
107         [DCB_PG_ATTR_BW_ID_ALL] = {.type = NLA_FLAG},
108 };
109 
110 /* DCB traffic class nested attributes. */
111 static const struct nla_policy dcbnl_tc_param_nest[DCB_TC_ATTR_PARAM_MAX + 1] = {
112         [DCB_TC_ATTR_PARAM_PGID]            = {.type = NLA_U8},
113         [DCB_TC_ATTR_PARAM_UP_MAPPING]      = {.type = NLA_U8},
114         [DCB_TC_ATTR_PARAM_STRICT_PRIO]     = {.type = NLA_U8},
115         [DCB_TC_ATTR_PARAM_BW_PCT]          = {.type = NLA_U8},
116         [DCB_TC_ATTR_PARAM_ALL]             = {.type = NLA_FLAG},
117 };
118 
119 /* DCB capabilities nested attributes. */
120 static const struct nla_policy dcbnl_cap_nest[DCB_CAP_ATTR_MAX + 1] = {
121         [DCB_CAP_ATTR_ALL]     = {.type = NLA_FLAG},
122         [DCB_CAP_ATTR_PG]      = {.type = NLA_U8},
123         [DCB_CAP_ATTR_PFC]     = {.type = NLA_U8},
124         [DCB_CAP_ATTR_UP2TC]   = {.type = NLA_U8},
125         [DCB_CAP_ATTR_PG_TCS]  = {.type = NLA_U8},
126         [DCB_CAP_ATTR_PFC_TCS] = {.type = NLA_U8},
127         [DCB_CAP_ATTR_GSP]     = {.type = NLA_U8},
128         [DCB_CAP_ATTR_BCN]     = {.type = NLA_U8},
129         [DCB_CAP_ATTR_DCBX]    = {.type = NLA_U8},
130 };
131 
132 /* DCB capabilities nested attributes. */
133 static const struct nla_policy dcbnl_numtcs_nest[DCB_NUMTCS_ATTR_MAX + 1] = {
134         [DCB_NUMTCS_ATTR_ALL]     = {.type = NLA_FLAG},
135         [DCB_NUMTCS_ATTR_PG]      = {.type = NLA_U8},
136         [DCB_NUMTCS_ATTR_PFC]     = {.type = NLA_U8},
137 };
138 
139 /* DCB BCN nested attributes. */
140 static const struct nla_policy dcbnl_bcn_nest[DCB_BCN_ATTR_MAX + 1] = {
141         [DCB_BCN_ATTR_RP_0]         = {.type = NLA_U8},
142         [DCB_BCN_ATTR_RP_1]         = {.type = NLA_U8},
143         [DCB_BCN_ATTR_RP_2]         = {.type = NLA_U8},
144         [DCB_BCN_ATTR_RP_3]         = {.type = NLA_U8},
145         [DCB_BCN_ATTR_RP_4]         = {.type = NLA_U8},
146         [DCB_BCN_ATTR_RP_5]         = {.type = NLA_U8},
147         [DCB_BCN_ATTR_RP_6]         = {.type = NLA_U8},
148         [DCB_BCN_ATTR_RP_7]         = {.type = NLA_U8},
149         [DCB_BCN_ATTR_RP_ALL]       = {.type = NLA_FLAG},
150         [DCB_BCN_ATTR_BCNA_0]       = {.type = NLA_U32},
151         [DCB_BCN_ATTR_BCNA_1]       = {.type = NLA_U32},
152         [DCB_BCN_ATTR_ALPHA]        = {.type = NLA_U32},
153         [DCB_BCN_ATTR_BETA]         = {.type = NLA_U32},
154         [DCB_BCN_ATTR_GD]           = {.type = NLA_U32},
155         [DCB_BCN_ATTR_GI]           = {.type = NLA_U32},
156         [DCB_BCN_ATTR_TMAX]         = {.type = NLA_U32},
157         [DCB_BCN_ATTR_TD]           = {.type = NLA_U32},
158         [DCB_BCN_ATTR_RMIN]         = {.type = NLA_U32},
159         [DCB_BCN_ATTR_W]            = {.type = NLA_U32},
160         [DCB_BCN_ATTR_RD]           = {.type = NLA_U32},
161         [DCB_BCN_ATTR_RU]           = {.type = NLA_U32},
162         [DCB_BCN_ATTR_WRTT]         = {.type = NLA_U32},
163         [DCB_BCN_ATTR_RI]           = {.type = NLA_U32},
164         [DCB_BCN_ATTR_C]            = {.type = NLA_U32},
165         [DCB_BCN_ATTR_ALL]          = {.type = NLA_FLAG},
166 };
167 
168 /* DCB APP nested attributes. */
169 static const struct nla_policy dcbnl_app_nest[DCB_APP_ATTR_MAX + 1] = {
170         [DCB_APP_ATTR_IDTYPE]       = {.type = NLA_U8},
171         [DCB_APP_ATTR_ID]           = {.type = NLA_U16},
172         [DCB_APP_ATTR_PRIORITY]     = {.type = NLA_U8},
173 };
174 
175 /* IEEE 802.1Qaz nested attributes. */
176 static const struct nla_policy dcbnl_ieee_policy[DCB_ATTR_IEEE_MAX + 1] = {
177         [DCB_ATTR_IEEE_ETS]         = {.len = sizeof(struct ieee_ets)},
178         [DCB_ATTR_IEEE_PFC]         = {.len = sizeof(struct ieee_pfc)},
179         [DCB_ATTR_IEEE_APP_TABLE]   = {.type = NLA_NESTED},
180 };
181 
182 static const struct nla_policy dcbnl_ieee_app[DCB_ATTR_IEEE_APP_MAX + 1] = {
183         [DCB_ATTR_IEEE_APP]         = {.len = sizeof(struct dcb_app)},
184 };
185 
186 /* DCB number of traffic classes nested attributes. */
187 static const struct nla_policy dcbnl_featcfg_nest[DCB_FEATCFG_ATTR_MAX + 1] = {
188         [DCB_FEATCFG_ATTR_ALL]      = {.type = NLA_FLAG},
189         [DCB_FEATCFG_ATTR_PG]       = {.type = NLA_U8},
190         [DCB_FEATCFG_ATTR_PFC]      = {.type = NLA_U8},
191         [DCB_FEATCFG_ATTR_APP]      = {.type = NLA_U8},
192 };
193 
194 static LIST_HEAD(dcb_app_list);
195 static DEFINE_SPINLOCK(dcb_lock);
196 
197 /* standard netlink reply call */
198 static int dcbnl_reply(u8 value, u8 event, u8 cmd, u8 attr, u32 pid,
199                        u32 seq, u16 flags)
200 {
201         struct sk_buff *dcbnl_skb;
202         struct dcbmsg *dcb;
203         struct nlmsghdr *nlh;
204         int ret = -EINVAL;
205 
206         dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
207         if (!dcbnl_skb)
208                 return ret;
209 
210         nlh = NLMSG_NEW(dcbnl_skb, pid, seq, event, sizeof(*dcb), flags);
211 
212         dcb = NLMSG_DATA(nlh);
213         dcb->dcb_family = AF_UNSPEC;
214         dcb->cmd = cmd;
215         dcb->dcb_pad = 0;
216 
217         ret = nla_put_u8(dcbnl_skb, attr, value);
218         if (ret)
219                 goto err;
220 
221         /* end the message, assign the nlmsg_len. */
222         nlmsg_end(dcbnl_skb, nlh);
223         ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
224         if (ret)
225                 return -EINVAL;
226 
227         return 0;
228 nlmsg_failure:
229 err:
230         kfree_skb(dcbnl_skb);
231         return ret;
232 }
233 
234 static int dcbnl_getstate(struct net_device *netdev, struct nlattr **tb,
235                           u32 pid, u32 seq, u16 flags)
236 {
237         int ret = -EINVAL;
238 
239         /* if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->getstate) */
240         if (!netdev->dcbnl_ops->getstate)
241                 return ret;
242 
243         ret = dcbnl_reply(netdev->dcbnl_ops->getstate(netdev), RTM_GETDCB,
244                           DCB_CMD_GSTATE, DCB_ATTR_STATE, pid, seq, flags);
245 
246         return ret;
247 }
248 
249 static int dcbnl_getpfccfg(struct net_device *netdev, struct nlattr **tb,
250                            u32 pid, u32 seq, u16 flags)
251 {
252         struct sk_buff *dcbnl_skb;
253         struct nlmsghdr *nlh;
254         struct dcbmsg *dcb;
255         struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1], *nest;
256         u8 value;
257         int ret = -EINVAL;
258         int i;
259         int getall = 0;
260 
261         if (!tb[DCB_ATTR_PFC_CFG] || !netdev->dcbnl_ops->getpfccfg)
262                 return ret;
263 
264         ret = nla_parse_nested(data, DCB_PFC_UP_ATTR_MAX,
265                                tb[DCB_ATTR_PFC_CFG],
266                                dcbnl_pfc_up_nest);
267         if (ret)
268                 goto err_out;
269 
270         dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
271         if (!dcbnl_skb)
272                 goto err_out;
273 
274         nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
275 
276         dcb = NLMSG_DATA(nlh);
277         dcb->dcb_family = AF_UNSPEC;
278         dcb->cmd = DCB_CMD_PFC_GCFG;
279 
280         nest = nla_nest_start(dcbnl_skb, DCB_ATTR_PFC_CFG);
281         if (!nest)
282                 goto err;
283 
284         if (data[DCB_PFC_UP_ATTR_ALL])
285                 getall = 1;
286 
287         for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) {
288                 if (!getall && !data[i])
289                         continue;
290 
291                 netdev->dcbnl_ops->getpfccfg(netdev, i - DCB_PFC_UP_ATTR_0,
292                                              &value);
293                 ret = nla_put_u8(dcbnl_skb, i, value);
294 
295                 if (ret) {
296                         nla_nest_cancel(dcbnl_skb, nest);
297                         goto err;
298                 }
299         }
300         nla_nest_end(dcbnl_skb, nest);
301 
302         nlmsg_end(dcbnl_skb, nlh);
303 
304         ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
305         if (ret)
306                 goto err_out;
307 
308         return 0;
309 nlmsg_failure:
310 err:
311         kfree_skb(dcbnl_skb);
312 err_out:
313         return -EINVAL;
314 }
315 
316 static int dcbnl_getperm_hwaddr(struct net_device *netdev, struct nlattr **tb,
317                                 u32 pid, u32 seq, u16 flags)
318 {
319         struct sk_buff *dcbnl_skb;
320         struct nlmsghdr *nlh;
321         struct dcbmsg *dcb;
322         u8 perm_addr[MAX_ADDR_LEN];
323         int ret = -EINVAL;
324 
325         if (!netdev->dcbnl_ops->getpermhwaddr)
326                 return ret;
327 
328         dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
329         if (!dcbnl_skb)
330                 goto err_out;
331 
332         nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
333 
334         dcb = NLMSG_DATA(nlh);
335         dcb->dcb_family = AF_UNSPEC;
336         dcb->cmd = DCB_CMD_GPERM_HWADDR;
337 
338         memset(perm_addr, 0, sizeof(perm_addr));
339         netdev->dcbnl_ops->getpermhwaddr(netdev, perm_addr);
340 
341         ret = nla_put(dcbnl_skb, DCB_ATTR_PERM_HWADDR, sizeof(perm_addr),
342                       perm_addr);
343 
344         nlmsg_end(dcbnl_skb, nlh);
345 
346         ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
347         if (ret)
348                 goto err_out;
349 
350         return 0;
351 
352 nlmsg_failure:
353         kfree_skb(dcbnl_skb);
354 err_out:
355         return -EINVAL;
356 }
357 
358 static int dcbnl_getcap(struct net_device *netdev, struct nlattr **tb,
359                         u32 pid, u32 seq, u16 flags)
360 {
361         struct sk_buff *dcbnl_skb;
362         struct nlmsghdr *nlh;
363         struct dcbmsg *dcb;
364         struct nlattr *data[DCB_CAP_ATTR_MAX + 1], *nest;
365         u8 value;
366         int ret = -EINVAL;
367         int i;
368         int getall = 0;
369 
370         if (!tb[DCB_ATTR_CAP] || !netdev->dcbnl_ops->getcap)
371                 return ret;
372 
373         ret = nla_parse_nested(data, DCB_CAP_ATTR_MAX, tb[DCB_ATTR_CAP],
374                                dcbnl_cap_nest);
375         if (ret)
376                 goto err_out;
377 
378         dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
379         if (!dcbnl_skb)
380                 goto err_out;
381 
382         nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
383 
384         dcb = NLMSG_DATA(nlh);
385         dcb->dcb_family = AF_UNSPEC;
386         dcb->cmd = DCB_CMD_GCAP;
387 
388         nest = nla_nest_start(dcbnl_skb, DCB_ATTR_CAP);
389         if (!nest)
390                 goto err;
391 
392         if (data[DCB_CAP_ATTR_ALL])
393                 getall = 1;
394 
395         for (i = DCB_CAP_ATTR_ALL+1; i <= DCB_CAP_ATTR_MAX; i++) {
396                 if (!getall && !data[i])
397                         continue;
398 
399                 if (!netdev->dcbnl_ops->getcap(netdev, i, &value)) {
400                         ret = nla_put_u8(dcbnl_skb, i, value);
401 
402                         if (ret) {
403                                 nla_nest_cancel(dcbnl_skb, nest);
404                                 goto err;
405                         }
406                 }
407         }
408         nla_nest_end(dcbnl_skb, nest);
409 
410         nlmsg_end(dcbnl_skb, nlh);
411 
412         ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
413         if (ret)
414                 goto err_out;
415 
416         return 0;
417 nlmsg_failure:
418 err:
419         kfree_skb(dcbnl_skb);
420 err_out:
421         return -EINVAL;
422 }
423 
424 static int dcbnl_getnumtcs(struct net_device *netdev, struct nlattr **tb,
425                            u32 pid, u32 seq, u16 flags)
426 {
427         struct sk_buff *dcbnl_skb;
428         struct nlmsghdr *nlh;
429         struct dcbmsg *dcb;
430         struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1], *nest;
431         u8 value;
432         int ret = -EINVAL;
433         int i;
434         int getall = 0;
435 
436         if (!tb[DCB_ATTR_NUMTCS] || !netdev->dcbnl_ops->getnumtcs)
437                 return ret;
438 
439         ret = nla_parse_nested(data, DCB_NUMTCS_ATTR_MAX, tb[DCB_ATTR_NUMTCS],
440                                dcbnl_numtcs_nest);
441         if (ret) {
442                 ret = -EINVAL;
443                 goto err_out;
444         }
445 
446         dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
447         if (!dcbnl_skb) {
448                 ret = -EINVAL;
449                 goto err_out;
450         }
451 
452         nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
453 
454         dcb = NLMSG_DATA(nlh);
455         dcb->dcb_family = AF_UNSPEC;
456         dcb->cmd = DCB_CMD_GNUMTCS;
457 
458         nest = nla_nest_start(dcbnl_skb, DCB_ATTR_NUMTCS);
459         if (!nest) {
460                 ret = -EINVAL;
461                 goto err;
462         }
463 
464         if (data[DCB_NUMTCS_ATTR_ALL])
465                 getall = 1;
466 
467         for (i = DCB_NUMTCS_ATTR_ALL+1; i <= DCB_NUMTCS_ATTR_MAX; i++) {
468                 if (!getall && !data[i])
469                         continue;
470 
471                 ret = netdev->dcbnl_ops->getnumtcs(netdev, i, &value);
472                 if (!ret) {
473                         ret = nla_put_u8(dcbnl_skb, i, value);
474 
475                         if (ret) {
476                                 nla_nest_cancel(dcbnl_skb, nest);
477                                 ret = -EINVAL;
478                                 goto err;
479                         }
480                 } else {
481                         goto err;
482                 }
483         }
484         nla_nest_end(dcbnl_skb, nest);
485 
486         nlmsg_end(dcbnl_skb, nlh);
487 
488         ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
489         if (ret) {
490                 ret = -EINVAL;
491                 goto err_out;
492         }
493 
494         return 0;
495 nlmsg_failure:
496 err:
497         kfree_skb(dcbnl_skb);
498 err_out:
499         return ret;
500 }
501 
502 static int dcbnl_setnumtcs(struct net_device *netdev, struct nlattr **tb,
503                            u32 pid, u32 seq, u16 flags)
504 {
505         struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1];
506         int ret = -EINVAL;
507         u8 value;
508         int i;
509 
510         if (!tb[DCB_ATTR_NUMTCS] || !netdev->dcbnl_ops->setnumtcs)
511                 return ret;
512 
513         ret = nla_parse_nested(data, DCB_NUMTCS_ATTR_MAX, tb[DCB_ATTR_NUMTCS],
514                                dcbnl_numtcs_nest);
515 
516         if (ret) {
517                 ret = -EINVAL;
518                 goto err;
519         }
520 
521         for (i = DCB_NUMTCS_ATTR_ALL+1; i <= DCB_NUMTCS_ATTR_MAX; i++) {
522                 if (data[i] == NULL)
523                         continue;
524 
525                 value = nla_get_u8(data[i]);
526 
527                 ret = netdev->dcbnl_ops->setnumtcs(netdev, i, value);
528 
529                 if (ret)
530                         goto operr;
531         }
532 
533 operr:
534         ret = dcbnl_reply(!!ret, RTM_SETDCB, DCB_CMD_SNUMTCS,
535                           DCB_ATTR_NUMTCS, pid, seq, flags);
536 
537 err:
538         return ret;
539 }
540 
541 static int dcbnl_getpfcstate(struct net_device *netdev, struct nlattr **tb,
542                              u32 pid, u32 seq, u16 flags)
543 {
544         int ret = -EINVAL;
545 
546         if (!netdev->dcbnl_ops->getpfcstate)
547                 return ret;
548 
549         ret = dcbnl_reply(netdev->dcbnl_ops->getpfcstate(netdev), RTM_GETDCB,
550                           DCB_CMD_PFC_GSTATE, DCB_ATTR_PFC_STATE,
551                           pid, seq, flags);
552 
553         return ret;
554 }
555 
556 static int dcbnl_setpfcstate(struct net_device *netdev, struct nlattr **tb,
557                              u32 pid, u32 seq, u16 flags)
558 {
559         int ret = -EINVAL;
560         u8 value;
561 
562         if (!tb[DCB_ATTR_PFC_STATE] || !netdev->dcbnl_ops->setpfcstate)
563                 return ret;
564 
565         value = nla_get_u8(tb[DCB_ATTR_PFC_STATE]);
566 
567         netdev->dcbnl_ops->setpfcstate(netdev, value);
568 
569         ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_PFC_SSTATE, DCB_ATTR_PFC_STATE,
570                           pid, seq, flags);
571 
572         return ret;
573 }
574 
575 static int dcbnl_getapp(struct net_device *netdev, struct nlattr **tb,
576                         u32 pid, u32 seq, u16 flags)
577 {
578         struct sk_buff *dcbnl_skb;
579         struct nlmsghdr *nlh;
580         struct dcbmsg *dcb;
581         struct nlattr *app_nest;
582         struct nlattr *app_tb[DCB_APP_ATTR_MAX + 1];
583         u16 id;
584         u8 up, idtype;
585         int ret = -EINVAL;
586 
587         if (!tb[DCB_ATTR_APP])
588                 goto out;
589 
590         ret = nla_parse_nested(app_tb, DCB_APP_ATTR_MAX, tb[DCB_ATTR_APP],
591                                dcbnl_app_nest);
592         if (ret)
593                 goto out;
594 
595         ret = -EINVAL;
596         /* all must be non-null */
597         if ((!app_tb[DCB_APP_ATTR_IDTYPE]) ||
598             (!app_tb[DCB_APP_ATTR_ID]))
599                 goto out;
600 
601         /* either by eth type or by socket number */
602         idtype = nla_get_u8(app_tb[DCB_APP_ATTR_IDTYPE]);
603         if ((idtype != DCB_APP_IDTYPE_ETHTYPE) &&
604             (idtype != DCB_APP_IDTYPE_PORTNUM))
605                 goto out;
606 
607         id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]);
608 
609         if (netdev->dcbnl_ops->getapp) {
610                 up = netdev->dcbnl_ops->getapp(netdev, idtype, id);
611         } else {
612                 struct dcb_app app = {
613                                         .selector = idtype,
614                                         .protocol = id,
615                                      };
616                 up = dcb_getapp(netdev, &app);
617         }
618 
619         /* send this back */
620         dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
621         if (!dcbnl_skb)
622                 goto out;
623 
624         nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
625         dcb = NLMSG_DATA(nlh);
626         dcb->dcb_family = AF_UNSPEC;
627         dcb->cmd = DCB_CMD_GAPP;
628 
629         app_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_APP);
630         if (!app_nest)
631                 goto out_cancel;
632 
633         ret = nla_put_u8(dcbnl_skb, DCB_APP_ATTR_IDTYPE, idtype);
634         if (ret)
635                 goto out_cancel;
636 
637         ret = nla_put_u16(dcbnl_skb, DCB_APP_ATTR_ID, id);
638         if (ret)
639                 goto out_cancel;
640 
641         ret = nla_put_u8(dcbnl_skb, DCB_APP_ATTR_PRIORITY, up);
642         if (ret)
643                 goto out_cancel;
644 
645         nla_nest_end(dcbnl_skb, app_nest);
646         nlmsg_end(dcbnl_skb, nlh);
647 
648         ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
649         if (ret)
650                 goto nlmsg_failure;
651 
652         goto out;
653 
654 out_cancel:
655         nla_nest_cancel(dcbnl_skb, app_nest);
656 nlmsg_failure:
657         kfree_skb(dcbnl_skb);
658 out:
659         return ret;
660 }
661 
662 static int dcbnl_setapp(struct net_device *netdev, struct nlattr **tb,
663                         u32 pid, u32 seq, u16 flags)
664 {
665         int err, ret = -EINVAL;
666         u16 id;
667         u8 up, idtype;
668         struct nlattr *app_tb[DCB_APP_ATTR_MAX + 1];
669 
670         if (!tb[DCB_ATTR_APP])
671                 goto out;
672 
673         ret = nla_parse_nested(app_tb, DCB_APP_ATTR_MAX, tb[DCB_ATTR_APP],
674                                dcbnl_app_nest);
675         if (ret)
676                 goto out;
677 
678         ret = -EINVAL;
679         /* all must be non-null */
680         if ((!app_tb[DCB_APP_ATTR_IDTYPE]) ||
681             (!app_tb[DCB_APP_ATTR_ID]) ||
682             (!app_tb[DCB_APP_ATTR_PRIORITY]))
683                 goto out;
684 
685         /* either by eth type or by socket number */
686         idtype = nla_get_u8(app_tb[DCB_APP_ATTR_IDTYPE]);
687         if ((idtype != DCB_APP_IDTYPE_ETHTYPE) &&
688             (idtype != DCB_APP_IDTYPE_PORTNUM))
689                 goto out;
690 
691         id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]);
692         up = nla_get_u8(app_tb[DCB_APP_ATTR_PRIORITY]);
693 
694         if (netdev->dcbnl_ops->setapp) {
695                 err = netdev->dcbnl_ops->setapp(netdev, idtype, id, up);
696         } else {
697                 struct dcb_app app;
698                 app.selector = idtype;
699                 app.protocol = id;
700                 app.priority = up;
701                 err = dcb_setapp(netdev, &app);
702         }
703 
704         ret = dcbnl_reply(err, RTM_SETDCB, DCB_CMD_SAPP, DCB_ATTR_APP,
705                           pid, seq, flags);
706 out:
707         return ret;
708 }
709 
710 static int __dcbnl_pg_getcfg(struct net_device *netdev, struct nlattr **tb,
711                              u32 pid, u32 seq, u16 flags, int dir)
712 {
713         struct sk_buff *dcbnl_skb;
714         struct nlmsghdr *nlh;
715         struct dcbmsg *dcb;
716         struct nlattr *pg_nest, *param_nest, *data;
717         struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1];
718         struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1];
719         u8 prio, pgid, tc_pct, up_map;
720         int ret  = -EINVAL;
721         int getall = 0;
722         int i;
723 
724         if (!tb[DCB_ATTR_PG_CFG] ||
725             !netdev->dcbnl_ops->getpgtccfgtx ||
726             !netdev->dcbnl_ops->getpgtccfgrx ||
727             !netdev->dcbnl_ops->getpgbwgcfgtx ||
728             !netdev->dcbnl_ops->getpgbwgcfgrx)
729                 return ret;
730 
731         ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX,
732                                tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest);
733 
734         if (ret)
735                 goto err_out;
736 
737         dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
738         if (!dcbnl_skb)
739                 goto err_out;
740 
741         nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
742 
743         dcb = NLMSG_DATA(nlh);
744         dcb->dcb_family = AF_UNSPEC;
745         dcb->cmd = (dir) ? DCB_CMD_PGRX_GCFG : DCB_CMD_PGTX_GCFG;
746 
747         pg_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_PG_CFG);
748         if (!pg_nest)
749                 goto err;
750 
751         if (pg_tb[DCB_PG_ATTR_TC_ALL])
752                 getall = 1;
753 
754         for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) {
755                 if (!getall && !pg_tb[i])
756                         continue;
757 
758                 if (pg_tb[DCB_PG_ATTR_TC_ALL])
759                         data = pg_tb[DCB_PG_ATTR_TC_ALL];
760                 else
761                         data = pg_tb[i];
762                 ret = nla_parse_nested(param_tb, DCB_TC_ATTR_PARAM_MAX,
763                                        data, dcbnl_tc_param_nest);
764                 if (ret)
765                         goto err_pg;
766 
767                 param_nest = nla_nest_start(dcbnl_skb, i);
768                 if (!param_nest)
769                         goto err_pg;
770 
771                 pgid = DCB_ATTR_VALUE_UNDEFINED;
772                 prio = DCB_ATTR_VALUE_UNDEFINED;
773                 tc_pct = DCB_ATTR_VALUE_UNDEFINED;
774                 up_map = DCB_ATTR_VALUE_UNDEFINED;
775 
776                 if (dir) {
777                         /* Rx */
778                         netdev->dcbnl_ops->getpgtccfgrx(netdev,
779                                                 i - DCB_PG_ATTR_TC_0, &prio,
780                                                 &pgid, &tc_pct, &up_map);
781                 } else {
782                         /* Tx */
783                         netdev->dcbnl_ops->getpgtccfgtx(netdev,
784                                                 i - DCB_PG_ATTR_TC_0, &prio,
785                                                 &pgid, &tc_pct, &up_map);
786                 }
787 
788                 if (param_tb[DCB_TC_ATTR_PARAM_PGID] ||
789                     param_tb[DCB_TC_ATTR_PARAM_ALL]) {
790                         ret = nla_put_u8(dcbnl_skb,
791                                          DCB_TC_ATTR_PARAM_PGID, pgid);
792                         if (ret)
793                                 goto err_param;
794                 }
795                 if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING] ||
796                     param_tb[DCB_TC_ATTR_PARAM_ALL]) {
797                         ret = nla_put_u8(dcbnl_skb,
798                                          DCB_TC_ATTR_PARAM_UP_MAPPING, up_map);
799                         if (ret)
800                                 goto err_param;
801                 }
802                 if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO] ||
803                     param_tb[DCB_TC_ATTR_PARAM_ALL]) {
804                         ret = nla_put_u8(dcbnl_skb,
805                                          DCB_TC_ATTR_PARAM_STRICT_PRIO, prio);
806                         if (ret)
807                                 goto err_param;
808                 }
809                 if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT] ||
810                     param_tb[DCB_TC_ATTR_PARAM_ALL]) {
811                         ret = nla_put_u8(dcbnl_skb, DCB_TC_ATTR_PARAM_BW_PCT,
812                                          tc_pct);
813                         if (ret)
814                                 goto err_param;
815                 }
816                 nla_nest_end(dcbnl_skb, param_nest);
817         }
818 
819         if (pg_tb[DCB_PG_ATTR_BW_ID_ALL])
820                 getall = 1;
821         else
822                 getall = 0;
823 
824         for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) {
825                 if (!getall && !pg_tb[i])
826                         continue;
827 
828                 tc_pct = DCB_ATTR_VALUE_UNDEFINED;
829 
830                 if (dir) {
831                         /* Rx */
832                         netdev->dcbnl_ops->getpgbwgcfgrx(netdev,
833                                         i - DCB_PG_ATTR_BW_ID_0, &tc_pct);
834                 } else {
835                         /* Tx */
836                         netdev->dcbnl_ops->getpgbwgcfgtx(netdev,
837                                         i - DCB_PG_ATTR_BW_ID_0, &tc_pct);
838                 }
839                 ret = nla_put_u8(dcbnl_skb, i, tc_pct);
840 
841                 if (ret)
842                         goto err_pg;
843         }
844 
845         nla_nest_end(dcbnl_skb, pg_nest);
846 
847         nlmsg_end(dcbnl_skb, nlh);
848 
849         ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
850         if (ret)
851                 goto err_out;
852 
853         return 0;
854 
855 err_param:
856         nla_nest_cancel(dcbnl_skb, param_nest);
857 err_pg:
858         nla_nest_cancel(dcbnl_skb, pg_nest);
859 nlmsg_failure:
860 err:
861         kfree_skb(dcbnl_skb);
862 err_out:
863         ret  = -EINVAL;
864         return ret;
865 }
866 
867 static int dcbnl_pgtx_getcfg(struct net_device *netdev, struct nlattr **tb,
868                              u32 pid, u32 seq, u16 flags)
869 {
870         return __dcbnl_pg_getcfg(netdev, tb, pid, seq, flags, 0);
871 }
872 
873 static int dcbnl_pgrx_getcfg(struct net_device *netdev, struct nlattr **tb,
874                              u32 pid, u32 seq, u16 flags)
875 {
876         return __dcbnl_pg_getcfg(netdev, tb, pid, seq, flags, 1);
877 }
878 
879 static int dcbnl_setstate(struct net_device *netdev, struct nlattr **tb,
880                           u32 pid, u32 seq, u16 flags)
881 {
882         int ret = -EINVAL;
883         u8 value;
884 
885         if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->setstate)
886                 return ret;
887 
888         value = nla_get_u8(tb[DCB_ATTR_STATE]);
889 
890         ret = dcbnl_reply(netdev->dcbnl_ops->setstate(netdev, value),
891                           RTM_SETDCB, DCB_CMD_SSTATE, DCB_ATTR_STATE,
892                           pid, seq, flags);
893 
894         return ret;
895 }
896 
897 static int dcbnl_setpfccfg(struct net_device *netdev, struct nlattr **tb,
898                            u32 pid, u32 seq, u16 flags)
899 {
900         struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1];
901         int i;
902         int ret = -EINVAL;
903         u8 value;
904 
905         if (!tb[DCB_ATTR_PFC_CFG] || !netdev->dcbnl_ops->setpfccfg)
906                 return ret;
907 
908         ret = nla_parse_nested(data, DCB_PFC_UP_ATTR_MAX,
909                                tb[DCB_ATTR_PFC_CFG],
910                                dcbnl_pfc_up_nest);
911         if (ret)
912                 goto err;
913 
914         for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) {
915                 if (data[i] == NULL)
916                         continue;
917                 value = nla_get_u8(data[i]);
918                 netdev->dcbnl_ops->setpfccfg(netdev,
919                         data[i]->nla_type - DCB_PFC_UP_ATTR_0, value);
920         }
921 
922         ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_PFC_SCFG, DCB_ATTR_PFC_CFG,
923                           pid, seq, flags);
924 err:
925         return ret;
926 }
927 
928 static int dcbnl_setall(struct net_device *netdev, struct nlattr **tb,
929                         u32 pid, u32 seq, u16 flags)
930 {
931         int ret = -EINVAL;
932 
933         if (!tb[DCB_ATTR_SET_ALL] || !netdev->dcbnl_ops->setall)
934                 return ret;
935 
936         ret = dcbnl_reply(netdev->dcbnl_ops->setall(netdev), RTM_SETDCB,
937                           DCB_CMD_SET_ALL, DCB_ATTR_SET_ALL, pid, seq, flags);
938 
939         return ret;
940 }
941 
942 static int __dcbnl_pg_setcfg(struct net_device *netdev, struct nlattr **tb,
943                              u32 pid, u32 seq, u16 flags, int dir)
944 {
945         struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1];
946         struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1];
947         int ret = -EINVAL;
948         int i;
949         u8 pgid;
950         u8 up_map;
951         u8 prio;
952         u8 tc_pct;
953 
954         if (!tb[DCB_ATTR_PG_CFG] ||
955             !netdev->dcbnl_ops->setpgtccfgtx ||
956             !netdev->dcbnl_ops->setpgtccfgrx ||
957             !netdev->dcbnl_ops->setpgbwgcfgtx ||
958             !netdev->dcbnl_ops->setpgbwgcfgrx)
959                 return ret;
960 
961         ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX,
962                                tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest);
963         if (ret)
964                 goto err;
965 
966         for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) {
967                 if (!pg_tb[i])
968                         continue;
969 
970                 ret = nla_parse_nested(param_tb, DCB_TC_ATTR_PARAM_MAX,
971                                        pg_tb[i], dcbnl_tc_param_nest);
972                 if (ret)
973                         goto err;
974 
975                 pgid = DCB_ATTR_VALUE_UNDEFINED;
976                 prio = DCB_ATTR_VALUE_UNDEFINED;
977                 tc_pct = DCB_ATTR_VALUE_UNDEFINED;
978                 up_map = DCB_ATTR_VALUE_UNDEFINED;
979 
980                 if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO])
981                         prio =
982                             nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO]);
983 
984                 if (param_tb[DCB_TC_ATTR_PARAM_PGID])
985                         pgid = nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_PGID]);
986 
987                 if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT])
988                         tc_pct = nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_BW_PCT]);
989 
990                 if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING])
991                         up_map =
992                              nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING]);
993 
994                 /* dir: Tx = 0, Rx = 1 */
995                 if (dir) {
996                         /* Rx */
997                         netdev->dcbnl_ops->setpgtccfgrx(netdev,
998                                 i - DCB_PG_ATTR_TC_0,
999                                 prio, pgid, tc_pct, up_map);
1000                 } else {
1001                         /* Tx */
1002                         netdev->dcbnl_ops->setpgtccfgtx(netdev,
1003                                 i - DCB_PG_ATTR_TC_0,
1004                                 prio, pgid, tc_pct, up_map);
1005                 }
1006         }
1007 
1008         for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) {
1009                 if (!pg_tb[i])
1010                         continue;
1011 
1012                 tc_pct = nla_get_u8(pg_tb[i]);
1013 
1014                 /* dir: Tx = 0, Rx = 1 */
1015                 if (dir) {
1016                         /* Rx */
1017                         netdev->dcbnl_ops->setpgbwgcfgrx(netdev,
1018                                          i - DCB_PG_ATTR_BW_ID_0, tc_pct);
1019                 } else {
1020                         /* Tx */
1021                         netdev->dcbnl_ops->setpgbwgcfgtx(netdev,
1022                                          i - DCB_PG_ATTR_BW_ID_0, tc_pct);
1023                 }
1024         }
1025 
1026         ret = dcbnl_reply(0, RTM_SETDCB,
1027                           (dir ? DCB_CMD_PGRX_SCFG : DCB_CMD_PGTX_SCFG),
1028                           DCB_ATTR_PG_CFG, pid, seq, flags);
1029 
1030 err:
1031         return ret;
1032 }
1033 
1034 static int dcbnl_pgtx_setcfg(struct net_device *netdev, struct nlattr **tb,
1035                              u32 pid, u32 seq, u16 flags)
1036 {
1037         return __dcbnl_pg_setcfg(netdev, tb, pid, seq, flags, 0);
1038 }
1039 
1040 static int dcbnl_pgrx_setcfg(struct net_device *netdev, struct nlattr **tb,
1041                              u32 pid, u32 seq, u16 flags)
1042 {
1043         return __dcbnl_pg_setcfg(netdev, tb, pid, seq, flags, 1);
1044 }
1045 
1046 static int dcbnl_bcn_getcfg(struct net_device *netdev, struct nlattr **tb,
1047                             u32 pid, u32 seq, u16 flags)
1048 {
1049         struct sk_buff *dcbnl_skb;
1050         struct nlmsghdr *nlh;
1051         struct dcbmsg *dcb;
1052         struct nlattr *bcn_nest;
1053         struct nlattr *bcn_tb[DCB_BCN_ATTR_MAX + 1];
1054         u8 value_byte;
1055         u32 value_integer;
1056         int ret  = -EINVAL;
1057         bool getall = false;
1058         int i;
1059 
1060         if (!tb[DCB_ATTR_BCN] || !netdev->dcbnl_ops->getbcnrp ||
1061             !netdev->dcbnl_ops->getbcncfg)
1062                 return ret;
1063 
1064         ret = nla_parse_nested(bcn_tb, DCB_BCN_ATTR_MAX,
1065                                tb[DCB_ATTR_BCN], dcbnl_bcn_nest);
1066 
1067         if (ret)
1068                 goto err_out;
1069 
1070         dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1071         if (!dcbnl_skb)
1072                 goto err_out;
1073 
1074         nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
1075 
1076         dcb = NLMSG_DATA(nlh);
1077         dcb->dcb_family = AF_UNSPEC;
1078         dcb->cmd = DCB_CMD_BCN_GCFG;
1079 
1080         bcn_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_BCN);
1081         if (!bcn_nest)
1082                 goto err;
1083 
1084         if (bcn_tb[DCB_BCN_ATTR_ALL])
1085                 getall = true;
1086 
1087         for (i = DCB_BCN_ATTR_RP_0; i <= DCB_BCN_ATTR_RP_7; i++) {
1088                 if (!getall && !bcn_tb[i])
1089                         continue;
1090 
1091                 netdev->dcbnl_ops->getbcnrp(netdev, i - DCB_BCN_ATTR_RP_0,
1092                                             &value_byte);
1093                 ret = nla_put_u8(dcbnl_skb, i, value_byte);
1094                 if (ret)
1095                         goto err_bcn;
1096         }
1097 
1098         for (i = DCB_BCN_ATTR_BCNA_0; i <= DCB_BCN_ATTR_RI; i++) {
1099                 if (!getall && !bcn_tb[i])
1100                         continue;
1101 
1102                 netdev->dcbnl_ops->getbcncfg(netdev, i,
1103                                              &value_integer);
1104                 ret = nla_put_u32(dcbnl_skb, i, value_integer);
1105                 if (ret)
1106                         goto err_bcn;
1107         }
1108 
1109         nla_nest_end(dcbnl_skb, bcn_nest);
1110 
1111         nlmsg_end(dcbnl_skb, nlh);
1112 
1113         ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
1114         if (ret)
1115                 goto err_out;
1116 
1117         return 0;
1118 
1119 err_bcn:
1120         nla_nest_cancel(dcbnl_skb, bcn_nest);
1121 nlmsg_failure:
1122 err:
1123         kfree_skb(dcbnl_skb);
1124 err_out:
1125         ret  = -EINVAL;
1126         return ret;
1127 }
1128 
1129 static int dcbnl_bcn_setcfg(struct net_device *netdev, struct nlattr **tb,
1130                             u32 pid, u32 seq, u16 flags)
1131 {
1132         struct nlattr *data[DCB_BCN_ATTR_MAX + 1];
1133         int i;
1134         int ret = -EINVAL;
1135         u8 value_byte;
1136         u32 value_int;
1137 
1138         if (!tb[DCB_ATTR_BCN] || !netdev->dcbnl_ops->setbcncfg ||
1139             !netdev->dcbnl_ops->setbcnrp)
1140                 return ret;
1141 
1142         ret = nla_parse_nested(data, DCB_BCN_ATTR_MAX,
1143                                tb[DCB_ATTR_BCN],
1144                                dcbnl_pfc_up_nest);
1145         if (ret)
1146                 goto err;
1147 
1148         for (i = DCB_BCN_ATTR_RP_0; i <= DCB_BCN_ATTR_RP_7; i++) {
1149                 if (data[i] == NULL)
1150                         continue;
1151                 value_byte = nla_get_u8(data[i]);
1152                 netdev->dcbnl_ops->setbcnrp(netdev,
1153                         data[i]->nla_type - DCB_BCN_ATTR_RP_0, value_byte);
1154         }
1155 
1156         for (i = DCB_BCN_ATTR_BCNA_0; i <= DCB_BCN_ATTR_RI; i++) {
1157                 if (data[i] == NULL)
1158                         continue;
1159                 value_int = nla_get_u32(data[i]);
1160                 netdev->dcbnl_ops->setbcncfg(netdev,
1161                                              i, value_int);
1162         }
1163 
1164         ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_BCN_SCFG, DCB_ATTR_BCN,
1165                           pid, seq, flags);
1166 err:
1167         return ret;
1168 }
1169 
1170 /* Handle IEEE 802.1Qaz SET commands. If any requested operation can not
1171  * be completed the entire msg is aborted and error value is returned.
1172  * No attempt is made to reconcile the case where only part of the
1173  * cmd can be completed.
1174  */
1175 static int dcbnl_ieee_set(struct net_device *netdev, struct nlattr **tb,
1176                           u32 pid, u32 seq, u16 flags)
1177 {
1178         const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
1179         struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1];
1180         int err = -EOPNOTSUPP;
1181 
1182         if (!ops)
1183                 goto err;
1184 
1185         err = nla_parse_nested(ieee, DCB_ATTR_IEEE_MAX,
1186                                tb[DCB_ATTR_IEEE], dcbnl_ieee_policy);
1187         if (err)
1188                 goto err;
1189 
1190         if (ieee[DCB_ATTR_IEEE_ETS] && ops->ieee_setets) {
1191                 struct ieee_ets *ets = nla_data(ieee[DCB_ATTR_IEEE_ETS]);
1192                 err = ops->ieee_setets(netdev, ets);
1193                 if (err)
1194                         goto err;
1195         }
1196 
1197         if (ieee[DCB_ATTR_IEEE_PFC] && ops->ieee_setpfc) {
1198                 struct ieee_pfc *pfc = nla_data(ieee[DCB_ATTR_IEEE_PFC]);
1199                 err = ops->ieee_setpfc(netdev, pfc);
1200                 if (err)
1201                         goto err;
1202         }
1203 
1204         if (ieee[DCB_ATTR_IEEE_APP_TABLE]) {
1205                 struct nlattr *attr;
1206                 int rem;
1207 
1208                 nla_for_each_nested(attr, ieee[DCB_ATTR_IEEE_APP_TABLE], rem) {
1209                         struct dcb_app *app_data;
1210                         if (nla_type(attr) != DCB_ATTR_IEEE_APP)
1211                                 continue;
1212                         app_data = nla_data(attr);
1213                         if (ops->ieee_setapp)
1214                                 err = ops->ieee_setapp(netdev, app_data);
1215                         else
1216                                 err = dcb_setapp(netdev, app_data);
1217                         if (err)
1218                                 goto err;
1219                 }
1220         }
1221 
1222 err:
1223         dcbnl_reply(err, RTM_SETDCB, DCB_CMD_IEEE_SET, DCB_ATTR_IEEE,
1224                     pid, seq, flags);
1225         return err;
1226 }
1227 
1228 static int dcbnl_build_peer_app(struct net_device *netdev, struct sk_buff* skb,
1229                                 int app_nested_type, int app_info_type,
1230                                 int app_entry_type)
1231 {
1232         struct dcb_peer_app_info info;
1233         struct dcb_app *table = NULL;
1234         const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
1235         u16 app_count;
1236         int err;
1237 
1238 
1239         /**
1240          * retrieve the peer app configuration form the driver. If the driver
1241          * handlers fail exit without doing anything
1242          */
1243         err = ops->peer_getappinfo(netdev, &info, &app_count);
1244         if (!err && app_count) {
1245                 table = kmalloc(sizeof(struct dcb_app) * app_count, GFP_KERNEL);
1246                 if (!table)
1247                         return -ENOMEM;
1248 
1249                 err = ops->peer_getapptable(netdev, table);
1250         }
1251 
1252         if (!err) {
1253                 u16 i;
1254                 struct nlattr *app;
1255 
1256                 /**
1257                  * build the message, from here on the only possible failure
1258                  * is due to the skb size
1259                  */
1260                 err = -EMSGSIZE;
1261 
1262                 app = nla_nest_start(skb, app_nested_type);
1263                 if (!app)
1264                         goto nla_put_failure;
1265 
1266                 if (app_info_type)
1267                         NLA_PUT(skb, app_info_type, sizeof(info), &info);
1268 
1269                 for (i = 0; i < app_count; i++)
1270                         NLA_PUT(skb, app_entry_type, sizeof(struct dcb_app),
1271                                 &table[i]);
1272 
1273                 nla_nest_end(skb, app);
1274         }
1275         err = 0;
1276 
1277 nla_put_failure:
1278         kfree(table);
1279         return err;
1280 }
1281 
1282 /* Handle IEEE 802.1Qaz GET commands. */
1283 static int dcbnl_ieee_get(struct net_device *netdev, struct nlattr **tb,
1284                           u32 pid, u32 seq, u16 flags)
1285 {
1286         struct sk_buff *skb;
1287         struct nlmsghdr *nlh;
1288         struct dcbmsg *dcb;
1289         struct nlattr *ieee, *app;
1290         struct dcb_app_type *itr;
1291         const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
1292         int err;
1293 
1294         if (!ops)
1295                 return -EOPNOTSUPP;
1296 
1297         skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1298         if (!skb)
1299                 return -ENOBUFS;
1300 
1301         nlh = NLMSG_NEW(skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
1302 
1303         dcb = NLMSG_DATA(nlh);
1304         dcb->dcb_family = AF_UNSPEC;
1305         dcb->cmd = DCB_CMD_IEEE_GET;
1306 
1307         NLA_PUT_STRING(skb, DCB_ATTR_IFNAME, netdev->name);
1308 
1309         ieee = nla_nest_start(skb, DCB_ATTR_IEEE);
1310         if (!ieee)
1311                 goto nla_put_failure;
1312 
1313         if (ops->ieee_getets) {
1314                 struct ieee_ets ets;
1315                 memset(&ets, 0, sizeof(ets));
1316                 err = ops->ieee_getets(netdev, &ets);
1317                 if (!err)
1318                         NLA_PUT(skb, DCB_ATTR_IEEE_ETS, sizeof(ets), &ets);
1319         }
1320 
1321         if (ops->ieee_getpfc) {
1322                 struct ieee_pfc pfc;
1323                 memset(&pfc, 0, sizeof(pfc));
1324                 err = ops->ieee_getpfc(netdev, &pfc);
1325                 if (!err)
1326                         NLA_PUT(skb, DCB_ATTR_IEEE_PFC, sizeof(pfc), &pfc);
1327         }
1328 
1329         app = nla_nest_start(skb, DCB_ATTR_IEEE_APP_TABLE);
1330         if (!app)
1331                 goto nla_put_failure;
1332 
1333         spin_lock(&dcb_lock);
1334         list_for_each_entry(itr, &dcb_app_list, list) {
1335                 if (strncmp(itr->name, netdev->name, IFNAMSIZ) == 0) {
1336                         err = nla_put(skb, DCB_ATTR_IEEE_APP, sizeof(itr->app),
1337                                          &itr->app);
1338                         if (err) {
1339                                 spin_unlock(&dcb_lock);
1340                                 goto nla_put_failure;
1341                         }
1342                 }
1343         }
1344         spin_unlock(&dcb_lock);
1345         nla_nest_end(skb, app);
1346 
1347         /* get peer info if available */
1348         if (ops->ieee_peer_getets) {
1349                 struct ieee_ets ets;
1350                 memset(&ets, 0, sizeof(ets));
1351                 err = ops->ieee_peer_getets(netdev, &ets);
1352                 if (!err)
1353                         NLA_PUT(skb, DCB_ATTR_IEEE_PEER_ETS, sizeof(ets), &ets);
1354         }
1355 
1356         if (ops->ieee_peer_getpfc) {
1357                 struct ieee_pfc pfc;
1358                 memset(&pfc, 0, sizeof(pfc));
1359                 err = ops->ieee_peer_getpfc(netdev, &pfc);
1360                 if (!err)
1361                         NLA_PUT(skb, DCB_ATTR_IEEE_PEER_PFC, sizeof(pfc), &pfc);
1362         }
1363 
1364         if (ops->peer_getappinfo && ops->peer_getapptable) {
1365                 err = dcbnl_build_peer_app(netdev, skb,
1366                                            DCB_ATTR_IEEE_PEER_APP,
1367                                            DCB_ATTR_IEEE_APP_UNSPEC,
1368                                            DCB_ATTR_IEEE_APP);
1369                 if (err)
1370                         goto nla_put_failure;
1371         }
1372 
1373         nla_nest_end(skb, ieee);
1374         nlmsg_end(skb, nlh);
1375 
1376         return rtnl_unicast(skb, &init_net, pid);
1377 nla_put_failure:
1378         nlmsg_cancel(skb, nlh);
1379 nlmsg_failure:
1380         kfree_skb(skb);
1381         return -1;
1382 }
1383 
1384 /* DCBX configuration */
1385 static int dcbnl_getdcbx(struct net_device *netdev, struct nlattr **tb,
1386                          u32 pid, u32 seq, u16 flags)
1387 {
1388         int ret;
1389 
1390         if (!netdev->dcbnl_ops->getdcbx)
1391                 return -EOPNOTSUPP;
1392 
1393         ret = dcbnl_reply(netdev->dcbnl_ops->getdcbx(netdev), RTM_GETDCB,
1394                           DCB_CMD_GDCBX, DCB_ATTR_DCBX, pid, seq, flags);
1395 
1396         return ret;
1397 }
1398 
1399 static int dcbnl_setdcbx(struct net_device *netdev, struct nlattr **tb,
1400                          u32 pid, u32 seq, u16 flags)
1401 {
1402         int ret;
1403         u8 value;
1404 
1405         if (!netdev->dcbnl_ops->setdcbx)
1406                 return -EOPNOTSUPP;
1407 
1408         if (!tb[DCB_ATTR_DCBX])
1409                 return -EINVAL;
1410 
1411         value = nla_get_u8(tb[DCB_ATTR_DCBX]);
1412 
1413         ret = dcbnl_reply(netdev->dcbnl_ops->setdcbx(netdev, value),
1414                           RTM_SETDCB, DCB_CMD_SDCBX, DCB_ATTR_DCBX,
1415                           pid, seq, flags);
1416 
1417         return ret;
1418 }
1419 
1420 static int dcbnl_getfeatcfg(struct net_device *netdev, struct nlattr **tb,
1421                             u32 pid, u32 seq, u16 flags)
1422 {
1423         struct sk_buff *dcbnl_skb;
1424         struct nlmsghdr *nlh;
1425         struct dcbmsg *dcb;
1426         struct nlattr *data[DCB_FEATCFG_ATTR_MAX + 1], *nest;
1427         u8 value;
1428         int ret, i;
1429         int getall = 0;
1430 
1431         if (!netdev->dcbnl_ops->getfeatcfg)
1432                 return -EOPNOTSUPP;
1433 
1434         if (!tb[DCB_ATTR_FEATCFG])
1435                 return -EINVAL;
1436 
1437         ret = nla_parse_nested(data, DCB_FEATCFG_ATTR_MAX, tb[DCB_ATTR_FEATCFG],
1438                                dcbnl_featcfg_nest);
1439         if (ret)
1440                 goto err_out;
1441 
1442         dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1443         if (!dcbnl_skb) {
1444                 ret = -ENOBUFS;
1445                 goto err_out;
1446         }
1447 
1448         nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
1449 
1450         dcb = NLMSG_DATA(nlh);
1451         dcb->dcb_family = AF_UNSPEC;
1452         dcb->cmd = DCB_CMD_GFEATCFG;
1453 
1454         nest = nla_nest_start(dcbnl_skb, DCB_ATTR_FEATCFG);
1455         if (!nest) {
1456                 ret = -EMSGSIZE;
1457                 goto nla_put_failure;
1458         }
1459 
1460         if (data[DCB_FEATCFG_ATTR_ALL])
1461                 getall = 1;
1462 
1463         for (i = DCB_FEATCFG_ATTR_ALL+1; i <= DCB_FEATCFG_ATTR_MAX; i++) {
1464                 if (!getall && !data[i])
1465                         continue;
1466 
1467                 ret = netdev->dcbnl_ops->getfeatcfg(netdev, i, &value);
1468                 if (!ret)
1469                         ret = nla_put_u8(dcbnl_skb, i, value);
1470 
1471                 if (ret) {
1472                         nla_nest_cancel(dcbnl_skb, nest);
1473                         goto nla_put_failure;
1474                 }
1475         }
1476         nla_nest_end(dcbnl_skb, nest);
1477 
1478         nlmsg_end(dcbnl_skb, nlh);
1479 
1480         return rtnl_unicast(dcbnl_skb, &init_net, pid);
1481 nla_put_failure:
1482         nlmsg_cancel(dcbnl_skb, nlh);
1483 nlmsg_failure:
1484         kfree_skb(dcbnl_skb);
1485 err_out:
1486         return ret;
1487 }
1488 
1489 static int dcbnl_setfeatcfg(struct net_device *netdev, struct nlattr **tb,
1490                             u32 pid, u32 seq, u16 flags)
1491 {
1492         struct nlattr *data[DCB_FEATCFG_ATTR_MAX + 1];
1493         int ret, i;
1494         u8 value;
1495 
1496         if (!netdev->dcbnl_ops->setfeatcfg)
1497                 return -ENOTSUPP;
1498 
1499         if (!tb[DCB_ATTR_FEATCFG])
1500                 return -EINVAL;
1501 
1502         ret = nla_parse_nested(data, DCB_FEATCFG_ATTR_MAX, tb[DCB_ATTR_FEATCFG],
1503                                dcbnl_featcfg_nest);
1504 
1505         if (ret)
1506                 goto err;
1507 
1508         for (i = DCB_FEATCFG_ATTR_ALL+1; i <= DCB_FEATCFG_ATTR_MAX; i++) {
1509                 if (data[i] == NULL)
1510                         continue;
1511 
1512                 value = nla_get_u8(data[i]);
1513 
1514                 ret = netdev->dcbnl_ops->setfeatcfg(netdev, i, value);
1515 
1516                 if (ret)
1517                         goto err;
1518         }
1519 err:
1520         dcbnl_reply(ret, RTM_SETDCB, DCB_CMD_SFEATCFG, DCB_ATTR_FEATCFG,
1521                     pid, seq, flags);
1522 
1523         return ret;
1524 }
1525 
1526 /* Handle CEE DCBX GET commands. */
1527 static int dcbnl_cee_get(struct net_device *netdev, struct nlattr **tb,
1528                          u32 pid, u32 seq, u16 flags)
1529 {
1530         struct sk_buff *skb;
1531         struct nlmsghdr *nlh;
1532         struct dcbmsg *dcb;
1533         struct nlattr *cee;
1534         const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
1535         int err;
1536 
1537         if (!ops)
1538                 return -EOPNOTSUPP;
1539 
1540         skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1541         if (!skb)
1542                 return -ENOBUFS;
1543 
1544         nlh = NLMSG_NEW(skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
1545 
1546         dcb = NLMSG_DATA(nlh);
1547         dcb->dcb_family = AF_UNSPEC;
1548         dcb->cmd = DCB_CMD_CEE_GET;
1549 
1550         NLA_PUT_STRING(skb, DCB_ATTR_IFNAME, netdev->name);
1551 
1552         cee = nla_nest_start(skb, DCB_ATTR_CEE);
1553         if (!cee)
1554                 goto nla_put_failure;
1555 
1556         /* get peer info if available */
1557         if (ops->cee_peer_getpg) {
1558                 struct cee_pg pg;
1559                 memset(&pg, 0, sizeof(pg));
1560                 err = ops->cee_peer_getpg(netdev, &pg);
1561                 if (!err)
1562                         NLA_PUT(skb, DCB_ATTR_CEE_PEER_PG, sizeof(pg), &pg);
1563         }
1564 
1565         if (ops->cee_peer_getpfc) {
1566                 struct cee_pfc pfc;
1567                 memset(&pfc, 0, sizeof(pfc));
1568                 err = ops->cee_peer_getpfc(netdev, &pfc);
1569                 if (!err)
1570                         NLA_PUT(skb, DCB_ATTR_CEE_PEER_PFC, sizeof(pfc), &pfc);
1571         }
1572 
1573         if (ops->peer_getappinfo && ops->peer_getapptable) {
1574                 err = dcbnl_build_peer_app(netdev, skb,
1575                                            DCB_ATTR_CEE_PEER_APP_TABLE,
1576                                            DCB_ATTR_CEE_PEER_APP_INFO,
1577                                            DCB_ATTR_CEE_PEER_APP);
1578                 if (err)
1579                         goto nla_put_failure;
1580         }
1581 
1582         nla_nest_end(skb, cee);
1583         nlmsg_end(skb, nlh);
1584 
1585         return rtnl_unicast(skb, &init_net, pid);
1586 nla_put_failure:
1587         nlmsg_cancel(skb, nlh);
1588 nlmsg_failure:
1589         kfree_skb(skb);
1590         return -1;
1591 }
1592 
1593 static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
1594 {
1595         struct net *net = sock_net(skb->sk);
1596         struct net_device *netdev;
1597         struct dcbmsg  *dcb = (struct dcbmsg *)NLMSG_DATA(nlh);
1598         struct nlattr *tb[DCB_ATTR_MAX + 1];
1599         u32 pid = skb ? NETLINK_CB(skb).pid : 0;
1600         int ret = -EINVAL;
1601 
1602         if (!net_eq(net, &init_net))
1603                 return -EINVAL;
1604 
1605         ret = nlmsg_parse(nlh, sizeof(*dcb), tb, DCB_ATTR_MAX,
1606                           dcbnl_rtnl_policy);
1607         if (ret < 0)
1608                 return ret;
1609 
1610         if (!tb[DCB_ATTR_IFNAME])
1611                 return -EINVAL;
1612 
1613         netdev = dev_get_by_name(&init_net, nla_data(tb[DCB_ATTR_IFNAME]));
1614         if (!netdev)
1615                 return -EINVAL;
1616 
1617         if (!netdev->dcbnl_ops)
1618                 goto errout;
1619 
1620         switch (dcb->cmd) {
1621         case DCB_CMD_GSTATE:
1622                 ret = dcbnl_getstate(netdev, tb, pid, nlh->nlmsg_seq,
1623                                      nlh->nlmsg_flags);
1624                 goto out;
1625         case DCB_CMD_PFC_GCFG:
1626                 ret = dcbnl_getpfccfg(netdev, tb, pid, nlh->nlmsg_seq,
1627                                       nlh->nlmsg_flags);
1628                 goto out;
1629         case DCB_CMD_GPERM_HWADDR:
1630                 ret = dcbnl_getperm_hwaddr(netdev, tb, pid, nlh->nlmsg_seq,
1631                                            nlh->nlmsg_flags);
1632                 goto out;
1633         case DCB_CMD_PGTX_GCFG:
1634                 ret = dcbnl_pgtx_getcfg(netdev, tb, pid, nlh->nlmsg_seq,
1635                                         nlh->nlmsg_flags);
1636                 goto out;
1637         case DCB_CMD_PGRX_GCFG:
1638                 ret = dcbnl_pgrx_getcfg(netdev, tb, pid, nlh->nlmsg_seq,
1639                                         nlh->nlmsg_flags);
1640                 goto out;
1641         case DCB_CMD_BCN_GCFG:
1642                 ret = dcbnl_bcn_getcfg(netdev, tb, pid, nlh->nlmsg_seq,
1643                                        nlh->nlmsg_flags);
1644                 goto out;
1645         case DCB_CMD_SSTATE:
1646                 ret = dcbnl_setstate(netdev, tb, pid, nlh->nlmsg_seq,
1647                                      nlh->nlmsg_flags);
1648                 goto out;
1649         case DCB_CMD_PFC_SCFG:
1650                 ret = dcbnl_setpfccfg(netdev, tb, pid, nlh->nlmsg_seq,
1651                                       nlh->nlmsg_flags);
1652                 goto out;
1653 
1654         case DCB_CMD_SET_ALL:
1655                 ret = dcbnl_setall(netdev, tb, pid, nlh->nlmsg_seq,
1656                                    nlh->nlmsg_flags);
1657                 goto out;
1658         case DCB_CMD_PGTX_SCFG:
1659                 ret = dcbnl_pgtx_setcfg(netdev, tb, pid, nlh->nlmsg_seq,
1660                                         nlh->nlmsg_flags);
1661                 goto out;
1662         case DCB_CMD_PGRX_SCFG:
1663                 ret = dcbnl_pgrx_setcfg(netdev, tb, pid, nlh->nlmsg_seq,
1664                                         nlh->nlmsg_flags);
1665                 goto out;
1666         case DCB_CMD_GCAP:
1667                 ret = dcbnl_getcap(netdev, tb, pid, nlh->nlmsg_seq,
1668                                    nlh->nlmsg_flags);
1669                 goto out;
1670         case DCB_CMD_GNUMTCS:
1671                 ret = dcbnl_getnumtcs(netdev, tb, pid, nlh->nlmsg_seq,
1672                                       nlh->nlmsg_flags);
1673                 goto out;
1674         case DCB_CMD_SNUMTCS:
1675                 ret = dcbnl_setnumtcs(netdev, tb, pid, nlh->nlmsg_seq,
1676                                       nlh->nlmsg_flags);
1677                 goto out;
1678         case DCB_CMD_PFC_GSTATE:
1679                 ret = dcbnl_getpfcstate(netdev, tb, pid, nlh->nlmsg_seq,
1680                                         nlh->nlmsg_flags);
1681                 goto out;
1682         case DCB_CMD_PFC_SSTATE:
1683                 ret = dcbnl_setpfcstate(netdev, tb, pid, nlh->nlmsg_seq,
1684                                         nlh->nlmsg_flags);
1685                 goto out;
1686         case DCB_CMD_BCN_SCFG:
1687                 ret = dcbnl_bcn_setcfg(netdev, tb, pid, nlh->nlmsg_seq,
1688                                        nlh->nlmsg_flags);
1689                 goto out;
1690         case DCB_CMD_GAPP:
1691                 ret = dcbnl_getapp(netdev, tb, pid, nlh->nlmsg_seq,
1692                                    nlh->nlmsg_flags);
1693                 goto out;
1694         case DCB_CMD_SAPP:
1695                 ret = dcbnl_setapp(netdev, tb, pid, nlh->nlmsg_seq,
1696                                    nlh->nlmsg_flags);
1697                 goto out;
1698         case DCB_CMD_IEEE_SET:
1699                 ret = dcbnl_ieee_set(netdev, tb, pid, nlh->nlmsg_seq,
1700                                  nlh->nlmsg_flags);
1701                 goto out;
1702         case DCB_CMD_IEEE_GET:
1703                 ret = dcbnl_ieee_get(netdev, tb, pid, nlh->nlmsg_seq,
1704                                  nlh->nlmsg_flags);
1705                 goto out;
1706         case DCB_CMD_GDCBX:
1707                 ret = dcbnl_getdcbx(netdev, tb, pid, nlh->nlmsg_seq,
1708                                     nlh->nlmsg_flags);
1709                 goto out;
1710         case DCB_CMD_SDCBX:
1711                 ret = dcbnl_setdcbx(netdev, tb, pid, nlh->nlmsg_seq,
1712                                     nlh->nlmsg_flags);
1713                 goto out;
1714         case DCB_CMD_GFEATCFG:
1715                 ret = dcbnl_getfeatcfg(netdev, tb, pid, nlh->nlmsg_seq,
1716                                        nlh->nlmsg_flags);
1717                 goto out;
1718         case DCB_CMD_SFEATCFG:
1719                 ret = dcbnl_setfeatcfg(netdev, tb, pid, nlh->nlmsg_seq,
1720                                        nlh->nlmsg_flags);
1721                 goto out;
1722         case DCB_CMD_CEE_GET:
1723                 ret = dcbnl_cee_get(netdev, tb, pid, nlh->nlmsg_seq,
1724                                     nlh->nlmsg_flags);
1725                 goto out;
1726         default:
1727                 goto errout;
1728         }
1729 errout:
1730         ret = -EINVAL;
1731 out:
1732         dev_put(netdev);
1733         return ret;
1734 }
1735 
1736 /**
1737  * dcb_getapp - retrieve the DCBX application user priority
1738  *
1739  * On success returns a non-zero 802.1p user priority bitmap
1740  * otherwise returns 0 as the invalid user priority bitmap to
1741  * indicate an error.
1742  */
1743 u8 dcb_getapp(struct net_device *dev, struct dcb_app *app)
1744 {
1745         struct dcb_app_type *itr;
1746         u8 prio = 0;
1747 
1748         spin_lock(&dcb_lock);
1749         list_for_each_entry(itr, &dcb_app_list, list) {
1750                 if (itr->app.selector == app->selector &&
1751                     itr->app.protocol == app->protocol &&
1752                     (strncmp(itr->name, dev->name, IFNAMSIZ) == 0)) {
1753                         prio = itr->app.priority;
1754                         break;
1755                 }
1756         }
1757         spin_unlock(&dcb_lock);
1758 
1759         return prio;
1760 }
1761 EXPORT_SYMBOL(dcb_getapp);
1762 
1763 /**
1764  * ixgbe_dcbnl_setapp - add dcb application data to app list
1765  *
1766  * Priority 0 is the default priority this removes applications
1767  * from the app list if the priority is set to zero.
1768  */
1769 u8 dcb_setapp(struct net_device *dev, struct dcb_app *new)
1770 {
1771         struct dcb_app_type *itr;
1772         struct dcb_app_type event;
1773 
1774         memcpy(&event.name, dev->name, sizeof(event.name));
1775         memcpy(&event.app, new, sizeof(event.app));
1776 
1777         spin_lock(&dcb_lock);
1778         /* Search for existing match and replace */
1779         list_for_each_entry(itr, &dcb_app_list, list) {
1780                 if (itr->app.selector == new->selector &&
1781                     itr->app.protocol == new->protocol &&
1782                     (strncmp(itr->name, dev->name, IFNAMSIZ) == 0)) {
1783                         if (new->priority)
1784                                 itr->app.priority = new->priority;
1785                         else {
1786                                 list_del(&itr->list);
1787                                 kfree(itr);
1788                         }
1789                         goto out;
1790                 }
1791         }
1792         /* App type does not exist add new application type */
1793         if (new->priority) {
1794                 struct dcb_app_type *entry;
1795                 entry = kmalloc(sizeof(struct dcb_app_type), GFP_ATOMIC);
1796                 if (!entry) {
1797                         spin_unlock(&dcb_lock);
1798                         return -ENOMEM;
1799                 }
1800 
1801                 memcpy(&entry->app, new, sizeof(*new));
1802                 strncpy(entry->name, dev->name, IFNAMSIZ);
1803                 list_add(&entry->list, &dcb_app_list);
1804         }
1805 out:
1806         spin_unlock(&dcb_lock);
1807         call_dcbevent_notifiers(DCB_APP_EVENT, &event);
1808         return 0;
1809 }
1810 EXPORT_SYMBOL(dcb_setapp);
1811 
1812 static void dcb_flushapp(void)
1813 {
1814         struct dcb_app_type *app;
1815         struct dcb_app_type *tmp;
1816 
1817         spin_lock(&dcb_lock);
1818         list_for_each_entry_safe(app, tmp, &dcb_app_list, list) {
1819                 list_del(&app->list);
1820                 kfree(app);
1821         }
1822         spin_unlock(&dcb_lock);
1823 }
1824 
1825 static int __init dcbnl_init(void)
1826 {
1827         INIT_LIST_HEAD(&dcb_app_list);
1828 
1829         rtnl_register(PF_UNSPEC, RTM_GETDCB, dcb_doit, NULL, NULL);
1830         rtnl_register(PF_UNSPEC, RTM_SETDCB, dcb_doit, NULL, NULL);
1831 
1832         return 0;
1833 }
1834 module_init(dcbnl_init);
1835 
1836 static void __exit dcbnl_exit(void)
1837 {
1838         rtnl_unregister(PF_UNSPEC, RTM_GETDCB);
1839         rtnl_unregister(PF_UNSPEC, RTM_SETDCB);
1840         dcb_flushapp();
1841 }
1842 module_exit(dcbnl_exit);
1843 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp