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