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