dcbnl.c revision 7c77ab24e30bad7598b5cfda93be6f32ed439c2f
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/* 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
52MODULE_AUTHOR("Lucy Liu, <lucy.liu@intel.com>");
53MODULE_DESCRIPTION("Data Center Bridging netlink interface");
54MODULE_LICENSE("GPL");
55
56/**************** DCB attribute policies *************************************/
57
58/* DCB netlink attributes policy */
59static 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 */
76static 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 */
89static 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. */
111static 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. */
120static 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. */
133static 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. */
140static 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. */
169static 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. */
176static 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	[DCB_ATTR_IEEE_MAXRATE]   = {.len = sizeof(struct ieee_maxrate)},
181};
182
183static const struct nla_policy dcbnl_ieee_app[DCB_ATTR_IEEE_APP_MAX + 1] = {
184	[DCB_ATTR_IEEE_APP]	    = {.len = sizeof(struct dcb_app)},
185};
186
187/* DCB number of traffic classes nested attributes. */
188static const struct nla_policy dcbnl_featcfg_nest[DCB_FEATCFG_ATTR_MAX + 1] = {
189	[DCB_FEATCFG_ATTR_ALL]      = {.type = NLA_FLAG},
190	[DCB_FEATCFG_ATTR_PG]       = {.type = NLA_U8},
191	[DCB_FEATCFG_ATTR_PFC]      = {.type = NLA_U8},
192	[DCB_FEATCFG_ATTR_APP]      = {.type = NLA_U8},
193};
194
195static LIST_HEAD(dcb_app_list);
196static DEFINE_SPINLOCK(dcb_lock);
197
198static struct sk_buff *dcbnl_newmsg(int type, u8 cmd, u32 port, u32 seq,
199				    u32 flags, struct nlmsghdr **nlhp)
200{
201	struct sk_buff *skb;
202	struct dcbmsg *dcb;
203	struct nlmsghdr *nlh;
204
205	skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
206	if (!skb)
207		return NULL;
208
209	nlh = nlmsg_put(skb, port, seq, type, sizeof(*dcb), flags);
210	BUG_ON(!nlh);
211
212	dcb = nlmsg_data(nlh);
213	dcb->dcb_family = AF_UNSPEC;
214	dcb->cmd = cmd;
215	dcb->dcb_pad = 0;
216
217	if (nlhp)
218		*nlhp = nlh;
219
220	return skb;
221}
222
223static int dcbnl_getstate(struct net_device *netdev, struct nlmsghdr *nlh,
224			  u32 seq, struct nlattr **tb, struct sk_buff *skb)
225{
226	/* if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->getstate) */
227	if (!netdev->dcbnl_ops->getstate)
228		return -EOPNOTSUPP;
229
230	return nla_put_u8(skb, DCB_ATTR_STATE,
231			  netdev->dcbnl_ops->getstate(netdev));
232}
233
234static int dcbnl_getpfccfg(struct net_device *netdev, struct nlmsghdr *nlh,
235			   u32 seq, struct nlattr **tb, struct sk_buff *skb)
236{
237	struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1], *nest;
238	u8 value;
239	int ret;
240	int i;
241	int getall = 0;
242
243	if (!tb[DCB_ATTR_PFC_CFG])
244		return -EINVAL;
245
246	if (!netdev->dcbnl_ops->getpfccfg)
247		return -EOPNOTSUPP;
248
249	ret = nla_parse_nested(data, DCB_PFC_UP_ATTR_MAX,
250	                       tb[DCB_ATTR_PFC_CFG],
251	                       dcbnl_pfc_up_nest);
252	if (ret)
253		return ret;
254
255	nest = nla_nest_start(skb, DCB_ATTR_PFC_CFG);
256	if (!nest)
257		return -EMSGSIZE;
258
259	if (data[DCB_PFC_UP_ATTR_ALL])
260		getall = 1;
261
262	for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) {
263		if (!getall && !data[i])
264			continue;
265
266		netdev->dcbnl_ops->getpfccfg(netdev, i - DCB_PFC_UP_ATTR_0,
267		                             &value);
268		ret = nla_put_u8(skb, i, value);
269		if (ret) {
270			nla_nest_cancel(skb, nest);
271			return ret;
272		}
273	}
274	nla_nest_end(skb, nest);
275
276	return 0;
277}
278
279static int dcbnl_getperm_hwaddr(struct net_device *netdev, struct nlmsghdr *nlh,
280				u32 seq, struct nlattr **tb, struct sk_buff *skb)
281{
282	u8 perm_addr[MAX_ADDR_LEN];
283
284	if (!netdev->dcbnl_ops->getpermhwaddr)
285		return -EOPNOTSUPP;
286
287	netdev->dcbnl_ops->getpermhwaddr(netdev, perm_addr);
288
289	return nla_put(skb, DCB_ATTR_PERM_HWADDR, sizeof(perm_addr), perm_addr);
290}
291
292static int dcbnl_getcap(struct net_device *netdev, struct nlmsghdr *nlh,
293			u32 seq, struct nlattr **tb, struct sk_buff *skb)
294{
295	struct nlattr *data[DCB_CAP_ATTR_MAX + 1], *nest;
296	u8 value;
297	int ret;
298	int i;
299	int getall = 0;
300
301	if (!tb[DCB_ATTR_CAP])
302		return -EINVAL;
303
304	if (!netdev->dcbnl_ops->getcap)
305		return -EOPNOTSUPP;
306
307	ret = nla_parse_nested(data, DCB_CAP_ATTR_MAX, tb[DCB_ATTR_CAP],
308	                       dcbnl_cap_nest);
309	if (ret)
310		return ret;
311
312	nest = nla_nest_start(skb, DCB_ATTR_CAP);
313	if (!nest)
314		return -EMSGSIZE;
315
316	if (data[DCB_CAP_ATTR_ALL])
317		getall = 1;
318
319	for (i = DCB_CAP_ATTR_ALL+1; i <= DCB_CAP_ATTR_MAX; i++) {
320		if (!getall && !data[i])
321			continue;
322
323		if (!netdev->dcbnl_ops->getcap(netdev, i, &value)) {
324			ret = nla_put_u8(skb, i, value);
325			if (ret) {
326				nla_nest_cancel(skb, nest);
327				return ret;
328			}
329		}
330	}
331	nla_nest_end(skb, nest);
332
333	return 0;
334}
335
336static int dcbnl_getnumtcs(struct net_device *netdev, struct nlmsghdr *nlh,
337			   u32 seq, struct nlattr **tb, struct sk_buff *skb)
338{
339	struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1], *nest;
340	u8 value;
341	int ret;
342	int i;
343	int getall = 0;
344
345	if (!tb[DCB_ATTR_NUMTCS])
346		return -EINVAL;
347
348	if (!netdev->dcbnl_ops->getnumtcs)
349		return -EOPNOTSUPP;
350
351	ret = nla_parse_nested(data, DCB_NUMTCS_ATTR_MAX, tb[DCB_ATTR_NUMTCS],
352	                       dcbnl_numtcs_nest);
353	if (ret)
354		return ret;
355
356	nest = nla_nest_start(skb, DCB_ATTR_NUMTCS);
357	if (!nest)
358		return -EMSGSIZE;
359
360	if (data[DCB_NUMTCS_ATTR_ALL])
361		getall = 1;
362
363	for (i = DCB_NUMTCS_ATTR_ALL+1; i <= DCB_NUMTCS_ATTR_MAX; i++) {
364		if (!getall && !data[i])
365			continue;
366
367		ret = netdev->dcbnl_ops->getnumtcs(netdev, i, &value);
368		if (!ret) {
369			ret = nla_put_u8(skb, i, value);
370			if (ret) {
371				nla_nest_cancel(skb, nest);
372				return ret;
373			}
374		} else
375			return -EINVAL;
376	}
377	nla_nest_end(skb, nest);
378
379	return 0;
380}
381
382static int dcbnl_setnumtcs(struct net_device *netdev, struct nlmsghdr *nlh,
383			   u32 seq, struct nlattr **tb, struct sk_buff *skb)
384{
385	struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1];
386	int ret;
387	u8 value;
388	int i;
389
390	if (!tb[DCB_ATTR_NUMTCS])
391		return -EINVAL;
392
393	if (!netdev->dcbnl_ops->setnumtcs)
394		return -EOPNOTSUPP;
395
396	ret = nla_parse_nested(data, DCB_NUMTCS_ATTR_MAX, tb[DCB_ATTR_NUMTCS],
397	                       dcbnl_numtcs_nest);
398	if (ret)
399		return ret;
400
401	for (i = DCB_NUMTCS_ATTR_ALL+1; i <= DCB_NUMTCS_ATTR_MAX; i++) {
402		if (data[i] == NULL)
403			continue;
404
405		value = nla_get_u8(data[i]);
406
407		ret = netdev->dcbnl_ops->setnumtcs(netdev, i, value);
408		if (ret)
409			break;
410	}
411
412	return nla_put_u8(skb, DCB_ATTR_NUMTCS, !!ret);
413}
414
415static int dcbnl_getpfcstate(struct net_device *netdev, struct nlmsghdr *nlh,
416			     u32 seq, struct nlattr **tb, struct sk_buff *skb)
417{
418	if (!netdev->dcbnl_ops->getpfcstate)
419		return -EOPNOTSUPP;
420
421	return nla_put_u8(skb, DCB_ATTR_PFC_STATE,
422			  netdev->dcbnl_ops->getpfcstate(netdev));
423}
424
425static int dcbnl_setpfcstate(struct net_device *netdev, struct nlmsghdr *nlh,
426			     u32 seq, struct nlattr **tb, struct sk_buff *skb)
427{
428	u8 value;
429
430	if (!tb[DCB_ATTR_PFC_STATE])
431		return -EINVAL;
432
433	if (!netdev->dcbnl_ops->setpfcstate)
434		return -EOPNOTSUPP;
435
436	value = nla_get_u8(tb[DCB_ATTR_PFC_STATE]);
437
438	netdev->dcbnl_ops->setpfcstate(netdev, value);
439
440	return nla_put_u8(skb, DCB_ATTR_PFC_STATE, 0);
441}
442
443static int dcbnl_getapp(struct net_device *netdev, struct nlmsghdr *nlh,
444			u32 seq, struct nlattr **tb, struct sk_buff *skb)
445{
446	struct nlattr *app_nest;
447	struct nlattr *app_tb[DCB_APP_ATTR_MAX + 1];
448	u16 id;
449	u8 up, idtype;
450	int ret;
451
452	if (!tb[DCB_ATTR_APP])
453		return -EINVAL;
454
455	ret = nla_parse_nested(app_tb, DCB_APP_ATTR_MAX, tb[DCB_ATTR_APP],
456	                       dcbnl_app_nest);
457	if (ret)
458		return ret;
459
460	/* all must be non-null */
461	if ((!app_tb[DCB_APP_ATTR_IDTYPE]) ||
462	    (!app_tb[DCB_APP_ATTR_ID]))
463		return -EINVAL;
464
465	/* either by eth type or by socket number */
466	idtype = nla_get_u8(app_tb[DCB_APP_ATTR_IDTYPE]);
467	if ((idtype != DCB_APP_IDTYPE_ETHTYPE) &&
468	    (idtype != DCB_APP_IDTYPE_PORTNUM))
469		return -EINVAL;
470
471	id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]);
472
473	if (netdev->dcbnl_ops->getapp) {
474		up = netdev->dcbnl_ops->getapp(netdev, idtype, id);
475	} else {
476		struct dcb_app app = {
477					.selector = idtype,
478					.protocol = id,
479				     };
480		up = dcb_getapp(netdev, &app);
481	}
482
483	app_nest = nla_nest_start(skb, DCB_ATTR_APP);
484	if (!app_nest)
485		return -EMSGSIZE;
486
487	ret = nla_put_u8(skb, DCB_APP_ATTR_IDTYPE, idtype);
488	if (ret)
489		goto out_cancel;
490
491	ret = nla_put_u16(skb, DCB_APP_ATTR_ID, id);
492	if (ret)
493		goto out_cancel;
494
495	ret = nla_put_u8(skb, DCB_APP_ATTR_PRIORITY, up);
496	if (ret)
497		goto out_cancel;
498
499	nla_nest_end(skb, app_nest);
500
501	return 0;
502
503out_cancel:
504	nla_nest_cancel(skb, app_nest);
505	return ret;
506}
507
508static int dcbnl_setapp(struct net_device *netdev, struct nlmsghdr *nlh,
509			u32 seq, struct nlattr **tb, struct sk_buff *skb)
510{
511	int ret;
512	u16 id;
513	u8 up, idtype;
514	struct nlattr *app_tb[DCB_APP_ATTR_MAX + 1];
515
516	if (!tb[DCB_ATTR_APP])
517		return -EINVAL;
518
519	ret = nla_parse_nested(app_tb, DCB_APP_ATTR_MAX, tb[DCB_ATTR_APP],
520	                       dcbnl_app_nest);
521	if (ret)
522		return ret;
523
524	/* all must be non-null */
525	if ((!app_tb[DCB_APP_ATTR_IDTYPE]) ||
526	    (!app_tb[DCB_APP_ATTR_ID]) ||
527	    (!app_tb[DCB_APP_ATTR_PRIORITY]))
528		return -EINVAL;
529
530	/* either by eth type or by socket number */
531	idtype = nla_get_u8(app_tb[DCB_APP_ATTR_IDTYPE]);
532	if ((idtype != DCB_APP_IDTYPE_ETHTYPE) &&
533	    (idtype != DCB_APP_IDTYPE_PORTNUM))
534		return -EINVAL;
535
536	id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]);
537	up = nla_get_u8(app_tb[DCB_APP_ATTR_PRIORITY]);
538
539	if (netdev->dcbnl_ops->setapp) {
540		ret = netdev->dcbnl_ops->setapp(netdev, idtype, id, up);
541	} else {
542		struct dcb_app app;
543		app.selector = idtype;
544		app.protocol = id;
545		app.priority = up;
546		ret = dcb_setapp(netdev, &app);
547	}
548
549	ret = nla_put_u8(skb, DCB_ATTR_APP, ret);
550	dcbnl_cee_notify(netdev, RTM_SETDCB, DCB_CMD_SAPP, seq, 0);
551
552	return ret;
553}
554
555static int __dcbnl_pg_getcfg(struct net_device *netdev, struct nlmsghdr *nlh,
556			     struct nlattr **tb, struct sk_buff *skb, int dir)
557{
558	struct nlattr *pg_nest, *param_nest, *data;
559	struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1];
560	struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1];
561	u8 prio, pgid, tc_pct, up_map;
562	int ret;
563	int getall = 0;
564	int i;
565
566	if (!tb[DCB_ATTR_PG_CFG])
567		return -EINVAL;
568
569	if (!netdev->dcbnl_ops->getpgtccfgtx ||
570	    !netdev->dcbnl_ops->getpgtccfgrx ||
571	    !netdev->dcbnl_ops->getpgbwgcfgtx ||
572	    !netdev->dcbnl_ops->getpgbwgcfgrx)
573		return -EOPNOTSUPP;
574
575	ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX,
576	                       tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest);
577	if (ret)
578		return ret;
579
580	pg_nest = nla_nest_start(skb, DCB_ATTR_PG_CFG);
581	if (!pg_nest)
582		return -EMSGSIZE;
583
584	if (pg_tb[DCB_PG_ATTR_TC_ALL])
585		getall = 1;
586
587	for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) {
588		if (!getall && !pg_tb[i])
589			continue;
590
591		if (pg_tb[DCB_PG_ATTR_TC_ALL])
592			data = pg_tb[DCB_PG_ATTR_TC_ALL];
593		else
594			data = pg_tb[i];
595		ret = nla_parse_nested(param_tb, DCB_TC_ATTR_PARAM_MAX,
596				       data, dcbnl_tc_param_nest);
597		if (ret)
598			goto err_pg;
599
600		param_nest = nla_nest_start(skb, i);
601		if (!param_nest)
602			goto err_pg;
603
604		pgid = DCB_ATTR_VALUE_UNDEFINED;
605		prio = DCB_ATTR_VALUE_UNDEFINED;
606		tc_pct = DCB_ATTR_VALUE_UNDEFINED;
607		up_map = DCB_ATTR_VALUE_UNDEFINED;
608
609		if (dir) {
610			/* Rx */
611			netdev->dcbnl_ops->getpgtccfgrx(netdev,
612						i - DCB_PG_ATTR_TC_0, &prio,
613						&pgid, &tc_pct, &up_map);
614		} else {
615			/* Tx */
616			netdev->dcbnl_ops->getpgtccfgtx(netdev,
617						i - DCB_PG_ATTR_TC_0, &prio,
618						&pgid, &tc_pct, &up_map);
619		}
620
621		if (param_tb[DCB_TC_ATTR_PARAM_PGID] ||
622		    param_tb[DCB_TC_ATTR_PARAM_ALL]) {
623			ret = nla_put_u8(skb,
624			                 DCB_TC_ATTR_PARAM_PGID, pgid);
625			if (ret)
626				goto err_param;
627		}
628		if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING] ||
629		    param_tb[DCB_TC_ATTR_PARAM_ALL]) {
630			ret = nla_put_u8(skb,
631			                 DCB_TC_ATTR_PARAM_UP_MAPPING, up_map);
632			if (ret)
633				goto err_param;
634		}
635		if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO] ||
636		    param_tb[DCB_TC_ATTR_PARAM_ALL]) {
637			ret = nla_put_u8(skb,
638			                 DCB_TC_ATTR_PARAM_STRICT_PRIO, prio);
639			if (ret)
640				goto err_param;
641		}
642		if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT] ||
643		    param_tb[DCB_TC_ATTR_PARAM_ALL]) {
644			ret = nla_put_u8(skb, DCB_TC_ATTR_PARAM_BW_PCT,
645			                 tc_pct);
646			if (ret)
647				goto err_param;
648		}
649		nla_nest_end(skb, param_nest);
650	}
651
652	if (pg_tb[DCB_PG_ATTR_BW_ID_ALL])
653		getall = 1;
654	else
655		getall = 0;
656
657	for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) {
658		if (!getall && !pg_tb[i])
659			continue;
660
661		tc_pct = DCB_ATTR_VALUE_UNDEFINED;
662
663		if (dir) {
664			/* Rx */
665			netdev->dcbnl_ops->getpgbwgcfgrx(netdev,
666					i - DCB_PG_ATTR_BW_ID_0, &tc_pct);
667		} else {
668			/* Tx */
669			netdev->dcbnl_ops->getpgbwgcfgtx(netdev,
670					i - DCB_PG_ATTR_BW_ID_0, &tc_pct);
671		}
672		ret = nla_put_u8(skb, i, tc_pct);
673		if (ret)
674			goto err_pg;
675	}
676
677	nla_nest_end(skb, pg_nest);
678
679	return 0;
680
681err_param:
682	nla_nest_cancel(skb, param_nest);
683err_pg:
684	nla_nest_cancel(skb, pg_nest);
685
686	return -EMSGSIZE;
687}
688
689static int dcbnl_pgtx_getcfg(struct net_device *netdev, struct nlmsghdr *nlh,
690			     u32 seq, struct nlattr **tb, struct sk_buff *skb)
691{
692	return __dcbnl_pg_getcfg(netdev, nlh, tb, skb, 0);
693}
694
695static int dcbnl_pgrx_getcfg(struct net_device *netdev, struct nlmsghdr *nlh,
696			     u32 seq, struct nlattr **tb, struct sk_buff *skb)
697{
698	return __dcbnl_pg_getcfg(netdev, nlh, tb, skb, 1);
699}
700
701static int dcbnl_setstate(struct net_device *netdev, struct nlmsghdr *nlh,
702			  u32 seq, struct nlattr **tb, struct sk_buff *skb)
703{
704	u8 value;
705
706	if (!tb[DCB_ATTR_STATE])
707		return -EINVAL;
708
709	if (!netdev->dcbnl_ops->setstate)
710		return -EOPNOTSUPP;
711
712	value = nla_get_u8(tb[DCB_ATTR_STATE]);
713
714	return nla_put_u8(skb, DCB_ATTR_STATE,
715			  netdev->dcbnl_ops->setstate(netdev, value));
716}
717
718static int dcbnl_setpfccfg(struct net_device *netdev, struct nlmsghdr *nlh,
719			   u32 seq, struct nlattr **tb, struct sk_buff *skb)
720{
721	struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1];
722	int i;
723	int ret;
724	u8 value;
725
726	if (!tb[DCB_ATTR_PFC_CFG])
727		return -EINVAL;
728
729	if (!netdev->dcbnl_ops->setpfccfg)
730		return -EOPNOTSUPP;
731
732	ret = nla_parse_nested(data, DCB_PFC_UP_ATTR_MAX,
733	                       tb[DCB_ATTR_PFC_CFG],
734	                       dcbnl_pfc_up_nest);
735	if (ret)
736		return ret;
737
738	for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) {
739		if (data[i] == NULL)
740			continue;
741		value = nla_get_u8(data[i]);
742		netdev->dcbnl_ops->setpfccfg(netdev,
743			data[i]->nla_type - DCB_PFC_UP_ATTR_0, value);
744	}
745
746	return nla_put_u8(skb, DCB_ATTR_PFC_CFG, 0);
747}
748
749static int dcbnl_setall(struct net_device *netdev, struct nlmsghdr *nlh,
750			u32 seq, struct nlattr **tb, struct sk_buff *skb)
751{
752	int ret;
753
754	if (!tb[DCB_ATTR_SET_ALL])
755		return -EINVAL;
756
757	if (!netdev->dcbnl_ops->setall)
758		return -EOPNOTSUPP;
759
760	ret = nla_put_u8(skb, DCB_ATTR_SET_ALL,
761			 netdev->dcbnl_ops->setall(netdev));
762	dcbnl_cee_notify(netdev, RTM_SETDCB, DCB_CMD_SET_ALL, seq, 0);
763
764	return ret;
765}
766
767static int __dcbnl_pg_setcfg(struct net_device *netdev, struct nlmsghdr *nlh,
768			     u32 seq, struct nlattr **tb, struct sk_buff *skb,
769			     int dir)
770{
771	struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1];
772	struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1];
773	int ret;
774	int i;
775	u8 pgid;
776	u8 up_map;
777	u8 prio;
778	u8 tc_pct;
779
780	if (!tb[DCB_ATTR_PG_CFG])
781		return -EINVAL;
782
783	if (!netdev->dcbnl_ops->setpgtccfgtx ||
784	    !netdev->dcbnl_ops->setpgtccfgrx ||
785	    !netdev->dcbnl_ops->setpgbwgcfgtx ||
786	    !netdev->dcbnl_ops->setpgbwgcfgrx)
787		return -EOPNOTSUPP;
788
789	ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX,
790	                       tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest);
791	if (ret)
792		return ret;
793
794	for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) {
795		if (!pg_tb[i])
796			continue;
797
798		ret = nla_parse_nested(param_tb, DCB_TC_ATTR_PARAM_MAX,
799		                       pg_tb[i], dcbnl_tc_param_nest);
800		if (ret)
801			return ret;
802
803		pgid = DCB_ATTR_VALUE_UNDEFINED;
804		prio = DCB_ATTR_VALUE_UNDEFINED;
805		tc_pct = DCB_ATTR_VALUE_UNDEFINED;
806		up_map = DCB_ATTR_VALUE_UNDEFINED;
807
808		if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO])
809			prio =
810			    nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO]);
811
812		if (param_tb[DCB_TC_ATTR_PARAM_PGID])
813			pgid = nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_PGID]);
814
815		if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT])
816			tc_pct = nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_BW_PCT]);
817
818		if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING])
819			up_map =
820			     nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING]);
821
822		/* dir: Tx = 0, Rx = 1 */
823		if (dir) {
824			/* Rx */
825			netdev->dcbnl_ops->setpgtccfgrx(netdev,
826				i - DCB_PG_ATTR_TC_0,
827				prio, pgid, tc_pct, up_map);
828		} else {
829			/* Tx */
830			netdev->dcbnl_ops->setpgtccfgtx(netdev,
831				i - DCB_PG_ATTR_TC_0,
832				prio, pgid, tc_pct, up_map);
833		}
834	}
835
836	for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) {
837		if (!pg_tb[i])
838			continue;
839
840		tc_pct = nla_get_u8(pg_tb[i]);
841
842		/* dir: Tx = 0, Rx = 1 */
843		if (dir) {
844			/* Rx */
845			netdev->dcbnl_ops->setpgbwgcfgrx(netdev,
846					 i - DCB_PG_ATTR_BW_ID_0, tc_pct);
847		} else {
848			/* Tx */
849			netdev->dcbnl_ops->setpgbwgcfgtx(netdev,
850					 i - DCB_PG_ATTR_BW_ID_0, tc_pct);
851		}
852	}
853
854	return nla_put_u8(skb, DCB_ATTR_PG_CFG, 0);
855}
856
857static int dcbnl_pgtx_setcfg(struct net_device *netdev, struct nlmsghdr *nlh,
858			     u32 seq, struct nlattr **tb, struct sk_buff *skb)
859{
860	return __dcbnl_pg_setcfg(netdev, nlh, seq, tb, skb, 0);
861}
862
863static int dcbnl_pgrx_setcfg(struct net_device *netdev, struct nlmsghdr *nlh,
864			     u32 seq, struct nlattr **tb, struct sk_buff *skb)
865{
866	return __dcbnl_pg_setcfg(netdev, nlh, seq, tb, skb, 1);
867}
868
869static int dcbnl_bcn_getcfg(struct net_device *netdev, struct nlmsghdr *nlh,
870			    u32 seq, struct nlattr **tb, struct sk_buff *skb)
871{
872	struct nlattr *bcn_nest;
873	struct nlattr *bcn_tb[DCB_BCN_ATTR_MAX + 1];
874	u8 value_byte;
875	u32 value_integer;
876	int ret;
877	bool getall = false;
878	int i;
879
880	if (!tb[DCB_ATTR_BCN])
881		return -EINVAL;
882
883	if (!netdev->dcbnl_ops->getbcnrp ||
884	    !netdev->dcbnl_ops->getbcncfg)
885		return -EOPNOTSUPP;
886
887	ret = nla_parse_nested(bcn_tb, DCB_BCN_ATTR_MAX,
888	                       tb[DCB_ATTR_BCN], dcbnl_bcn_nest);
889	if (ret)
890		return ret;
891
892	bcn_nest = nla_nest_start(skb, DCB_ATTR_BCN);
893	if (!bcn_nest)
894		return -EMSGSIZE;
895
896	if (bcn_tb[DCB_BCN_ATTR_ALL])
897		getall = true;
898
899	for (i = DCB_BCN_ATTR_RP_0; i <= DCB_BCN_ATTR_RP_7; i++) {
900		if (!getall && !bcn_tb[i])
901			continue;
902
903		netdev->dcbnl_ops->getbcnrp(netdev, i - DCB_BCN_ATTR_RP_0,
904		                            &value_byte);
905		ret = nla_put_u8(skb, i, value_byte);
906		if (ret)
907			goto err_bcn;
908	}
909
910	for (i = DCB_BCN_ATTR_BCNA_0; i <= DCB_BCN_ATTR_RI; i++) {
911		if (!getall && !bcn_tb[i])
912			continue;
913
914		netdev->dcbnl_ops->getbcncfg(netdev, i,
915		                             &value_integer);
916		ret = nla_put_u32(skb, i, value_integer);
917		if (ret)
918			goto err_bcn;
919	}
920
921	nla_nest_end(skb, bcn_nest);
922
923	return 0;
924
925err_bcn:
926	nla_nest_cancel(skb, bcn_nest);
927	return ret;
928}
929
930static int dcbnl_bcn_setcfg(struct net_device *netdev, struct nlmsghdr *nlh,
931			    u32 seq, struct nlattr **tb, struct sk_buff *skb)
932{
933	struct nlattr *data[DCB_BCN_ATTR_MAX + 1];
934	int i;
935	int ret;
936	u8 value_byte;
937	u32 value_int;
938
939	if (!tb[DCB_ATTR_BCN])
940		return -EINVAL;
941
942	if (!netdev->dcbnl_ops->setbcncfg ||
943	    !netdev->dcbnl_ops->setbcnrp)
944		return -EOPNOTSUPP;
945
946	ret = nla_parse_nested(data, DCB_BCN_ATTR_MAX,
947	                       tb[DCB_ATTR_BCN],
948	                       dcbnl_pfc_up_nest);
949	if (ret)
950		return ret;
951
952	for (i = DCB_BCN_ATTR_RP_0; i <= DCB_BCN_ATTR_RP_7; i++) {
953		if (data[i] == NULL)
954			continue;
955		value_byte = nla_get_u8(data[i]);
956		netdev->dcbnl_ops->setbcnrp(netdev,
957			data[i]->nla_type - DCB_BCN_ATTR_RP_0, value_byte);
958	}
959
960	for (i = DCB_BCN_ATTR_BCNA_0; i <= DCB_BCN_ATTR_RI; i++) {
961		if (data[i] == NULL)
962			continue;
963		value_int = nla_get_u32(data[i]);
964		netdev->dcbnl_ops->setbcncfg(netdev,
965	                                     i, value_int);
966	}
967
968	return nla_put_u8(skb, DCB_ATTR_BCN, 0);
969}
970
971static int dcbnl_build_peer_app(struct net_device *netdev, struct sk_buff* skb,
972				int app_nested_type, int app_info_type,
973				int app_entry_type)
974{
975	struct dcb_peer_app_info info;
976	struct dcb_app *table = NULL;
977	const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
978	u16 app_count;
979	int err;
980
981
982	/**
983	 * retrieve the peer app configuration form the driver. If the driver
984	 * handlers fail exit without doing anything
985	 */
986	err = ops->peer_getappinfo(netdev, &info, &app_count);
987	if (!err && app_count) {
988		table = kmalloc(sizeof(struct dcb_app) * app_count, GFP_KERNEL);
989		if (!table)
990			return -ENOMEM;
991
992		err = ops->peer_getapptable(netdev, table);
993	}
994
995	if (!err) {
996		u16 i;
997		struct nlattr *app;
998
999		/**
1000		 * build the message, from here on the only possible failure
1001		 * is due to the skb size
1002		 */
1003		err = -EMSGSIZE;
1004
1005		app = nla_nest_start(skb, app_nested_type);
1006		if (!app)
1007			goto nla_put_failure;
1008
1009		if (app_info_type &&
1010		    nla_put(skb, app_info_type, sizeof(info), &info))
1011			goto nla_put_failure;
1012
1013		for (i = 0; i < app_count; i++) {
1014			if (nla_put(skb, app_entry_type, sizeof(struct dcb_app),
1015				    &table[i]))
1016				goto nla_put_failure;
1017		}
1018		nla_nest_end(skb, app);
1019	}
1020	err = 0;
1021
1022nla_put_failure:
1023	kfree(table);
1024	return err;
1025}
1026
1027/* Handle IEEE 802.1Qaz GET commands. */
1028static int dcbnl_ieee_fill(struct sk_buff *skb, struct net_device *netdev)
1029{
1030	struct nlattr *ieee, *app;
1031	struct dcb_app_type *itr;
1032	const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
1033	int dcbx;
1034	int err;
1035
1036	if (nla_put_string(skb, DCB_ATTR_IFNAME, netdev->name))
1037		return -EMSGSIZE;
1038
1039	ieee = nla_nest_start(skb, DCB_ATTR_IEEE);
1040	if (!ieee)
1041		return -EMSGSIZE;
1042
1043	if (ops->ieee_getets) {
1044		struct ieee_ets ets;
1045		err = ops->ieee_getets(netdev, &ets);
1046		if (!err &&
1047		    nla_put(skb, DCB_ATTR_IEEE_ETS, sizeof(ets), &ets))
1048			return -EMSGSIZE;
1049	}
1050
1051	if (ops->ieee_getmaxrate) {
1052		struct ieee_maxrate maxrate;
1053		err = ops->ieee_getmaxrate(netdev, &maxrate);
1054		if (!err) {
1055			err = nla_put(skb, DCB_ATTR_IEEE_MAXRATE,
1056				      sizeof(maxrate), &maxrate);
1057			if (err)
1058				return -EMSGSIZE;
1059		}
1060	}
1061
1062	if (ops->ieee_getpfc) {
1063		struct ieee_pfc pfc;
1064		err = ops->ieee_getpfc(netdev, &pfc);
1065		if (!err &&
1066		    nla_put(skb, DCB_ATTR_IEEE_PFC, sizeof(pfc), &pfc))
1067			return -EMSGSIZE;
1068	}
1069
1070	app = nla_nest_start(skb, DCB_ATTR_IEEE_APP_TABLE);
1071	if (!app)
1072		return -EMSGSIZE;
1073
1074	spin_lock(&dcb_lock);
1075	list_for_each_entry(itr, &dcb_app_list, list) {
1076		if (itr->ifindex == netdev->ifindex) {
1077			err = nla_put(skb, DCB_ATTR_IEEE_APP, sizeof(itr->app),
1078					 &itr->app);
1079			if (err) {
1080				spin_unlock(&dcb_lock);
1081				return -EMSGSIZE;
1082			}
1083		}
1084	}
1085
1086	if (netdev->dcbnl_ops->getdcbx)
1087		dcbx = netdev->dcbnl_ops->getdcbx(netdev);
1088	else
1089		dcbx = -EOPNOTSUPP;
1090
1091	spin_unlock(&dcb_lock);
1092	nla_nest_end(skb, app);
1093
1094	/* get peer info if available */
1095	if (ops->ieee_peer_getets) {
1096		struct ieee_ets ets;
1097		err = ops->ieee_peer_getets(netdev, &ets);
1098		if (!err &&
1099		    nla_put(skb, DCB_ATTR_IEEE_PEER_ETS, sizeof(ets), &ets))
1100			return -EMSGSIZE;
1101	}
1102
1103	if (ops->ieee_peer_getpfc) {
1104		struct ieee_pfc pfc;
1105		err = ops->ieee_peer_getpfc(netdev, &pfc);
1106		if (!err &&
1107		    nla_put(skb, DCB_ATTR_IEEE_PEER_PFC, sizeof(pfc), &pfc))
1108			return -EMSGSIZE;
1109	}
1110
1111	if (ops->peer_getappinfo && ops->peer_getapptable) {
1112		err = dcbnl_build_peer_app(netdev, skb,
1113					   DCB_ATTR_IEEE_PEER_APP,
1114					   DCB_ATTR_IEEE_APP_UNSPEC,
1115					   DCB_ATTR_IEEE_APP);
1116		if (err)
1117			return -EMSGSIZE;
1118	}
1119
1120	nla_nest_end(skb, ieee);
1121	if (dcbx >= 0) {
1122		err = nla_put_u8(skb, DCB_ATTR_DCBX, dcbx);
1123		if (err)
1124			return -EMSGSIZE;
1125	}
1126
1127	return 0;
1128}
1129
1130static int dcbnl_cee_pg_fill(struct sk_buff *skb, struct net_device *dev,
1131			     int dir)
1132{
1133	u8 pgid, up_map, prio, tc_pct;
1134	const struct dcbnl_rtnl_ops *ops = dev->dcbnl_ops;
1135	int i = dir ? DCB_ATTR_CEE_TX_PG : DCB_ATTR_CEE_RX_PG;
1136	struct nlattr *pg = nla_nest_start(skb, i);
1137
1138	if (!pg)
1139		return -EMSGSIZE;
1140
1141	for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) {
1142		struct nlattr *tc_nest = nla_nest_start(skb, i);
1143
1144		if (!tc_nest)
1145			return -EMSGSIZE;
1146
1147		pgid = DCB_ATTR_VALUE_UNDEFINED;
1148		prio = DCB_ATTR_VALUE_UNDEFINED;
1149		tc_pct = DCB_ATTR_VALUE_UNDEFINED;
1150		up_map = DCB_ATTR_VALUE_UNDEFINED;
1151
1152		if (!dir)
1153			ops->getpgtccfgrx(dev, i - DCB_PG_ATTR_TC_0,
1154					  &prio, &pgid, &tc_pct, &up_map);
1155		else
1156			ops->getpgtccfgtx(dev, i - DCB_PG_ATTR_TC_0,
1157					  &prio, &pgid, &tc_pct, &up_map);
1158
1159		if (nla_put_u8(skb, DCB_TC_ATTR_PARAM_PGID, pgid) ||
1160		    nla_put_u8(skb, DCB_TC_ATTR_PARAM_UP_MAPPING, up_map) ||
1161		    nla_put_u8(skb, DCB_TC_ATTR_PARAM_STRICT_PRIO, prio) ||
1162		    nla_put_u8(skb, DCB_TC_ATTR_PARAM_BW_PCT, tc_pct))
1163			return -EMSGSIZE;
1164		nla_nest_end(skb, tc_nest);
1165	}
1166
1167	for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) {
1168		tc_pct = DCB_ATTR_VALUE_UNDEFINED;
1169
1170		if (!dir)
1171			ops->getpgbwgcfgrx(dev, i - DCB_PG_ATTR_BW_ID_0,
1172					   &tc_pct);
1173		else
1174			ops->getpgbwgcfgtx(dev, i - DCB_PG_ATTR_BW_ID_0,
1175					   &tc_pct);
1176		if (nla_put_u8(skb, i, tc_pct))
1177			return -EMSGSIZE;
1178	}
1179	nla_nest_end(skb, pg);
1180	return 0;
1181}
1182
1183static int dcbnl_cee_fill(struct sk_buff *skb, struct net_device *netdev)
1184{
1185	struct nlattr *cee, *app;
1186	struct dcb_app_type *itr;
1187	const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
1188	int dcbx, i, err = -EMSGSIZE;
1189	u8 value;
1190
1191	if (nla_put_string(skb, DCB_ATTR_IFNAME, netdev->name))
1192		goto nla_put_failure;
1193	cee = nla_nest_start(skb, DCB_ATTR_CEE);
1194	if (!cee)
1195		goto nla_put_failure;
1196
1197	/* local pg */
1198	if (ops->getpgtccfgtx && ops->getpgbwgcfgtx) {
1199		err = dcbnl_cee_pg_fill(skb, netdev, 1);
1200		if (err)
1201			goto nla_put_failure;
1202	}
1203
1204	if (ops->getpgtccfgrx && ops->getpgbwgcfgrx) {
1205		err = dcbnl_cee_pg_fill(skb, netdev, 0);
1206		if (err)
1207			goto nla_put_failure;
1208	}
1209
1210	/* local pfc */
1211	if (ops->getpfccfg) {
1212		struct nlattr *pfc_nest = nla_nest_start(skb, DCB_ATTR_CEE_PFC);
1213
1214		if (!pfc_nest)
1215			goto nla_put_failure;
1216
1217		for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) {
1218			ops->getpfccfg(netdev, i - DCB_PFC_UP_ATTR_0, &value);
1219			if (nla_put_u8(skb, i, value))
1220				goto nla_put_failure;
1221		}
1222		nla_nest_end(skb, pfc_nest);
1223	}
1224
1225	/* local app */
1226	spin_lock(&dcb_lock);
1227	app = nla_nest_start(skb, DCB_ATTR_CEE_APP_TABLE);
1228	if (!app)
1229		goto dcb_unlock;
1230
1231	list_for_each_entry(itr, &dcb_app_list, list) {
1232		if (itr->ifindex == netdev->ifindex) {
1233			struct nlattr *app_nest = nla_nest_start(skb,
1234								 DCB_ATTR_APP);
1235			if (!app_nest)
1236				goto dcb_unlock;
1237
1238			err = nla_put_u8(skb, DCB_APP_ATTR_IDTYPE,
1239					 itr->app.selector);
1240			if (err)
1241				goto dcb_unlock;
1242
1243			err = nla_put_u16(skb, DCB_APP_ATTR_ID,
1244					  itr->app.protocol);
1245			if (err)
1246				goto dcb_unlock;
1247
1248			err = nla_put_u8(skb, DCB_APP_ATTR_PRIORITY,
1249					 itr->app.priority);
1250			if (err)
1251				goto dcb_unlock;
1252
1253			nla_nest_end(skb, app_nest);
1254		}
1255	}
1256	nla_nest_end(skb, app);
1257
1258	if (netdev->dcbnl_ops->getdcbx)
1259		dcbx = netdev->dcbnl_ops->getdcbx(netdev);
1260	else
1261		dcbx = -EOPNOTSUPP;
1262
1263	spin_unlock(&dcb_lock);
1264
1265	/* features flags */
1266	if (ops->getfeatcfg) {
1267		struct nlattr *feat = nla_nest_start(skb, DCB_ATTR_CEE_FEAT);
1268		if (!feat)
1269			goto nla_put_failure;
1270
1271		for (i = DCB_FEATCFG_ATTR_ALL + 1; i <= DCB_FEATCFG_ATTR_MAX;
1272		     i++)
1273			if (!ops->getfeatcfg(netdev, i, &value) &&
1274			    nla_put_u8(skb, i, value))
1275				goto nla_put_failure;
1276
1277		nla_nest_end(skb, feat);
1278	}
1279
1280	/* peer info if available */
1281	if (ops->cee_peer_getpg) {
1282		struct cee_pg pg;
1283		err = ops->cee_peer_getpg(netdev, &pg);
1284		if (!err &&
1285		    nla_put(skb, DCB_ATTR_CEE_PEER_PG, sizeof(pg), &pg))
1286			goto nla_put_failure;
1287	}
1288
1289	if (ops->cee_peer_getpfc) {
1290		struct cee_pfc pfc;
1291		err = ops->cee_peer_getpfc(netdev, &pfc);
1292		if (!err &&
1293		    nla_put(skb, DCB_ATTR_CEE_PEER_PFC, sizeof(pfc), &pfc))
1294			goto nla_put_failure;
1295	}
1296
1297	if (ops->peer_getappinfo && ops->peer_getapptable) {
1298		err = dcbnl_build_peer_app(netdev, skb,
1299					   DCB_ATTR_CEE_PEER_APP_TABLE,
1300					   DCB_ATTR_CEE_PEER_APP_INFO,
1301					   DCB_ATTR_CEE_PEER_APP);
1302		if (err)
1303			goto nla_put_failure;
1304	}
1305	nla_nest_end(skb, cee);
1306
1307	/* DCBX state */
1308	if (dcbx >= 0) {
1309		err = nla_put_u8(skb, DCB_ATTR_DCBX, dcbx);
1310		if (err)
1311			goto nla_put_failure;
1312	}
1313	return 0;
1314
1315dcb_unlock:
1316	spin_unlock(&dcb_lock);
1317nla_put_failure:
1318	return err;
1319}
1320
1321static int dcbnl_notify(struct net_device *dev, int event, int cmd,
1322			u32 seq, u32 portid, int dcbx_ver)
1323{
1324	struct net *net = dev_net(dev);
1325	struct sk_buff *skb;
1326	struct nlmsghdr *nlh;
1327	const struct dcbnl_rtnl_ops *ops = dev->dcbnl_ops;
1328	int err;
1329
1330	if (!ops)
1331		return -EOPNOTSUPP;
1332
1333	skb = dcbnl_newmsg(event, cmd, portid, seq, 0, &nlh);
1334	if (!skb)
1335		return -ENOBUFS;
1336
1337	if (dcbx_ver == DCB_CAP_DCBX_VER_IEEE)
1338		err = dcbnl_ieee_fill(skb, dev);
1339	else
1340		err = dcbnl_cee_fill(skb, dev);
1341
1342	if (err < 0) {
1343		/* Report error to broadcast listeners */
1344		nlmsg_free(skb);
1345		rtnl_set_sk_err(net, RTNLGRP_DCB, err);
1346	} else {
1347		/* End nlmsg and notify broadcast listeners */
1348		nlmsg_end(skb, nlh);
1349		rtnl_notify(skb, net, 0, RTNLGRP_DCB, NULL, GFP_KERNEL);
1350	}
1351
1352	return err;
1353}
1354
1355int dcbnl_ieee_notify(struct net_device *dev, int event, int cmd,
1356		      u32 seq, u32 portid)
1357{
1358	return dcbnl_notify(dev, event, cmd, seq, portid, DCB_CAP_DCBX_VER_IEEE);
1359}
1360EXPORT_SYMBOL(dcbnl_ieee_notify);
1361
1362int dcbnl_cee_notify(struct net_device *dev, int event, int cmd,
1363		     u32 seq, u32 portid)
1364{
1365	return dcbnl_notify(dev, event, cmd, seq, portid, DCB_CAP_DCBX_VER_CEE);
1366}
1367EXPORT_SYMBOL(dcbnl_cee_notify);
1368
1369/* Handle IEEE 802.1Qaz SET commands. If any requested operation can not
1370 * be completed the entire msg is aborted and error value is returned.
1371 * No attempt is made to reconcile the case where only part of the
1372 * cmd can be completed.
1373 */
1374static int dcbnl_ieee_set(struct net_device *netdev, struct nlmsghdr *nlh,
1375			  u32 seq, struct nlattr **tb, struct sk_buff *skb)
1376{
1377	const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
1378	struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1];
1379	int err;
1380
1381	if (!ops)
1382		return -EOPNOTSUPP;
1383
1384	if (!tb[DCB_ATTR_IEEE])
1385		return -EINVAL;
1386
1387	err = nla_parse_nested(ieee, DCB_ATTR_IEEE_MAX,
1388			       tb[DCB_ATTR_IEEE], dcbnl_ieee_policy);
1389	if (err)
1390		return err;
1391
1392	if (ieee[DCB_ATTR_IEEE_ETS] && ops->ieee_setets) {
1393		struct ieee_ets *ets = nla_data(ieee[DCB_ATTR_IEEE_ETS]);
1394		err = ops->ieee_setets(netdev, ets);
1395		if (err)
1396			goto err;
1397	}
1398
1399	if (ieee[DCB_ATTR_IEEE_MAXRATE] && ops->ieee_setmaxrate) {
1400		struct ieee_maxrate *maxrate =
1401			nla_data(ieee[DCB_ATTR_IEEE_MAXRATE]);
1402		err = ops->ieee_setmaxrate(netdev, maxrate);
1403		if (err)
1404			goto err;
1405	}
1406
1407	if (ieee[DCB_ATTR_IEEE_PFC] && ops->ieee_setpfc) {
1408		struct ieee_pfc *pfc = nla_data(ieee[DCB_ATTR_IEEE_PFC]);
1409		err = ops->ieee_setpfc(netdev, pfc);
1410		if (err)
1411			goto err;
1412	}
1413
1414	if (ieee[DCB_ATTR_IEEE_APP_TABLE]) {
1415		struct nlattr *attr;
1416		int rem;
1417
1418		nla_for_each_nested(attr, ieee[DCB_ATTR_IEEE_APP_TABLE], rem) {
1419			struct dcb_app *app_data;
1420			if (nla_type(attr) != DCB_ATTR_IEEE_APP)
1421				continue;
1422			app_data = nla_data(attr);
1423			if (ops->ieee_setapp)
1424				err = ops->ieee_setapp(netdev, app_data);
1425			else
1426				err = dcb_ieee_setapp(netdev, app_data);
1427			if (err)
1428				goto err;
1429		}
1430	}
1431
1432err:
1433	err = nla_put_u8(skb, DCB_ATTR_IEEE, err);
1434	dcbnl_ieee_notify(netdev, RTM_SETDCB, DCB_CMD_IEEE_SET, seq, 0);
1435	return err;
1436}
1437
1438static int dcbnl_ieee_get(struct net_device *netdev, struct nlmsghdr *nlh,
1439			  u32 seq, struct nlattr **tb, struct sk_buff *skb)
1440{
1441	const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
1442
1443	if (!ops)
1444		return -EOPNOTSUPP;
1445
1446	return dcbnl_ieee_fill(skb, netdev);
1447}
1448
1449static int dcbnl_ieee_del(struct net_device *netdev, struct nlmsghdr *nlh,
1450			  u32 seq, struct nlattr **tb, struct sk_buff *skb)
1451{
1452	const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
1453	struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1];
1454	int err;
1455
1456	if (!ops)
1457		return -EOPNOTSUPP;
1458
1459	if (!tb[DCB_ATTR_IEEE])
1460		return -EINVAL;
1461
1462	err = nla_parse_nested(ieee, DCB_ATTR_IEEE_MAX,
1463			       tb[DCB_ATTR_IEEE], dcbnl_ieee_policy);
1464	if (err)
1465		return err;
1466
1467	if (ieee[DCB_ATTR_IEEE_APP_TABLE]) {
1468		struct nlattr *attr;
1469		int rem;
1470
1471		nla_for_each_nested(attr, ieee[DCB_ATTR_IEEE_APP_TABLE], rem) {
1472			struct dcb_app *app_data;
1473
1474			if (nla_type(attr) != DCB_ATTR_IEEE_APP)
1475				continue;
1476			app_data = nla_data(attr);
1477			if (ops->ieee_delapp)
1478				err = ops->ieee_delapp(netdev, app_data);
1479			else
1480				err = dcb_ieee_delapp(netdev, app_data);
1481			if (err)
1482				goto err;
1483		}
1484	}
1485
1486err:
1487	err = nla_put_u8(skb, DCB_ATTR_IEEE, err);
1488	dcbnl_ieee_notify(netdev, RTM_SETDCB, DCB_CMD_IEEE_DEL, seq, 0);
1489	return err;
1490}
1491
1492
1493/* DCBX configuration */
1494static int dcbnl_getdcbx(struct net_device *netdev, struct nlmsghdr *nlh,
1495			 u32 seq, struct nlattr **tb, struct sk_buff *skb)
1496{
1497	if (!netdev->dcbnl_ops->getdcbx)
1498		return -EOPNOTSUPP;
1499
1500	return nla_put_u8(skb, DCB_ATTR_DCBX,
1501			  netdev->dcbnl_ops->getdcbx(netdev));
1502}
1503
1504static int dcbnl_setdcbx(struct net_device *netdev, struct nlmsghdr *nlh,
1505			 u32 seq, struct nlattr **tb, struct sk_buff *skb)
1506{
1507	u8 value;
1508
1509	if (!netdev->dcbnl_ops->setdcbx)
1510		return -EOPNOTSUPP;
1511
1512	if (!tb[DCB_ATTR_DCBX])
1513		return -EINVAL;
1514
1515	value = nla_get_u8(tb[DCB_ATTR_DCBX]);
1516
1517	return nla_put_u8(skb, DCB_ATTR_DCBX,
1518			  netdev->dcbnl_ops->setdcbx(netdev, value));
1519}
1520
1521static int dcbnl_getfeatcfg(struct net_device *netdev, struct nlmsghdr *nlh,
1522			    u32 seq, struct nlattr **tb, struct sk_buff *skb)
1523{
1524	struct nlattr *data[DCB_FEATCFG_ATTR_MAX + 1], *nest;
1525	u8 value;
1526	int ret, i;
1527	int getall = 0;
1528
1529	if (!netdev->dcbnl_ops->getfeatcfg)
1530		return -EOPNOTSUPP;
1531
1532	if (!tb[DCB_ATTR_FEATCFG])
1533		return -EINVAL;
1534
1535	ret = nla_parse_nested(data, DCB_FEATCFG_ATTR_MAX, tb[DCB_ATTR_FEATCFG],
1536			       dcbnl_featcfg_nest);
1537	if (ret)
1538		return ret;
1539
1540	nest = nla_nest_start(skb, DCB_ATTR_FEATCFG);
1541	if (!nest)
1542		return -EMSGSIZE;
1543
1544	if (data[DCB_FEATCFG_ATTR_ALL])
1545		getall = 1;
1546
1547	for (i = DCB_FEATCFG_ATTR_ALL+1; i <= DCB_FEATCFG_ATTR_MAX; i++) {
1548		if (!getall && !data[i])
1549			continue;
1550
1551		ret = netdev->dcbnl_ops->getfeatcfg(netdev, i, &value);
1552		if (!ret)
1553			ret = nla_put_u8(skb, i, value);
1554
1555		if (ret) {
1556			nla_nest_cancel(skb, nest);
1557			goto nla_put_failure;
1558		}
1559	}
1560	nla_nest_end(skb, nest);
1561
1562nla_put_failure:
1563	return ret;
1564}
1565
1566static int dcbnl_setfeatcfg(struct net_device *netdev, struct nlmsghdr *nlh,
1567			    u32 seq, struct nlattr **tb, struct sk_buff *skb)
1568{
1569	struct nlattr *data[DCB_FEATCFG_ATTR_MAX + 1];
1570	int ret, i;
1571	u8 value;
1572
1573	if (!netdev->dcbnl_ops->setfeatcfg)
1574		return -ENOTSUPP;
1575
1576	if (!tb[DCB_ATTR_FEATCFG])
1577		return -EINVAL;
1578
1579	ret = nla_parse_nested(data, DCB_FEATCFG_ATTR_MAX, tb[DCB_ATTR_FEATCFG],
1580			       dcbnl_featcfg_nest);
1581
1582	if (ret)
1583		goto err;
1584
1585	for (i = DCB_FEATCFG_ATTR_ALL+1; i <= DCB_FEATCFG_ATTR_MAX; i++) {
1586		if (data[i] == NULL)
1587			continue;
1588
1589		value = nla_get_u8(data[i]);
1590
1591		ret = netdev->dcbnl_ops->setfeatcfg(netdev, i, value);
1592
1593		if (ret)
1594			goto err;
1595	}
1596err:
1597	ret = nla_put_u8(skb, DCB_ATTR_FEATCFG, ret);
1598
1599	return ret;
1600}
1601
1602/* Handle CEE DCBX GET commands. */
1603static int dcbnl_cee_get(struct net_device *netdev, struct nlmsghdr *nlh,
1604			 u32 seq, struct nlattr **tb, struct sk_buff *skb)
1605{
1606	const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
1607
1608	if (!ops)
1609		return -EOPNOTSUPP;
1610
1611	return dcbnl_cee_fill(skb, netdev);
1612}
1613
1614struct reply_func {
1615	/* reply netlink message type */
1616	int	type;
1617
1618	/* function to fill message contents */
1619	int   (*cb)(struct net_device *, struct nlmsghdr *, u32,
1620		    struct nlattr **, struct sk_buff *);
1621};
1622
1623static const struct reply_func reply_funcs[DCB_CMD_MAX+1] = {
1624	[DCB_CMD_GSTATE]	= { RTM_GETDCB, dcbnl_getstate },
1625	[DCB_CMD_SSTATE]	= { RTM_SETDCB, dcbnl_setstate },
1626	[DCB_CMD_PFC_GCFG]	= { RTM_GETDCB, dcbnl_getpfccfg },
1627	[DCB_CMD_PFC_SCFG]	= { RTM_SETDCB, dcbnl_setpfccfg },
1628	[DCB_CMD_GPERM_HWADDR]	= { RTM_GETDCB, dcbnl_getperm_hwaddr },
1629	[DCB_CMD_GCAP]		= { RTM_GETDCB, dcbnl_getcap },
1630	[DCB_CMD_GNUMTCS]	= { RTM_GETDCB, dcbnl_getnumtcs },
1631	[DCB_CMD_SNUMTCS]	= { RTM_SETDCB, dcbnl_setnumtcs },
1632	[DCB_CMD_PFC_GSTATE]	= { RTM_GETDCB, dcbnl_getpfcstate },
1633	[DCB_CMD_PFC_SSTATE]	= { RTM_SETDCB, dcbnl_setpfcstate },
1634	[DCB_CMD_GAPP]		= { RTM_GETDCB, dcbnl_getapp },
1635	[DCB_CMD_SAPP]		= { RTM_SETDCB, dcbnl_setapp },
1636	[DCB_CMD_PGTX_GCFG]	= { RTM_GETDCB, dcbnl_pgtx_getcfg },
1637	[DCB_CMD_PGTX_SCFG]	= { RTM_SETDCB, dcbnl_pgtx_setcfg },
1638	[DCB_CMD_PGRX_GCFG]	= { RTM_GETDCB, dcbnl_pgrx_getcfg },
1639	[DCB_CMD_PGRX_SCFG]	= { RTM_SETDCB, dcbnl_pgrx_setcfg },
1640	[DCB_CMD_SET_ALL]	= { RTM_SETDCB, dcbnl_setall },
1641	[DCB_CMD_BCN_GCFG]	= { RTM_GETDCB, dcbnl_bcn_getcfg },
1642	[DCB_CMD_BCN_SCFG]	= { RTM_SETDCB, dcbnl_bcn_setcfg },
1643	[DCB_CMD_IEEE_GET]	= { RTM_GETDCB, dcbnl_ieee_get },
1644	[DCB_CMD_IEEE_SET]	= { RTM_SETDCB, dcbnl_ieee_set },
1645	[DCB_CMD_IEEE_DEL]	= { RTM_SETDCB, dcbnl_ieee_del },
1646	[DCB_CMD_GDCBX]		= { RTM_GETDCB, dcbnl_getdcbx },
1647	[DCB_CMD_SDCBX]		= { RTM_SETDCB, dcbnl_setdcbx },
1648	[DCB_CMD_GFEATCFG]	= { RTM_GETDCB, dcbnl_getfeatcfg },
1649	[DCB_CMD_SFEATCFG]	= { RTM_SETDCB, dcbnl_setfeatcfg },
1650	[DCB_CMD_CEE_GET]	= { RTM_GETDCB, dcbnl_cee_get },
1651};
1652
1653static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
1654{
1655	struct net *net = sock_net(skb->sk);
1656	struct net_device *netdev;
1657	struct dcbmsg *dcb = nlmsg_data(nlh);
1658	struct nlattr *tb[DCB_ATTR_MAX + 1];
1659	u32 portid = skb ? NETLINK_CB(skb).portid : 0;
1660	int ret = -EINVAL;
1661	struct sk_buff *reply_skb;
1662	struct nlmsghdr *reply_nlh = NULL;
1663	const struct reply_func *fn;
1664
1665	if ((nlh->nlmsg_type == RTM_SETDCB) && !capable(CAP_NET_ADMIN))
1666		return -EPERM;
1667
1668	ret = nlmsg_parse(nlh, sizeof(*dcb), tb, DCB_ATTR_MAX,
1669			  dcbnl_rtnl_policy);
1670	if (ret < 0)
1671		return ret;
1672
1673	if (dcb->cmd > DCB_CMD_MAX)
1674		return -EINVAL;
1675
1676	/* check if a reply function has been defined for the command */
1677	fn = &reply_funcs[dcb->cmd];
1678	if (!fn->cb)
1679		return -EOPNOTSUPP;
1680
1681	if (!tb[DCB_ATTR_IFNAME])
1682		return -EINVAL;
1683
1684	netdev = dev_get_by_name(net, nla_data(tb[DCB_ATTR_IFNAME]));
1685	if (!netdev)
1686		return -ENODEV;
1687
1688	if (!netdev->dcbnl_ops) {
1689		ret = -EOPNOTSUPP;
1690		goto out;
1691	}
1692
1693	reply_skb = dcbnl_newmsg(fn->type, dcb->cmd, portid, nlh->nlmsg_seq,
1694				 nlh->nlmsg_flags, &reply_nlh);
1695	if (!reply_skb) {
1696		ret = -ENOBUFS;
1697		goto out;
1698	}
1699
1700	ret = fn->cb(netdev, nlh, nlh->nlmsg_seq, tb, reply_skb);
1701	if (ret < 0) {
1702		nlmsg_free(reply_skb);
1703		goto out;
1704	}
1705
1706	nlmsg_end(reply_skb, reply_nlh);
1707
1708	ret = rtnl_unicast(reply_skb, net, portid);
1709out:
1710	dev_put(netdev);
1711	return ret;
1712}
1713
1714static struct dcb_app_type *dcb_app_lookup(const struct dcb_app *app,
1715					   int ifindex, int prio)
1716{
1717	struct dcb_app_type *itr;
1718
1719	list_for_each_entry(itr, &dcb_app_list, list) {
1720		if (itr->app.selector == app->selector &&
1721		    itr->app.protocol == app->protocol &&
1722		    itr->ifindex == ifindex &&
1723		    (!prio || itr->app.priority == prio))
1724			return itr;
1725	}
1726
1727	return NULL;
1728}
1729
1730static int dcb_app_add(const struct dcb_app *app, int ifindex)
1731{
1732	struct dcb_app_type *entry;
1733
1734	entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
1735	if (!entry)
1736		return -ENOMEM;
1737
1738	memcpy(&entry->app, app, sizeof(*app));
1739	entry->ifindex = ifindex;
1740	list_add(&entry->list, &dcb_app_list);
1741
1742	return 0;
1743}
1744
1745/**
1746 * dcb_getapp - retrieve the DCBX application user priority
1747 *
1748 * On success returns a non-zero 802.1p user priority bitmap
1749 * otherwise returns 0 as the invalid user priority bitmap to
1750 * indicate an error.
1751 */
1752u8 dcb_getapp(struct net_device *dev, struct dcb_app *app)
1753{
1754	struct dcb_app_type *itr;
1755	u8 prio = 0;
1756
1757	spin_lock(&dcb_lock);
1758	if ((itr = dcb_app_lookup(app, dev->ifindex, 0)))
1759		prio = itr->app.priority;
1760	spin_unlock(&dcb_lock);
1761
1762	return prio;
1763}
1764EXPORT_SYMBOL(dcb_getapp);
1765
1766/**
1767 * dcb_setapp - add CEE dcb application data to app list
1768 *
1769 * Priority 0 is an invalid priority in CEE spec. This routine
1770 * removes applications from the app list if the priority is
1771 * set to zero.
1772 */
1773int dcb_setapp(struct net_device *dev, struct dcb_app *new)
1774{
1775	struct dcb_app_type *itr;
1776	struct dcb_app_type event;
1777	int err = 0;
1778
1779	event.ifindex = dev->ifindex;
1780	memcpy(&event.app, new, sizeof(event.app));
1781	if (dev->dcbnl_ops->getdcbx)
1782		event.dcbx = dev->dcbnl_ops->getdcbx(dev);
1783
1784	spin_lock(&dcb_lock);
1785	/* Search for existing match and replace */
1786	if ((itr = dcb_app_lookup(new, dev->ifindex, 0))) {
1787		if (new->priority)
1788			itr->app.priority = new->priority;
1789		else {
1790			list_del(&itr->list);
1791			kfree(itr);
1792		}
1793		goto out;
1794	}
1795	/* App type does not exist add new application type */
1796	if (new->priority)
1797		err = dcb_app_add(new, dev->ifindex);
1798out:
1799	spin_unlock(&dcb_lock);
1800	if (!err)
1801		call_dcbevent_notifiers(DCB_APP_EVENT, &event);
1802	return err;
1803}
1804EXPORT_SYMBOL(dcb_setapp);
1805
1806/**
1807 * dcb_ieee_getapp_mask - retrieve the IEEE DCB application priority
1808 *
1809 * Helper routine which on success returns a non-zero 802.1Qaz user
1810 * priority bitmap otherwise returns 0 to indicate the dcb_app was
1811 * not found in APP list.
1812 */
1813u8 dcb_ieee_getapp_mask(struct net_device *dev, struct dcb_app *app)
1814{
1815	struct dcb_app_type *itr;
1816	u8 prio = 0;
1817
1818	spin_lock(&dcb_lock);
1819	if ((itr = dcb_app_lookup(app, dev->ifindex, 0)))
1820		prio |= 1 << itr->app.priority;
1821	spin_unlock(&dcb_lock);
1822
1823	return prio;
1824}
1825EXPORT_SYMBOL(dcb_ieee_getapp_mask);
1826
1827/**
1828 * dcb_ieee_setapp - add IEEE dcb application data to app list
1829 *
1830 * This adds Application data to the list. Multiple application
1831 * entries may exists for the same selector and protocol as long
1832 * as the priorities are different.
1833 */
1834int dcb_ieee_setapp(struct net_device *dev, struct dcb_app *new)
1835{
1836	struct dcb_app_type event;
1837	int err = 0;
1838
1839	event.ifindex = dev->ifindex;
1840	memcpy(&event.app, new, sizeof(event.app));
1841	if (dev->dcbnl_ops->getdcbx)
1842		event.dcbx = dev->dcbnl_ops->getdcbx(dev);
1843
1844	spin_lock(&dcb_lock);
1845	/* Search for existing match and abort if found */
1846	if (dcb_app_lookup(new, dev->ifindex, new->priority)) {
1847		err = -EEXIST;
1848		goto out;
1849	}
1850
1851	err = dcb_app_add(new, dev->ifindex);
1852out:
1853	spin_unlock(&dcb_lock);
1854	if (!err)
1855		call_dcbevent_notifiers(DCB_APP_EVENT, &event);
1856	return err;
1857}
1858EXPORT_SYMBOL(dcb_ieee_setapp);
1859
1860/**
1861 * dcb_ieee_delapp - delete IEEE dcb application data from list
1862 *
1863 * This removes a matching APP data from the APP list
1864 */
1865int dcb_ieee_delapp(struct net_device *dev, struct dcb_app *del)
1866{
1867	struct dcb_app_type *itr;
1868	struct dcb_app_type event;
1869	int err = -ENOENT;
1870
1871	event.ifindex = dev->ifindex;
1872	memcpy(&event.app, del, sizeof(event.app));
1873	if (dev->dcbnl_ops->getdcbx)
1874		event.dcbx = dev->dcbnl_ops->getdcbx(dev);
1875
1876	spin_lock(&dcb_lock);
1877	/* Search for existing match and remove it. */
1878	if ((itr = dcb_app_lookup(del, dev->ifindex, del->priority))) {
1879		list_del(&itr->list);
1880		kfree(itr);
1881		err = 0;
1882	}
1883
1884	spin_unlock(&dcb_lock);
1885	if (!err)
1886		call_dcbevent_notifiers(DCB_APP_EVENT, &event);
1887	return err;
1888}
1889EXPORT_SYMBOL(dcb_ieee_delapp);
1890
1891static void dcb_flushapp(void)
1892{
1893	struct dcb_app_type *app;
1894	struct dcb_app_type *tmp;
1895
1896	spin_lock(&dcb_lock);
1897	list_for_each_entry_safe(app, tmp, &dcb_app_list, list) {
1898		list_del(&app->list);
1899		kfree(app);
1900	}
1901	spin_unlock(&dcb_lock);
1902}
1903
1904static int __init dcbnl_init(void)
1905{
1906	INIT_LIST_HEAD(&dcb_app_list);
1907
1908	rtnl_register(PF_UNSPEC, RTM_GETDCB, dcb_doit, NULL, NULL);
1909	rtnl_register(PF_UNSPEC, RTM_SETDCB, dcb_doit, NULL, NULL);
1910
1911	return 0;
1912}
1913module_init(dcbnl_init);
1914
1915static void __exit dcbnl_exit(void)
1916{
1917	rtnl_unregister(PF_UNSPEC, RTM_GETDCB);
1918	rtnl_unregister(PF_UNSPEC, RTM_SETDCB);
1919	dcb_flushapp();
1920}
1921module_exit(dcbnl_exit);
1922