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