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