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