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