diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
commit | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (patch) | |
tree | a8f4d49d63b1ecc92f2fddceba0655b2472c5bd9 /net/dcb | |
parent | 406089d01562f1e2bf9f089fd7637009ebaad589 (diff) |
Patched in Tegra support.
Diffstat (limited to 'net/dcb')
-rw-r--r-- | net/dcb/dcbevent.c | 1 | ||||
-rw-r--r-- | net/dcb/dcbnl.c | 1279 |
2 files changed, 805 insertions, 475 deletions
diff --git a/net/dcb/dcbevent.c b/net/dcb/dcbevent.c index 1d9eb7c60a6..665a8802105 100644 --- a/net/dcb/dcbevent.c +++ b/net/dcb/dcbevent.c | |||
@@ -19,7 +19,6 @@ | |||
19 | 19 | ||
20 | #include <linux/rtnetlink.h> | 20 | #include <linux/rtnetlink.h> |
21 | #include <linux/notifier.h> | 21 | #include <linux/notifier.h> |
22 | #include <linux/export.h> | ||
23 | 22 | ||
24 | static ATOMIC_NOTIFIER_HEAD(dcbevent_notif_chain); | 23 | static ATOMIC_NOTIFIER_HEAD(dcbevent_notif_chain); |
25 | 24 | ||
diff --git a/net/dcb/dcbnl.c b/net/dcb/dcbnl.c index 1b588e23cf8..3cb56af4e13 100644 --- a/net/dcb/dcbnl.c +++ b/net/dcb/dcbnl.c | |||
@@ -25,10 +25,10 @@ | |||
25 | #include <linux/dcbnl.h> | 25 | #include <linux/dcbnl.h> |
26 | #include <net/dcbevent.h> | 26 | #include <net/dcbevent.h> |
27 | #include <linux/rtnetlink.h> | 27 | #include <linux/rtnetlink.h> |
28 | #include <linux/module.h> | ||
29 | #include <net/sock.h> | 28 | #include <net/sock.h> |
30 | 29 | ||
31 | /* Data Center Bridging (DCB) is a collection of Ethernet enhancements | 30 | /** |
31 | * Data Center Bridging (DCB) is a collection of Ethernet enhancements | ||
32 | * intended to allow network traffic with differing requirements | 32 | * intended to allow network traffic with differing requirements |
33 | * (highly reliable, no drops vs. best effort vs. low latency) to operate | 33 | * (highly reliable, no drops vs. best effort vs. low latency) to operate |
34 | * and co-exist on Ethernet. Current DCB features are: | 34 | * and co-exist on Ethernet. Current DCB features are: |
@@ -177,7 +177,6 @@ static const struct nla_policy dcbnl_ieee_policy[DCB_ATTR_IEEE_MAX + 1] = { | |||
177 | [DCB_ATTR_IEEE_ETS] = {.len = sizeof(struct ieee_ets)}, | 177 | [DCB_ATTR_IEEE_ETS] = {.len = sizeof(struct ieee_ets)}, |
178 | [DCB_ATTR_IEEE_PFC] = {.len = sizeof(struct ieee_pfc)}, | 178 | [DCB_ATTR_IEEE_PFC] = {.len = sizeof(struct ieee_pfc)}, |
179 | [DCB_ATTR_IEEE_APP_TABLE] = {.type = NLA_NESTED}, | 179 | [DCB_ATTR_IEEE_APP_TABLE] = {.type = NLA_NESTED}, |
180 | [DCB_ATTR_IEEE_MAXRATE] = {.len = sizeof(struct ieee_maxrate)}, | ||
181 | }; | 180 | }; |
182 | 181 | ||
183 | static const struct nla_policy dcbnl_ieee_app[DCB_ATTR_IEEE_APP_MAX + 1] = { | 182 | static const struct nla_policy dcbnl_ieee_app[DCB_ATTR_IEEE_APP_MAX + 1] = { |
@@ -195,66 +194,92 @@ static const struct nla_policy dcbnl_featcfg_nest[DCB_FEATCFG_ATTR_MAX + 1] = { | |||
195 | static LIST_HEAD(dcb_app_list); | 194 | static LIST_HEAD(dcb_app_list); |
196 | static DEFINE_SPINLOCK(dcb_lock); | 195 | static DEFINE_SPINLOCK(dcb_lock); |
197 | 196 | ||
198 | static struct sk_buff *dcbnl_newmsg(int type, u8 cmd, u32 port, u32 seq, | 197 | /* standard netlink reply call */ |
199 | u32 flags, struct nlmsghdr **nlhp) | 198 | static int dcbnl_reply(u8 value, u8 event, u8 cmd, u8 attr, u32 pid, |
199 | u32 seq, u16 flags) | ||
200 | { | 200 | { |
201 | struct sk_buff *skb; | 201 | struct sk_buff *dcbnl_skb; |
202 | struct dcbmsg *dcb; | 202 | struct dcbmsg *dcb; |
203 | struct nlmsghdr *nlh; | 203 | struct nlmsghdr *nlh; |
204 | int ret = -EINVAL; | ||
204 | 205 | ||
205 | skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 206 | dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
206 | if (!skb) | 207 | if (!dcbnl_skb) |
207 | return NULL; | 208 | return ret; |
208 | 209 | ||
209 | nlh = nlmsg_put(skb, port, seq, type, sizeof(*dcb), flags); | 210 | nlh = NLMSG_NEW(dcbnl_skb, pid, seq, event, sizeof(*dcb), flags); |
210 | BUG_ON(!nlh); | ||
211 | 211 | ||
212 | dcb = nlmsg_data(nlh); | 212 | dcb = NLMSG_DATA(nlh); |
213 | dcb->dcb_family = AF_UNSPEC; | 213 | dcb->dcb_family = AF_UNSPEC; |
214 | dcb->cmd = cmd; | 214 | dcb->cmd = cmd; |
215 | dcb->dcb_pad = 0; | 215 | dcb->dcb_pad = 0; |
216 | 216 | ||
217 | if (nlhp) | 217 | ret = nla_put_u8(dcbnl_skb, attr, value); |
218 | *nlhp = nlh; | 218 | if (ret) |
219 | goto err; | ||
219 | 220 | ||
220 | return skb; | 221 | /* end the message, assign the nlmsg_len. */ |
222 | nlmsg_end(dcbnl_skb, nlh); | ||
223 | ret = rtnl_unicast(dcbnl_skb, &init_net, pid); | ||
224 | if (ret) | ||
225 | return -EINVAL; | ||
226 | |||
227 | return 0; | ||
228 | nlmsg_failure: | ||
229 | err: | ||
230 | kfree_skb(dcbnl_skb); | ||
231 | return ret; | ||
221 | } | 232 | } |
222 | 233 | ||
223 | static int dcbnl_getstate(struct net_device *netdev, struct nlmsghdr *nlh, | 234 | static int dcbnl_getstate(struct net_device *netdev, struct nlattr **tb, |
224 | u32 seq, struct nlattr **tb, struct sk_buff *skb) | 235 | u32 pid, u32 seq, u16 flags) |
225 | { | 236 | { |
237 | int ret = -EINVAL; | ||
238 | |||
226 | /* if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->getstate) */ | 239 | /* if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->getstate) */ |
227 | if (!netdev->dcbnl_ops->getstate) | 240 | if (!netdev->dcbnl_ops->getstate) |
228 | return -EOPNOTSUPP; | 241 | return ret; |
242 | |||
243 | ret = dcbnl_reply(netdev->dcbnl_ops->getstate(netdev), RTM_GETDCB, | ||
244 | DCB_CMD_GSTATE, DCB_ATTR_STATE, pid, seq, flags); | ||
229 | 245 | ||
230 | return nla_put_u8(skb, DCB_ATTR_STATE, | 246 | return ret; |
231 | netdev->dcbnl_ops->getstate(netdev)); | ||
232 | } | 247 | } |
233 | 248 | ||
234 | static int dcbnl_getpfccfg(struct net_device *netdev, struct nlmsghdr *nlh, | 249 | static int dcbnl_getpfccfg(struct net_device *netdev, struct nlattr **tb, |
235 | u32 seq, struct nlattr **tb, struct sk_buff *skb) | 250 | u32 pid, u32 seq, u16 flags) |
236 | { | 251 | { |
252 | struct sk_buff *dcbnl_skb; | ||
253 | struct nlmsghdr *nlh; | ||
254 | struct dcbmsg *dcb; | ||
237 | struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1], *nest; | 255 | struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1], *nest; |
238 | u8 value; | 256 | u8 value; |
239 | int ret; | 257 | int ret = -EINVAL; |
240 | int i; | 258 | int i; |
241 | int getall = 0; | 259 | int getall = 0; |
242 | 260 | ||
243 | if (!tb[DCB_ATTR_PFC_CFG]) | 261 | if (!tb[DCB_ATTR_PFC_CFG] || !netdev->dcbnl_ops->getpfccfg) |
244 | return -EINVAL; | 262 | return ret; |
245 | |||
246 | if (!netdev->dcbnl_ops->getpfccfg) | ||
247 | return -EOPNOTSUPP; | ||
248 | 263 | ||
249 | ret = nla_parse_nested(data, DCB_PFC_UP_ATTR_MAX, | 264 | ret = nla_parse_nested(data, DCB_PFC_UP_ATTR_MAX, |
250 | tb[DCB_ATTR_PFC_CFG], | 265 | tb[DCB_ATTR_PFC_CFG], |
251 | dcbnl_pfc_up_nest); | 266 | dcbnl_pfc_up_nest); |
252 | if (ret) | 267 | if (ret) |
253 | return ret; | 268 | goto err_out; |
254 | 269 | ||
255 | nest = nla_nest_start(skb, DCB_ATTR_PFC_CFG); | 270 | dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
271 | if (!dcbnl_skb) | ||
272 | goto err_out; | ||
273 | |||
274 | nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); | ||
275 | |||
276 | dcb = NLMSG_DATA(nlh); | ||
277 | dcb->dcb_family = AF_UNSPEC; | ||
278 | dcb->cmd = DCB_CMD_PFC_GCFG; | ||
279 | |||
280 | nest = nla_nest_start(dcbnl_skb, DCB_ATTR_PFC_CFG); | ||
256 | if (!nest) | 281 | if (!nest) |
257 | return -EMSGSIZE; | 282 | goto err; |
258 | 283 | ||
259 | if (data[DCB_PFC_UP_ATTR_ALL]) | 284 | if (data[DCB_PFC_UP_ATTR_ALL]) |
260 | getall = 1; | 285 | getall = 1; |
@@ -265,53 +290,103 @@ static int dcbnl_getpfccfg(struct net_device *netdev, struct nlmsghdr *nlh, | |||
265 | 290 | ||
266 | netdev->dcbnl_ops->getpfccfg(netdev, i - DCB_PFC_UP_ATTR_0, | 291 | netdev->dcbnl_ops->getpfccfg(netdev, i - DCB_PFC_UP_ATTR_0, |
267 | &value); | 292 | &value); |
268 | ret = nla_put_u8(skb, i, value); | 293 | ret = nla_put_u8(dcbnl_skb, i, value); |
294 | |||
269 | if (ret) { | 295 | if (ret) { |
270 | nla_nest_cancel(skb, nest); | 296 | nla_nest_cancel(dcbnl_skb, nest); |
271 | return ret; | 297 | goto err; |
272 | } | 298 | } |
273 | } | 299 | } |
274 | nla_nest_end(skb, nest); | 300 | nla_nest_end(dcbnl_skb, nest); |
301 | |||
302 | nlmsg_end(dcbnl_skb, nlh); | ||
303 | |||
304 | ret = rtnl_unicast(dcbnl_skb, &init_net, pid); | ||
305 | if (ret) | ||
306 | goto err_out; | ||
275 | 307 | ||
276 | return 0; | 308 | return 0; |
309 | nlmsg_failure: | ||
310 | err: | ||
311 | kfree_skb(dcbnl_skb); | ||
312 | err_out: | ||
313 | return -EINVAL; | ||
277 | } | 314 | } |
278 | 315 | ||
279 | static int dcbnl_getperm_hwaddr(struct net_device *netdev, struct nlmsghdr *nlh, | 316 | static int dcbnl_getperm_hwaddr(struct net_device *netdev, struct nlattr **tb, |
280 | u32 seq, struct nlattr **tb, struct sk_buff *skb) | 317 | u32 pid, u32 seq, u16 flags) |
281 | { | 318 | { |
319 | struct sk_buff *dcbnl_skb; | ||
320 | struct nlmsghdr *nlh; | ||
321 | struct dcbmsg *dcb; | ||
282 | u8 perm_addr[MAX_ADDR_LEN]; | 322 | u8 perm_addr[MAX_ADDR_LEN]; |
323 | int ret = -EINVAL; | ||
283 | 324 | ||
284 | if (!netdev->dcbnl_ops->getpermhwaddr) | 325 | if (!netdev->dcbnl_ops->getpermhwaddr) |
285 | return -EOPNOTSUPP; | 326 | return ret; |
327 | |||
328 | dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
329 | if (!dcbnl_skb) | ||
330 | goto err_out; | ||
331 | |||
332 | nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); | ||
333 | |||
334 | dcb = NLMSG_DATA(nlh); | ||
335 | dcb->dcb_family = AF_UNSPEC; | ||
336 | dcb->cmd = DCB_CMD_GPERM_HWADDR; | ||
286 | 337 | ||
287 | netdev->dcbnl_ops->getpermhwaddr(netdev, perm_addr); | 338 | netdev->dcbnl_ops->getpermhwaddr(netdev, perm_addr); |
288 | 339 | ||
289 | return nla_put(skb, DCB_ATTR_PERM_HWADDR, sizeof(perm_addr), perm_addr); | 340 | ret = nla_put(dcbnl_skb, DCB_ATTR_PERM_HWADDR, sizeof(perm_addr), |
341 | perm_addr); | ||
342 | |||
343 | nlmsg_end(dcbnl_skb, nlh); | ||
344 | |||
345 | ret = rtnl_unicast(dcbnl_skb, &init_net, pid); | ||
346 | if (ret) | ||
347 | goto err_out; | ||
348 | |||
349 | return 0; | ||
350 | |||
351 | nlmsg_failure: | ||
352 | kfree_skb(dcbnl_skb); | ||
353 | err_out: | ||
354 | return -EINVAL; | ||
290 | } | 355 | } |
291 | 356 | ||
292 | static int dcbnl_getcap(struct net_device *netdev, struct nlmsghdr *nlh, | 357 | static int dcbnl_getcap(struct net_device *netdev, struct nlattr **tb, |
293 | u32 seq, struct nlattr **tb, struct sk_buff *skb) | 358 | u32 pid, u32 seq, u16 flags) |
294 | { | 359 | { |
360 | struct sk_buff *dcbnl_skb; | ||
361 | struct nlmsghdr *nlh; | ||
362 | struct dcbmsg *dcb; | ||
295 | struct nlattr *data[DCB_CAP_ATTR_MAX + 1], *nest; | 363 | struct nlattr *data[DCB_CAP_ATTR_MAX + 1], *nest; |
296 | u8 value; | 364 | u8 value; |
297 | int ret; | 365 | int ret = -EINVAL; |
298 | int i; | 366 | int i; |
299 | int getall = 0; | 367 | int getall = 0; |
300 | 368 | ||
301 | if (!tb[DCB_ATTR_CAP]) | 369 | if (!tb[DCB_ATTR_CAP] || !netdev->dcbnl_ops->getcap) |
302 | return -EINVAL; | 370 | return ret; |
303 | |||
304 | if (!netdev->dcbnl_ops->getcap) | ||
305 | return -EOPNOTSUPP; | ||
306 | 371 | ||
307 | ret = nla_parse_nested(data, DCB_CAP_ATTR_MAX, tb[DCB_ATTR_CAP], | 372 | ret = nla_parse_nested(data, DCB_CAP_ATTR_MAX, tb[DCB_ATTR_CAP], |
308 | dcbnl_cap_nest); | 373 | dcbnl_cap_nest); |
309 | if (ret) | 374 | if (ret) |
310 | return ret; | 375 | goto err_out; |
376 | |||
377 | dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
378 | if (!dcbnl_skb) | ||
379 | goto err_out; | ||
311 | 380 | ||
312 | nest = nla_nest_start(skb, DCB_ATTR_CAP); | 381 | nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); |
382 | |||
383 | dcb = NLMSG_DATA(nlh); | ||
384 | dcb->dcb_family = AF_UNSPEC; | ||
385 | dcb->cmd = DCB_CMD_GCAP; | ||
386 | |||
387 | nest = nla_nest_start(dcbnl_skb, DCB_ATTR_CAP); | ||
313 | if (!nest) | 388 | if (!nest) |
314 | return -EMSGSIZE; | 389 | goto err; |
315 | 390 | ||
316 | if (data[DCB_CAP_ATTR_ALL]) | 391 | if (data[DCB_CAP_ATTR_ALL]) |
317 | getall = 1; | 392 | getall = 1; |
@@ -321,41 +396,69 @@ static int dcbnl_getcap(struct net_device *netdev, struct nlmsghdr *nlh, | |||
321 | continue; | 396 | continue; |
322 | 397 | ||
323 | if (!netdev->dcbnl_ops->getcap(netdev, i, &value)) { | 398 | if (!netdev->dcbnl_ops->getcap(netdev, i, &value)) { |
324 | ret = nla_put_u8(skb, i, value); | 399 | ret = nla_put_u8(dcbnl_skb, i, value); |
400 | |||
325 | if (ret) { | 401 | if (ret) { |
326 | nla_nest_cancel(skb, nest); | 402 | nla_nest_cancel(dcbnl_skb, nest); |
327 | return ret; | 403 | goto err; |
328 | } | 404 | } |
329 | } | 405 | } |
330 | } | 406 | } |
331 | nla_nest_end(skb, nest); | 407 | nla_nest_end(dcbnl_skb, nest); |
408 | |||
409 | nlmsg_end(dcbnl_skb, nlh); | ||
410 | |||
411 | ret = rtnl_unicast(dcbnl_skb, &init_net, pid); | ||
412 | if (ret) | ||
413 | goto err_out; | ||
332 | 414 | ||
333 | return 0; | 415 | return 0; |
416 | nlmsg_failure: | ||
417 | err: | ||
418 | kfree_skb(dcbnl_skb); | ||
419 | err_out: | ||
420 | return -EINVAL; | ||
334 | } | 421 | } |
335 | 422 | ||
336 | static int dcbnl_getnumtcs(struct net_device *netdev, struct nlmsghdr *nlh, | 423 | static int dcbnl_getnumtcs(struct net_device *netdev, struct nlattr **tb, |
337 | u32 seq, struct nlattr **tb, struct sk_buff *skb) | 424 | u32 pid, u32 seq, u16 flags) |
338 | { | 425 | { |
426 | struct sk_buff *dcbnl_skb; | ||
427 | struct nlmsghdr *nlh; | ||
428 | struct dcbmsg *dcb; | ||
339 | struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1], *nest; | 429 | struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1], *nest; |
340 | u8 value; | 430 | u8 value; |
341 | int ret; | 431 | int ret = -EINVAL; |
342 | int i; | 432 | int i; |
343 | int getall = 0; | 433 | int getall = 0; |
344 | 434 | ||
345 | if (!tb[DCB_ATTR_NUMTCS]) | 435 | if (!tb[DCB_ATTR_NUMTCS] || !netdev->dcbnl_ops->getnumtcs) |
346 | return -EINVAL; | 436 | return ret; |
347 | |||
348 | if (!netdev->dcbnl_ops->getnumtcs) | ||
349 | return -EOPNOTSUPP; | ||
350 | 437 | ||
351 | ret = nla_parse_nested(data, DCB_NUMTCS_ATTR_MAX, tb[DCB_ATTR_NUMTCS], | 438 | ret = nla_parse_nested(data, DCB_NUMTCS_ATTR_MAX, tb[DCB_ATTR_NUMTCS], |
352 | dcbnl_numtcs_nest); | 439 | dcbnl_numtcs_nest); |
353 | if (ret) | 440 | if (ret) { |
354 | return ret; | 441 | ret = -EINVAL; |
442 | goto err_out; | ||
443 | } | ||
355 | 444 | ||
356 | nest = nla_nest_start(skb, DCB_ATTR_NUMTCS); | 445 | dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
357 | if (!nest) | 446 | if (!dcbnl_skb) { |
358 | return -EMSGSIZE; | 447 | ret = -EINVAL; |
448 | goto err_out; | ||
449 | } | ||
450 | |||
451 | nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); | ||
452 | |||
453 | dcb = NLMSG_DATA(nlh); | ||
454 | dcb->dcb_family = AF_UNSPEC; | ||
455 | dcb->cmd = DCB_CMD_GNUMTCS; | ||
456 | |||
457 | nest = nla_nest_start(dcbnl_skb, DCB_ATTR_NUMTCS); | ||
458 | if (!nest) { | ||
459 | ret = -EINVAL; | ||
460 | goto err; | ||
461 | } | ||
359 | 462 | ||
360 | if (data[DCB_NUMTCS_ATTR_ALL]) | 463 | if (data[DCB_NUMTCS_ATTR_ALL]) |
361 | getall = 1; | 464 | getall = 1; |
@@ -366,37 +469,53 @@ static int dcbnl_getnumtcs(struct net_device *netdev, struct nlmsghdr *nlh, | |||
366 | 469 | ||
367 | ret = netdev->dcbnl_ops->getnumtcs(netdev, i, &value); | 470 | ret = netdev->dcbnl_ops->getnumtcs(netdev, i, &value); |
368 | if (!ret) { | 471 | if (!ret) { |
369 | ret = nla_put_u8(skb, i, value); | 472 | ret = nla_put_u8(dcbnl_skb, i, value); |
473 | |||
370 | if (ret) { | 474 | if (ret) { |
371 | nla_nest_cancel(skb, nest); | 475 | nla_nest_cancel(dcbnl_skb, nest); |
372 | return ret; | 476 | ret = -EINVAL; |
477 | goto err; | ||
373 | } | 478 | } |
374 | } else | 479 | } else { |
375 | return -EINVAL; | 480 | goto err; |
481 | } | ||
482 | } | ||
483 | nla_nest_end(dcbnl_skb, nest); | ||
484 | |||
485 | nlmsg_end(dcbnl_skb, nlh); | ||
486 | |||
487 | ret = rtnl_unicast(dcbnl_skb, &init_net, pid); | ||
488 | if (ret) { | ||
489 | ret = -EINVAL; | ||
490 | goto err_out; | ||
376 | } | 491 | } |
377 | nla_nest_end(skb, nest); | ||
378 | 492 | ||
379 | return 0; | 493 | return 0; |
494 | nlmsg_failure: | ||
495 | err: | ||
496 | kfree_skb(dcbnl_skb); | ||
497 | err_out: | ||
498 | return ret; | ||
380 | } | 499 | } |
381 | 500 | ||
382 | static int dcbnl_setnumtcs(struct net_device *netdev, struct nlmsghdr *nlh, | 501 | static int dcbnl_setnumtcs(struct net_device *netdev, struct nlattr **tb, |
383 | u32 seq, struct nlattr **tb, struct sk_buff *skb) | 502 | u32 pid, u32 seq, u16 flags) |
384 | { | 503 | { |
385 | struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1]; | 504 | struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1]; |
386 | int ret; | 505 | int ret = -EINVAL; |
387 | u8 value; | 506 | u8 value; |
388 | int i; | 507 | int i; |
389 | 508 | ||
390 | if (!tb[DCB_ATTR_NUMTCS]) | 509 | if (!tb[DCB_ATTR_NUMTCS] || !netdev->dcbnl_ops->setnumtcs) |
391 | return -EINVAL; | 510 | return ret; |
392 | |||
393 | if (!netdev->dcbnl_ops->setnumtcs) | ||
394 | return -EOPNOTSUPP; | ||
395 | 511 | ||
396 | ret = nla_parse_nested(data, DCB_NUMTCS_ATTR_MAX, tb[DCB_ATTR_NUMTCS], | 512 | ret = nla_parse_nested(data, DCB_NUMTCS_ATTR_MAX, tb[DCB_ATTR_NUMTCS], |
397 | dcbnl_numtcs_nest); | 513 | dcbnl_numtcs_nest); |
398 | if (ret) | 514 | |
399 | return ret; | 515 | if (ret) { |
516 | ret = -EINVAL; | ||
517 | goto err; | ||
518 | } | ||
400 | 519 | ||
401 | for (i = DCB_NUMTCS_ATTR_ALL+1; i <= DCB_NUMTCS_ATTR_MAX; i++) { | 520 | for (i = DCB_NUMTCS_ATTR_ALL+1; i <= DCB_NUMTCS_ATTR_MAX; i++) { |
402 | if (data[i] == NULL) | 521 | if (data[i] == NULL) |
@@ -405,68 +524,84 @@ static int dcbnl_setnumtcs(struct net_device *netdev, struct nlmsghdr *nlh, | |||
405 | value = nla_get_u8(data[i]); | 524 | value = nla_get_u8(data[i]); |
406 | 525 | ||
407 | ret = netdev->dcbnl_ops->setnumtcs(netdev, i, value); | 526 | ret = netdev->dcbnl_ops->setnumtcs(netdev, i, value); |
527 | |||
408 | if (ret) | 528 | if (ret) |
409 | break; | 529 | goto operr; |
410 | } | 530 | } |
411 | 531 | ||
412 | return nla_put_u8(skb, DCB_ATTR_NUMTCS, !!ret); | 532 | operr: |
533 | ret = dcbnl_reply(!!ret, RTM_SETDCB, DCB_CMD_SNUMTCS, | ||
534 | DCB_ATTR_NUMTCS, pid, seq, flags); | ||
535 | |||
536 | err: | ||
537 | return ret; | ||
413 | } | 538 | } |
414 | 539 | ||
415 | static int dcbnl_getpfcstate(struct net_device *netdev, struct nlmsghdr *nlh, | 540 | static int dcbnl_getpfcstate(struct net_device *netdev, struct nlattr **tb, |
416 | u32 seq, struct nlattr **tb, struct sk_buff *skb) | 541 | u32 pid, u32 seq, u16 flags) |
417 | { | 542 | { |
543 | int ret = -EINVAL; | ||
544 | |||
418 | if (!netdev->dcbnl_ops->getpfcstate) | 545 | if (!netdev->dcbnl_ops->getpfcstate) |
419 | return -EOPNOTSUPP; | 546 | return ret; |
547 | |||
548 | ret = dcbnl_reply(netdev->dcbnl_ops->getpfcstate(netdev), RTM_GETDCB, | ||
549 | DCB_CMD_PFC_GSTATE, DCB_ATTR_PFC_STATE, | ||
550 | pid, seq, flags); | ||
420 | 551 | ||
421 | return nla_put_u8(skb, DCB_ATTR_PFC_STATE, | 552 | return ret; |
422 | netdev->dcbnl_ops->getpfcstate(netdev)); | ||
423 | } | 553 | } |
424 | 554 | ||
425 | static int dcbnl_setpfcstate(struct net_device *netdev, struct nlmsghdr *nlh, | 555 | static int dcbnl_setpfcstate(struct net_device *netdev, struct nlattr **tb, |
426 | u32 seq, struct nlattr **tb, struct sk_buff *skb) | 556 | u32 pid, u32 seq, u16 flags) |
427 | { | 557 | { |
558 | int ret = -EINVAL; | ||
428 | u8 value; | 559 | u8 value; |
429 | 560 | ||
430 | if (!tb[DCB_ATTR_PFC_STATE]) | 561 | if (!tb[DCB_ATTR_PFC_STATE] || !netdev->dcbnl_ops->setpfcstate) |
431 | return -EINVAL; | 562 | return ret; |
432 | |||
433 | if (!netdev->dcbnl_ops->setpfcstate) | ||
434 | return -EOPNOTSUPP; | ||
435 | 563 | ||
436 | value = nla_get_u8(tb[DCB_ATTR_PFC_STATE]); | 564 | value = nla_get_u8(tb[DCB_ATTR_PFC_STATE]); |
437 | 565 | ||
438 | netdev->dcbnl_ops->setpfcstate(netdev, value); | 566 | netdev->dcbnl_ops->setpfcstate(netdev, value); |
439 | 567 | ||
440 | return nla_put_u8(skb, DCB_ATTR_PFC_STATE, 0); | 568 | ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_PFC_SSTATE, DCB_ATTR_PFC_STATE, |
569 | pid, seq, flags); | ||
570 | |||
571 | return ret; | ||
441 | } | 572 | } |
442 | 573 | ||
443 | static int dcbnl_getapp(struct net_device *netdev, struct nlmsghdr *nlh, | 574 | static int dcbnl_getapp(struct net_device *netdev, struct nlattr **tb, |
444 | u32 seq, struct nlattr **tb, struct sk_buff *skb) | 575 | u32 pid, u32 seq, u16 flags) |
445 | { | 576 | { |
577 | struct sk_buff *dcbnl_skb; | ||
578 | struct nlmsghdr *nlh; | ||
579 | struct dcbmsg *dcb; | ||
446 | struct nlattr *app_nest; | 580 | struct nlattr *app_nest; |
447 | struct nlattr *app_tb[DCB_APP_ATTR_MAX + 1]; | 581 | struct nlattr *app_tb[DCB_APP_ATTR_MAX + 1]; |
448 | u16 id; | 582 | u16 id; |
449 | u8 up, idtype; | 583 | u8 up, idtype; |
450 | int ret; | 584 | int ret = -EINVAL; |
451 | 585 | ||
452 | if (!tb[DCB_ATTR_APP]) | 586 | if (!tb[DCB_ATTR_APP]) |
453 | return -EINVAL; | 587 | goto out; |
454 | 588 | ||
455 | ret = nla_parse_nested(app_tb, DCB_APP_ATTR_MAX, tb[DCB_ATTR_APP], | 589 | ret = nla_parse_nested(app_tb, DCB_APP_ATTR_MAX, tb[DCB_ATTR_APP], |
456 | dcbnl_app_nest); | 590 | dcbnl_app_nest); |
457 | if (ret) | 591 | if (ret) |
458 | return ret; | 592 | goto out; |
459 | 593 | ||
594 | ret = -EINVAL; | ||
460 | /* all must be non-null */ | 595 | /* all must be non-null */ |
461 | if ((!app_tb[DCB_APP_ATTR_IDTYPE]) || | 596 | if ((!app_tb[DCB_APP_ATTR_IDTYPE]) || |
462 | (!app_tb[DCB_APP_ATTR_ID])) | 597 | (!app_tb[DCB_APP_ATTR_ID])) |
463 | return -EINVAL; | 598 | goto out; |
464 | 599 | ||
465 | /* either by eth type or by socket number */ | 600 | /* either by eth type or by socket number */ |
466 | idtype = nla_get_u8(app_tb[DCB_APP_ATTR_IDTYPE]); | 601 | idtype = nla_get_u8(app_tb[DCB_APP_ATTR_IDTYPE]); |
467 | if ((idtype != DCB_APP_IDTYPE_ETHTYPE) && | 602 | if ((idtype != DCB_APP_IDTYPE_ETHTYPE) && |
468 | (idtype != DCB_APP_IDTYPE_PORTNUM)) | 603 | (idtype != DCB_APP_IDTYPE_PORTNUM)) |
469 | return -EINVAL; | 604 | goto out; |
470 | 605 | ||
471 | id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]); | 606 | id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]); |
472 | 607 | ||
@@ -480,106 +615,137 @@ static int dcbnl_getapp(struct net_device *netdev, struct nlmsghdr *nlh, | |||
480 | up = dcb_getapp(netdev, &app); | 615 | up = dcb_getapp(netdev, &app); |
481 | } | 616 | } |
482 | 617 | ||
483 | app_nest = nla_nest_start(skb, DCB_ATTR_APP); | 618 | /* send this back */ |
619 | dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
620 | if (!dcbnl_skb) | ||
621 | goto out; | ||
622 | |||
623 | nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); | ||
624 | dcb = NLMSG_DATA(nlh); | ||
625 | dcb->dcb_family = AF_UNSPEC; | ||
626 | dcb->cmd = DCB_CMD_GAPP; | ||
627 | |||
628 | app_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_APP); | ||
484 | if (!app_nest) | 629 | if (!app_nest) |
485 | return -EMSGSIZE; | 630 | goto out_cancel; |
486 | 631 | ||
487 | ret = nla_put_u8(skb, DCB_APP_ATTR_IDTYPE, idtype); | 632 | ret = nla_put_u8(dcbnl_skb, DCB_APP_ATTR_IDTYPE, idtype); |
488 | if (ret) | 633 | if (ret) |
489 | goto out_cancel; | 634 | goto out_cancel; |
490 | 635 | ||
491 | ret = nla_put_u16(skb, DCB_APP_ATTR_ID, id); | 636 | ret = nla_put_u16(dcbnl_skb, DCB_APP_ATTR_ID, id); |
492 | if (ret) | 637 | if (ret) |
493 | goto out_cancel; | 638 | goto out_cancel; |
494 | 639 | ||
495 | ret = nla_put_u8(skb, DCB_APP_ATTR_PRIORITY, up); | 640 | ret = nla_put_u8(dcbnl_skb, DCB_APP_ATTR_PRIORITY, up); |
496 | if (ret) | 641 | if (ret) |
497 | goto out_cancel; | 642 | goto out_cancel; |
498 | 643 | ||
499 | nla_nest_end(skb, app_nest); | 644 | nla_nest_end(dcbnl_skb, app_nest); |
645 | nlmsg_end(dcbnl_skb, nlh); | ||
500 | 646 | ||
501 | return 0; | 647 | ret = rtnl_unicast(dcbnl_skb, &init_net, pid); |
648 | if (ret) | ||
649 | goto nlmsg_failure; | ||
650 | |||
651 | goto out; | ||
502 | 652 | ||
503 | out_cancel: | 653 | out_cancel: |
504 | nla_nest_cancel(skb, app_nest); | 654 | nla_nest_cancel(dcbnl_skb, app_nest); |
655 | nlmsg_failure: | ||
656 | kfree_skb(dcbnl_skb); | ||
657 | out: | ||
505 | return ret; | 658 | return ret; |
506 | } | 659 | } |
507 | 660 | ||
508 | static int dcbnl_setapp(struct net_device *netdev, struct nlmsghdr *nlh, | 661 | static int dcbnl_setapp(struct net_device *netdev, struct nlattr **tb, |
509 | u32 seq, struct nlattr **tb, struct sk_buff *skb) | 662 | u32 pid, u32 seq, u16 flags) |
510 | { | 663 | { |
511 | int ret; | 664 | int err, ret = -EINVAL; |
512 | u16 id; | 665 | u16 id; |
513 | u8 up, idtype; | 666 | u8 up, idtype; |
514 | struct nlattr *app_tb[DCB_APP_ATTR_MAX + 1]; | 667 | struct nlattr *app_tb[DCB_APP_ATTR_MAX + 1]; |
515 | 668 | ||
516 | if (!tb[DCB_ATTR_APP]) | 669 | if (!tb[DCB_ATTR_APP]) |
517 | return -EINVAL; | 670 | goto out; |
518 | 671 | ||
519 | ret = nla_parse_nested(app_tb, DCB_APP_ATTR_MAX, tb[DCB_ATTR_APP], | 672 | ret = nla_parse_nested(app_tb, DCB_APP_ATTR_MAX, tb[DCB_ATTR_APP], |
520 | dcbnl_app_nest); | 673 | dcbnl_app_nest); |
521 | if (ret) | 674 | if (ret) |
522 | return ret; | 675 | goto out; |
523 | 676 | ||
677 | ret = -EINVAL; | ||
524 | /* all must be non-null */ | 678 | /* all must be non-null */ |
525 | if ((!app_tb[DCB_APP_ATTR_IDTYPE]) || | 679 | if ((!app_tb[DCB_APP_ATTR_IDTYPE]) || |
526 | (!app_tb[DCB_APP_ATTR_ID]) || | 680 | (!app_tb[DCB_APP_ATTR_ID]) || |
527 | (!app_tb[DCB_APP_ATTR_PRIORITY])) | 681 | (!app_tb[DCB_APP_ATTR_PRIORITY])) |
528 | return -EINVAL; | 682 | goto out; |
529 | 683 | ||
530 | /* either by eth type or by socket number */ | 684 | /* either by eth type or by socket number */ |
531 | idtype = nla_get_u8(app_tb[DCB_APP_ATTR_IDTYPE]); | 685 | idtype = nla_get_u8(app_tb[DCB_APP_ATTR_IDTYPE]); |
532 | if ((idtype != DCB_APP_IDTYPE_ETHTYPE) && | 686 | if ((idtype != DCB_APP_IDTYPE_ETHTYPE) && |
533 | (idtype != DCB_APP_IDTYPE_PORTNUM)) | 687 | (idtype != DCB_APP_IDTYPE_PORTNUM)) |
534 | return -EINVAL; | 688 | goto out; |
535 | 689 | ||
536 | id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]); | 690 | id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]); |
537 | up = nla_get_u8(app_tb[DCB_APP_ATTR_PRIORITY]); | 691 | up = nla_get_u8(app_tb[DCB_APP_ATTR_PRIORITY]); |
538 | 692 | ||
539 | if (netdev->dcbnl_ops->setapp) { | 693 | if (netdev->dcbnl_ops->setapp) { |
540 | ret = netdev->dcbnl_ops->setapp(netdev, idtype, id, up); | 694 | err = netdev->dcbnl_ops->setapp(netdev, idtype, id, up); |
541 | } else { | 695 | } else { |
542 | struct dcb_app app; | 696 | struct dcb_app app; |
543 | app.selector = idtype; | 697 | app.selector = idtype; |
544 | app.protocol = id; | 698 | app.protocol = id; |
545 | app.priority = up; | 699 | app.priority = up; |
546 | ret = dcb_setapp(netdev, &app); | 700 | err = dcb_setapp(netdev, &app); |
547 | } | 701 | } |
548 | 702 | ||
549 | ret = nla_put_u8(skb, DCB_ATTR_APP, ret); | 703 | ret = dcbnl_reply(err, RTM_SETDCB, DCB_CMD_SAPP, DCB_ATTR_APP, |
550 | dcbnl_cee_notify(netdev, RTM_SETDCB, DCB_CMD_SAPP, seq, 0); | 704 | pid, seq, flags); |
551 | 705 | out: | |
552 | return ret; | 706 | return ret; |
553 | } | 707 | } |
554 | 708 | ||
555 | static int __dcbnl_pg_getcfg(struct net_device *netdev, struct nlmsghdr *nlh, | 709 | static int __dcbnl_pg_getcfg(struct net_device *netdev, struct nlattr **tb, |
556 | struct nlattr **tb, struct sk_buff *skb, int dir) | 710 | u32 pid, u32 seq, u16 flags, int dir) |
557 | { | 711 | { |
712 | struct sk_buff *dcbnl_skb; | ||
713 | struct nlmsghdr *nlh; | ||
714 | struct dcbmsg *dcb; | ||
558 | struct nlattr *pg_nest, *param_nest, *data; | 715 | struct nlattr *pg_nest, *param_nest, *data; |
559 | struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1]; | 716 | struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1]; |
560 | struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1]; | 717 | struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1]; |
561 | u8 prio, pgid, tc_pct, up_map; | 718 | u8 prio, pgid, tc_pct, up_map; |
562 | int ret; | 719 | int ret = -EINVAL; |
563 | int getall = 0; | 720 | int getall = 0; |
564 | int i; | 721 | int i; |
565 | 722 | ||
566 | if (!tb[DCB_ATTR_PG_CFG]) | 723 | if (!tb[DCB_ATTR_PG_CFG] || |
567 | return -EINVAL; | 724 | !netdev->dcbnl_ops->getpgtccfgtx || |
568 | |||
569 | if (!netdev->dcbnl_ops->getpgtccfgtx || | ||
570 | !netdev->dcbnl_ops->getpgtccfgrx || | 725 | !netdev->dcbnl_ops->getpgtccfgrx || |
571 | !netdev->dcbnl_ops->getpgbwgcfgtx || | 726 | !netdev->dcbnl_ops->getpgbwgcfgtx || |
572 | !netdev->dcbnl_ops->getpgbwgcfgrx) | 727 | !netdev->dcbnl_ops->getpgbwgcfgrx) |
573 | return -EOPNOTSUPP; | 728 | return ret; |
574 | 729 | ||
575 | ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX, | 730 | ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX, |
576 | tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest); | 731 | tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest); |
732 | |||
577 | if (ret) | 733 | if (ret) |
578 | return ret; | 734 | goto err_out; |
735 | |||
736 | dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
737 | if (!dcbnl_skb) | ||
738 | goto err_out; | ||
739 | |||
740 | nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); | ||
741 | |||
742 | dcb = NLMSG_DATA(nlh); | ||
743 | dcb->dcb_family = AF_UNSPEC; | ||
744 | dcb->cmd = (dir) ? DCB_CMD_PGRX_GCFG : DCB_CMD_PGTX_GCFG; | ||
579 | 745 | ||
580 | pg_nest = nla_nest_start(skb, DCB_ATTR_PG_CFG); | 746 | pg_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_PG_CFG); |
581 | if (!pg_nest) | 747 | if (!pg_nest) |
582 | return -EMSGSIZE; | 748 | goto err; |
583 | 749 | ||
584 | if (pg_tb[DCB_PG_ATTR_TC_ALL]) | 750 | if (pg_tb[DCB_PG_ATTR_TC_ALL]) |
585 | getall = 1; | 751 | getall = 1; |
@@ -597,7 +763,7 @@ static int __dcbnl_pg_getcfg(struct net_device *netdev, struct nlmsghdr *nlh, | |||
597 | if (ret) | 763 | if (ret) |
598 | goto err_pg; | 764 | goto err_pg; |
599 | 765 | ||
600 | param_nest = nla_nest_start(skb, i); | 766 | param_nest = nla_nest_start(dcbnl_skb, i); |
601 | if (!param_nest) | 767 | if (!param_nest) |
602 | goto err_pg; | 768 | goto err_pg; |
603 | 769 | ||
@@ -620,33 +786,33 @@ static int __dcbnl_pg_getcfg(struct net_device *netdev, struct nlmsghdr *nlh, | |||
620 | 786 | ||
621 | if (param_tb[DCB_TC_ATTR_PARAM_PGID] || | 787 | if (param_tb[DCB_TC_ATTR_PARAM_PGID] || |
622 | param_tb[DCB_TC_ATTR_PARAM_ALL]) { | 788 | param_tb[DCB_TC_ATTR_PARAM_ALL]) { |
623 | ret = nla_put_u8(skb, | 789 | ret = nla_put_u8(dcbnl_skb, |
624 | DCB_TC_ATTR_PARAM_PGID, pgid); | 790 | DCB_TC_ATTR_PARAM_PGID, pgid); |
625 | if (ret) | 791 | if (ret) |
626 | goto err_param; | 792 | goto err_param; |
627 | } | 793 | } |
628 | if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING] || | 794 | if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING] || |
629 | param_tb[DCB_TC_ATTR_PARAM_ALL]) { | 795 | param_tb[DCB_TC_ATTR_PARAM_ALL]) { |
630 | ret = nla_put_u8(skb, | 796 | ret = nla_put_u8(dcbnl_skb, |
631 | DCB_TC_ATTR_PARAM_UP_MAPPING, up_map); | 797 | DCB_TC_ATTR_PARAM_UP_MAPPING, up_map); |
632 | if (ret) | 798 | if (ret) |
633 | goto err_param; | 799 | goto err_param; |
634 | } | 800 | } |
635 | if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO] || | 801 | if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO] || |
636 | param_tb[DCB_TC_ATTR_PARAM_ALL]) { | 802 | param_tb[DCB_TC_ATTR_PARAM_ALL]) { |
637 | ret = nla_put_u8(skb, | 803 | ret = nla_put_u8(dcbnl_skb, |
638 | DCB_TC_ATTR_PARAM_STRICT_PRIO, prio); | 804 | DCB_TC_ATTR_PARAM_STRICT_PRIO, prio); |
639 | if (ret) | 805 | if (ret) |
640 | goto err_param; | 806 | goto err_param; |
641 | } | 807 | } |
642 | if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT] || | 808 | if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT] || |
643 | param_tb[DCB_TC_ATTR_PARAM_ALL]) { | 809 | param_tb[DCB_TC_ATTR_PARAM_ALL]) { |
644 | ret = nla_put_u8(skb, DCB_TC_ATTR_PARAM_BW_PCT, | 810 | ret = nla_put_u8(dcbnl_skb, DCB_TC_ATTR_PARAM_BW_PCT, |
645 | tc_pct); | 811 | tc_pct); |
646 | if (ret) | 812 | if (ret) |
647 | goto err_param; | 813 | goto err_param; |
648 | } | 814 | } |
649 | nla_nest_end(skb, param_nest); | 815 | nla_nest_end(dcbnl_skb, param_nest); |
650 | } | 816 | } |
651 | 817 | ||
652 | if (pg_tb[DCB_PG_ATTR_BW_ID_ALL]) | 818 | if (pg_tb[DCB_PG_ATTR_BW_ID_ALL]) |
@@ -669,71 +835,80 @@ static int __dcbnl_pg_getcfg(struct net_device *netdev, struct nlmsghdr *nlh, | |||
669 | netdev->dcbnl_ops->getpgbwgcfgtx(netdev, | 835 | netdev->dcbnl_ops->getpgbwgcfgtx(netdev, |
670 | i - DCB_PG_ATTR_BW_ID_0, &tc_pct); | 836 | i - DCB_PG_ATTR_BW_ID_0, &tc_pct); |
671 | } | 837 | } |
672 | ret = nla_put_u8(skb, i, tc_pct); | 838 | ret = nla_put_u8(dcbnl_skb, i, tc_pct); |
839 | |||
673 | if (ret) | 840 | if (ret) |
674 | goto err_pg; | 841 | goto err_pg; |
675 | } | 842 | } |
676 | 843 | ||
677 | nla_nest_end(skb, pg_nest); | 844 | nla_nest_end(dcbnl_skb, pg_nest); |
845 | |||
846 | nlmsg_end(dcbnl_skb, nlh); | ||
847 | |||
848 | ret = rtnl_unicast(dcbnl_skb, &init_net, pid); | ||
849 | if (ret) | ||
850 | goto err_out; | ||
678 | 851 | ||
679 | return 0; | 852 | return 0; |
680 | 853 | ||
681 | err_param: | 854 | err_param: |
682 | nla_nest_cancel(skb, param_nest); | 855 | nla_nest_cancel(dcbnl_skb, param_nest); |
683 | err_pg: | 856 | err_pg: |
684 | nla_nest_cancel(skb, pg_nest); | 857 | nla_nest_cancel(dcbnl_skb, pg_nest); |
685 | 858 | nlmsg_failure: | |
686 | return -EMSGSIZE; | 859 | err: |
860 | kfree_skb(dcbnl_skb); | ||
861 | err_out: | ||
862 | ret = -EINVAL; | ||
863 | return ret; | ||
687 | } | 864 | } |
688 | 865 | ||
689 | static int dcbnl_pgtx_getcfg(struct net_device *netdev, struct nlmsghdr *nlh, | 866 | static int dcbnl_pgtx_getcfg(struct net_device *netdev, struct nlattr **tb, |
690 | u32 seq, struct nlattr **tb, struct sk_buff *skb) | 867 | u32 pid, u32 seq, u16 flags) |
691 | { | 868 | { |
692 | return __dcbnl_pg_getcfg(netdev, nlh, tb, skb, 0); | 869 | return __dcbnl_pg_getcfg(netdev, tb, pid, seq, flags, 0); |
693 | } | 870 | } |
694 | 871 | ||
695 | static int dcbnl_pgrx_getcfg(struct net_device *netdev, struct nlmsghdr *nlh, | 872 | static int dcbnl_pgrx_getcfg(struct net_device *netdev, struct nlattr **tb, |
696 | u32 seq, struct nlattr **tb, struct sk_buff *skb) | 873 | u32 pid, u32 seq, u16 flags) |
697 | { | 874 | { |
698 | return __dcbnl_pg_getcfg(netdev, nlh, tb, skb, 1); | 875 | return __dcbnl_pg_getcfg(netdev, tb, pid, seq, flags, 1); |
699 | } | 876 | } |
700 | 877 | ||
701 | static int dcbnl_setstate(struct net_device *netdev, struct nlmsghdr *nlh, | 878 | static int dcbnl_setstate(struct net_device *netdev, struct nlattr **tb, |
702 | u32 seq, struct nlattr **tb, struct sk_buff *skb) | 879 | u32 pid, u32 seq, u16 flags) |
703 | { | 880 | { |
881 | int ret = -EINVAL; | ||
704 | u8 value; | 882 | u8 value; |
705 | 883 | ||
706 | if (!tb[DCB_ATTR_STATE]) | 884 | if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->setstate) |
707 | return -EINVAL; | 885 | return ret; |
708 | |||
709 | if (!netdev->dcbnl_ops->setstate) | ||
710 | return -EOPNOTSUPP; | ||
711 | 886 | ||
712 | value = nla_get_u8(tb[DCB_ATTR_STATE]); | 887 | value = nla_get_u8(tb[DCB_ATTR_STATE]); |
713 | 888 | ||
714 | return nla_put_u8(skb, DCB_ATTR_STATE, | 889 | ret = dcbnl_reply(netdev->dcbnl_ops->setstate(netdev, value), |
715 | netdev->dcbnl_ops->setstate(netdev, value)); | 890 | RTM_SETDCB, DCB_CMD_SSTATE, DCB_ATTR_STATE, |
891 | pid, seq, flags); | ||
892 | |||
893 | return ret; | ||
716 | } | 894 | } |
717 | 895 | ||
718 | static int dcbnl_setpfccfg(struct net_device *netdev, struct nlmsghdr *nlh, | 896 | static int dcbnl_setpfccfg(struct net_device *netdev, struct nlattr **tb, |
719 | u32 seq, struct nlattr **tb, struct sk_buff *skb) | 897 | u32 pid, u32 seq, u16 flags) |
720 | { | 898 | { |
721 | struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1]; | 899 | struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1]; |
722 | int i; | 900 | int i; |
723 | int ret; | 901 | int ret = -EINVAL; |
724 | u8 value; | 902 | u8 value; |
725 | 903 | ||
726 | if (!tb[DCB_ATTR_PFC_CFG]) | 904 | if (!tb[DCB_ATTR_PFC_CFG] || !netdev->dcbnl_ops->setpfccfg) |
727 | return -EINVAL; | 905 | return ret; |
728 | |||
729 | if (!netdev->dcbnl_ops->setpfccfg) | ||
730 | return -EOPNOTSUPP; | ||
731 | 906 | ||
732 | ret = nla_parse_nested(data, DCB_PFC_UP_ATTR_MAX, | 907 | ret = nla_parse_nested(data, DCB_PFC_UP_ATTR_MAX, |
733 | tb[DCB_ATTR_PFC_CFG], | 908 | tb[DCB_ATTR_PFC_CFG], |
734 | dcbnl_pfc_up_nest); | 909 | dcbnl_pfc_up_nest); |
735 | if (ret) | 910 | if (ret) |
736 | return ret; | 911 | goto err; |
737 | 912 | ||
738 | for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) { | 913 | for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) { |
739 | if (data[i] == NULL) | 914 | if (data[i] == NULL) |
@@ -743,53 +918,49 @@ static int dcbnl_setpfccfg(struct net_device *netdev, struct nlmsghdr *nlh, | |||
743 | data[i]->nla_type - DCB_PFC_UP_ATTR_0, value); | 918 | data[i]->nla_type - DCB_PFC_UP_ATTR_0, value); |
744 | } | 919 | } |
745 | 920 | ||
746 | return nla_put_u8(skb, DCB_ATTR_PFC_CFG, 0); | 921 | ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_PFC_SCFG, DCB_ATTR_PFC_CFG, |
922 | pid, seq, flags); | ||
923 | err: | ||
924 | return ret; | ||
747 | } | 925 | } |
748 | 926 | ||
749 | static int dcbnl_setall(struct net_device *netdev, struct nlmsghdr *nlh, | 927 | static int dcbnl_setall(struct net_device *netdev, struct nlattr **tb, |
750 | u32 seq, struct nlattr **tb, struct sk_buff *skb) | 928 | u32 pid, u32 seq, u16 flags) |
751 | { | 929 | { |
752 | int ret; | 930 | int ret = -EINVAL; |
753 | |||
754 | if (!tb[DCB_ATTR_SET_ALL]) | ||
755 | return -EINVAL; | ||
756 | 931 | ||
757 | if (!netdev->dcbnl_ops->setall) | 932 | if (!tb[DCB_ATTR_SET_ALL] || !netdev->dcbnl_ops->setall) |
758 | return -EOPNOTSUPP; | 933 | return ret; |
759 | 934 | ||
760 | ret = nla_put_u8(skb, DCB_ATTR_SET_ALL, | 935 | ret = dcbnl_reply(netdev->dcbnl_ops->setall(netdev), RTM_SETDCB, |
761 | netdev->dcbnl_ops->setall(netdev)); | 936 | DCB_CMD_SET_ALL, DCB_ATTR_SET_ALL, pid, seq, flags); |
762 | dcbnl_cee_notify(netdev, RTM_SETDCB, DCB_CMD_SET_ALL, seq, 0); | ||
763 | 937 | ||
764 | return ret; | 938 | return ret; |
765 | } | 939 | } |
766 | 940 | ||
767 | static int __dcbnl_pg_setcfg(struct net_device *netdev, struct nlmsghdr *nlh, | 941 | static int __dcbnl_pg_setcfg(struct net_device *netdev, struct nlattr **tb, |
768 | u32 seq, struct nlattr **tb, struct sk_buff *skb, | 942 | u32 pid, u32 seq, u16 flags, int dir) |
769 | int dir) | ||
770 | { | 943 | { |
771 | struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1]; | 944 | struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1]; |
772 | struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1]; | 945 | struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1]; |
773 | int ret; | 946 | int ret = -EINVAL; |
774 | int i; | 947 | int i; |
775 | u8 pgid; | 948 | u8 pgid; |
776 | u8 up_map; | 949 | u8 up_map; |
777 | u8 prio; | 950 | u8 prio; |
778 | u8 tc_pct; | 951 | u8 tc_pct; |
779 | 952 | ||
780 | if (!tb[DCB_ATTR_PG_CFG]) | 953 | if (!tb[DCB_ATTR_PG_CFG] || |
781 | return -EINVAL; | 954 | !netdev->dcbnl_ops->setpgtccfgtx || |
782 | |||
783 | if (!netdev->dcbnl_ops->setpgtccfgtx || | ||
784 | !netdev->dcbnl_ops->setpgtccfgrx || | 955 | !netdev->dcbnl_ops->setpgtccfgrx || |
785 | !netdev->dcbnl_ops->setpgbwgcfgtx || | 956 | !netdev->dcbnl_ops->setpgbwgcfgtx || |
786 | !netdev->dcbnl_ops->setpgbwgcfgrx) | 957 | !netdev->dcbnl_ops->setpgbwgcfgrx) |
787 | return -EOPNOTSUPP; | 958 | return ret; |
788 | 959 | ||
789 | ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX, | 960 | ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX, |
790 | tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest); | 961 | tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest); |
791 | if (ret) | 962 | if (ret) |
792 | return ret; | 963 | goto err; |
793 | 964 | ||
794 | for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) { | 965 | for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) { |
795 | if (!pg_tb[i]) | 966 | if (!pg_tb[i]) |
@@ -798,7 +969,7 @@ static int __dcbnl_pg_setcfg(struct net_device *netdev, struct nlmsghdr *nlh, | |||
798 | ret = nla_parse_nested(param_tb, DCB_TC_ATTR_PARAM_MAX, | 969 | ret = nla_parse_nested(param_tb, DCB_TC_ATTR_PARAM_MAX, |
799 | pg_tb[i], dcbnl_tc_param_nest); | 970 | pg_tb[i], dcbnl_tc_param_nest); |
800 | if (ret) | 971 | if (ret) |
801 | return ret; | 972 | goto err; |
802 | 973 | ||
803 | pgid = DCB_ATTR_VALUE_UNDEFINED; | 974 | pgid = DCB_ATTR_VALUE_UNDEFINED; |
804 | prio = DCB_ATTR_VALUE_UNDEFINED; | 975 | prio = DCB_ATTR_VALUE_UNDEFINED; |
@@ -851,47 +1022,63 @@ static int __dcbnl_pg_setcfg(struct net_device *netdev, struct nlmsghdr *nlh, | |||
851 | } | 1022 | } |
852 | } | 1023 | } |
853 | 1024 | ||
854 | return nla_put_u8(skb, DCB_ATTR_PG_CFG, 0); | 1025 | ret = dcbnl_reply(0, RTM_SETDCB, |
1026 | (dir ? DCB_CMD_PGRX_SCFG : DCB_CMD_PGTX_SCFG), | ||
1027 | DCB_ATTR_PG_CFG, pid, seq, flags); | ||
1028 | |||
1029 | err: | ||
1030 | return ret; | ||
855 | } | 1031 | } |
856 | 1032 | ||
857 | static int dcbnl_pgtx_setcfg(struct net_device *netdev, struct nlmsghdr *nlh, | 1033 | static int dcbnl_pgtx_setcfg(struct net_device *netdev, struct nlattr **tb, |
858 | u32 seq, struct nlattr **tb, struct sk_buff *skb) | 1034 | u32 pid, u32 seq, u16 flags) |
859 | { | 1035 | { |
860 | return __dcbnl_pg_setcfg(netdev, nlh, seq, tb, skb, 0); | 1036 | return __dcbnl_pg_setcfg(netdev, tb, pid, seq, flags, 0); |
861 | } | 1037 | } |
862 | 1038 | ||
863 | static int dcbnl_pgrx_setcfg(struct net_device *netdev, struct nlmsghdr *nlh, | 1039 | static int dcbnl_pgrx_setcfg(struct net_device *netdev, struct nlattr **tb, |
864 | u32 seq, struct nlattr **tb, struct sk_buff *skb) | 1040 | u32 pid, u32 seq, u16 flags) |
865 | { | 1041 | { |
866 | return __dcbnl_pg_setcfg(netdev, nlh, seq, tb, skb, 1); | 1042 | return __dcbnl_pg_setcfg(netdev, tb, pid, seq, flags, 1); |
867 | } | 1043 | } |
868 | 1044 | ||
869 | static int dcbnl_bcn_getcfg(struct net_device *netdev, struct nlmsghdr *nlh, | 1045 | static int dcbnl_bcn_getcfg(struct net_device *netdev, struct nlattr **tb, |
870 | u32 seq, struct nlattr **tb, struct sk_buff *skb) | 1046 | u32 pid, u32 seq, u16 flags) |
871 | { | 1047 | { |
1048 | struct sk_buff *dcbnl_skb; | ||
1049 | struct nlmsghdr *nlh; | ||
1050 | struct dcbmsg *dcb; | ||
872 | struct nlattr *bcn_nest; | 1051 | struct nlattr *bcn_nest; |
873 | struct nlattr *bcn_tb[DCB_BCN_ATTR_MAX + 1]; | 1052 | struct nlattr *bcn_tb[DCB_BCN_ATTR_MAX + 1]; |
874 | u8 value_byte; | 1053 | u8 value_byte; |
875 | u32 value_integer; | 1054 | u32 value_integer; |
876 | int ret; | 1055 | int ret = -EINVAL; |
877 | bool getall = false; | 1056 | bool getall = false; |
878 | int i; | 1057 | int i; |
879 | 1058 | ||
880 | if (!tb[DCB_ATTR_BCN]) | 1059 | if (!tb[DCB_ATTR_BCN] || !netdev->dcbnl_ops->getbcnrp || |
881 | return -EINVAL; | ||
882 | |||
883 | if (!netdev->dcbnl_ops->getbcnrp || | ||
884 | !netdev->dcbnl_ops->getbcncfg) | 1060 | !netdev->dcbnl_ops->getbcncfg) |
885 | return -EOPNOTSUPP; | 1061 | return ret; |
886 | 1062 | ||
887 | ret = nla_parse_nested(bcn_tb, DCB_BCN_ATTR_MAX, | 1063 | ret = nla_parse_nested(bcn_tb, DCB_BCN_ATTR_MAX, |
888 | tb[DCB_ATTR_BCN], dcbnl_bcn_nest); | 1064 | tb[DCB_ATTR_BCN], dcbnl_bcn_nest); |
1065 | |||
889 | if (ret) | 1066 | if (ret) |
890 | return ret; | 1067 | goto err_out; |
1068 | |||
1069 | dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
1070 | if (!dcbnl_skb) | ||
1071 | goto err_out; | ||
1072 | |||
1073 | nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); | ||
891 | 1074 | ||
892 | bcn_nest = nla_nest_start(skb, DCB_ATTR_BCN); | 1075 | dcb = NLMSG_DATA(nlh); |
1076 | dcb->dcb_family = AF_UNSPEC; | ||
1077 | dcb->cmd = DCB_CMD_BCN_GCFG; | ||
1078 | |||
1079 | bcn_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_BCN); | ||
893 | if (!bcn_nest) | 1080 | if (!bcn_nest) |
894 | return -EMSGSIZE; | 1081 | goto err; |
895 | 1082 | ||
896 | if (bcn_tb[DCB_BCN_ATTR_ALL]) | 1083 | if (bcn_tb[DCB_BCN_ATTR_ALL]) |
897 | getall = true; | 1084 | getall = true; |
@@ -902,7 +1089,7 @@ static int dcbnl_bcn_getcfg(struct net_device *netdev, struct nlmsghdr *nlh, | |||
902 | 1089 | ||
903 | netdev->dcbnl_ops->getbcnrp(netdev, i - DCB_BCN_ATTR_RP_0, | 1090 | netdev->dcbnl_ops->getbcnrp(netdev, i - DCB_BCN_ATTR_RP_0, |
904 | &value_byte); | 1091 | &value_byte); |
905 | ret = nla_put_u8(skb, i, value_byte); | 1092 | ret = nla_put_u8(dcbnl_skb, i, value_byte); |
906 | if (ret) | 1093 | if (ret) |
907 | goto err_bcn; | 1094 | goto err_bcn; |
908 | } | 1095 | } |
@@ -913,41 +1100,49 @@ static int dcbnl_bcn_getcfg(struct net_device *netdev, struct nlmsghdr *nlh, | |||
913 | 1100 | ||
914 | netdev->dcbnl_ops->getbcncfg(netdev, i, | 1101 | netdev->dcbnl_ops->getbcncfg(netdev, i, |
915 | &value_integer); | 1102 | &value_integer); |
916 | ret = nla_put_u32(skb, i, value_integer); | 1103 | ret = nla_put_u32(dcbnl_skb, i, value_integer); |
917 | if (ret) | 1104 | if (ret) |
918 | goto err_bcn; | 1105 | goto err_bcn; |
919 | } | 1106 | } |
920 | 1107 | ||
921 | nla_nest_end(skb, bcn_nest); | 1108 | nla_nest_end(dcbnl_skb, bcn_nest); |
1109 | |||
1110 | nlmsg_end(dcbnl_skb, nlh); | ||
1111 | |||
1112 | ret = rtnl_unicast(dcbnl_skb, &init_net, pid); | ||
1113 | if (ret) | ||
1114 | goto err_out; | ||
922 | 1115 | ||
923 | return 0; | 1116 | return 0; |
924 | 1117 | ||
925 | err_bcn: | 1118 | err_bcn: |
926 | nla_nest_cancel(skb, bcn_nest); | 1119 | nla_nest_cancel(dcbnl_skb, bcn_nest); |
1120 | nlmsg_failure: | ||
1121 | err: | ||
1122 | kfree_skb(dcbnl_skb); | ||
1123 | err_out: | ||
1124 | ret = -EINVAL; | ||
927 | return ret; | 1125 | return ret; |
928 | } | 1126 | } |
929 | 1127 | ||
930 | static int dcbnl_bcn_setcfg(struct net_device *netdev, struct nlmsghdr *nlh, | 1128 | static int dcbnl_bcn_setcfg(struct net_device *netdev, struct nlattr **tb, |
931 | u32 seq, struct nlattr **tb, struct sk_buff *skb) | 1129 | u32 pid, u32 seq, u16 flags) |
932 | { | 1130 | { |
933 | struct nlattr *data[DCB_BCN_ATTR_MAX + 1]; | 1131 | struct nlattr *data[DCB_BCN_ATTR_MAX + 1]; |
934 | int i; | 1132 | int i; |
935 | int ret; | 1133 | int ret = -EINVAL; |
936 | u8 value_byte; | 1134 | u8 value_byte; |
937 | u32 value_int; | 1135 | u32 value_int; |
938 | 1136 | ||
939 | if (!tb[DCB_ATTR_BCN]) | 1137 | if (!tb[DCB_ATTR_BCN] || !netdev->dcbnl_ops->setbcncfg || |
940 | return -EINVAL; | ||
941 | |||
942 | if (!netdev->dcbnl_ops->setbcncfg || | ||
943 | !netdev->dcbnl_ops->setbcnrp) | 1138 | !netdev->dcbnl_ops->setbcnrp) |
944 | return -EOPNOTSUPP; | 1139 | return ret; |
945 | 1140 | ||
946 | ret = nla_parse_nested(data, DCB_BCN_ATTR_MAX, | 1141 | ret = nla_parse_nested(data, DCB_BCN_ATTR_MAX, |
947 | tb[DCB_ATTR_BCN], | 1142 | tb[DCB_ATTR_BCN], |
948 | dcbnl_pfc_up_nest); | 1143 | dcbnl_pfc_up_nest); |
949 | if (ret) | 1144 | if (ret) |
950 | return ret; | 1145 | goto err; |
951 | 1146 | ||
952 | for (i = DCB_BCN_ATTR_RP_0; i <= DCB_BCN_ATTR_RP_7; i++) { | 1147 | for (i = DCB_BCN_ATTR_RP_0; i <= DCB_BCN_ATTR_RP_7; i++) { |
953 | if (data[i] == NULL) | 1148 | if (data[i] == NULL) |
@@ -965,7 +1160,10 @@ static int dcbnl_bcn_setcfg(struct net_device *netdev, struct nlmsghdr *nlh, | |||
965 | i, value_int); | 1160 | i, value_int); |
966 | } | 1161 | } |
967 | 1162 | ||
968 | return nla_put_u8(skb, DCB_ATTR_BCN, 0); | 1163 | ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_BCN_SCFG, DCB_ATTR_BCN, |
1164 | pid, seq, flags); | ||
1165 | err: | ||
1166 | return ret; | ||
969 | } | 1167 | } |
970 | 1168 | ||
971 | static int dcbnl_build_peer_app(struct net_device *netdev, struct sk_buff* skb, | 1169 | static int dcbnl_build_peer_app(struct net_device *netdev, struct sk_buff* skb, |
@@ -1006,15 +1204,13 @@ static int dcbnl_build_peer_app(struct net_device *netdev, struct sk_buff* skb, | |||
1006 | if (!app) | 1204 | if (!app) |
1007 | goto nla_put_failure; | 1205 | goto nla_put_failure; |
1008 | 1206 | ||
1009 | if (app_info_type && | 1207 | if (app_info_type) |
1010 | nla_put(skb, app_info_type, sizeof(info), &info)) | 1208 | NLA_PUT(skb, app_info_type, sizeof(info), &info); |
1011 | goto nla_put_failure; | 1209 | |
1210 | for (i = 0; i < app_count; i++) | ||
1211 | NLA_PUT(skb, app_entry_type, sizeof(struct dcb_app), | ||
1212 | &table[i]); | ||
1012 | 1213 | ||
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); | 1214 | nla_nest_end(skb, app); |
1019 | } | 1215 | } |
1020 | err = 0; | 1216 | err = 0; |
@@ -1031,54 +1227,40 @@ static int dcbnl_ieee_fill(struct sk_buff *skb, struct net_device *netdev) | |||
1031 | struct dcb_app_type *itr; | 1227 | struct dcb_app_type *itr; |
1032 | const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; | 1228 | const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; |
1033 | int dcbx; | 1229 | int dcbx; |
1034 | int err; | 1230 | int err = -EMSGSIZE; |
1035 | 1231 | ||
1036 | if (nla_put_string(skb, DCB_ATTR_IFNAME, netdev->name)) | 1232 | NLA_PUT_STRING(skb, DCB_ATTR_IFNAME, netdev->name); |
1037 | return -EMSGSIZE; | ||
1038 | 1233 | ||
1039 | ieee = nla_nest_start(skb, DCB_ATTR_IEEE); | 1234 | ieee = nla_nest_start(skb, DCB_ATTR_IEEE); |
1040 | if (!ieee) | 1235 | if (!ieee) |
1041 | return -EMSGSIZE; | 1236 | goto nla_put_failure; |
1042 | 1237 | ||
1043 | if (ops->ieee_getets) { | 1238 | if (ops->ieee_getets) { |
1044 | struct ieee_ets ets; | 1239 | struct ieee_ets ets; |
1045 | err = ops->ieee_getets(netdev, &ets); | 1240 | err = ops->ieee_getets(netdev, &ets); |
1046 | if (!err && | 1241 | if (!err) |
1047 | nla_put(skb, DCB_ATTR_IEEE_ETS, sizeof(ets), &ets)) | 1242 | 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 | } | 1243 | } |
1061 | 1244 | ||
1062 | if (ops->ieee_getpfc) { | 1245 | if (ops->ieee_getpfc) { |
1063 | struct ieee_pfc pfc; | 1246 | struct ieee_pfc pfc; |
1064 | err = ops->ieee_getpfc(netdev, &pfc); | 1247 | err = ops->ieee_getpfc(netdev, &pfc); |
1065 | if (!err && | 1248 | if (!err) |
1066 | nla_put(skb, DCB_ATTR_IEEE_PFC, sizeof(pfc), &pfc)) | 1249 | NLA_PUT(skb, DCB_ATTR_IEEE_PFC, sizeof(pfc), &pfc); |
1067 | return -EMSGSIZE; | ||
1068 | } | 1250 | } |
1069 | 1251 | ||
1070 | app = nla_nest_start(skb, DCB_ATTR_IEEE_APP_TABLE); | 1252 | app = nla_nest_start(skb, DCB_ATTR_IEEE_APP_TABLE); |
1071 | if (!app) | 1253 | if (!app) |
1072 | return -EMSGSIZE; | 1254 | goto nla_put_failure; |
1073 | 1255 | ||
1074 | spin_lock(&dcb_lock); | 1256 | spin_lock(&dcb_lock); |
1075 | list_for_each_entry(itr, &dcb_app_list, list) { | 1257 | list_for_each_entry(itr, &dcb_app_list, list) { |
1076 | if (itr->ifindex == netdev->ifindex) { | 1258 | if (strncmp(itr->name, netdev->name, IFNAMSIZ) == 0) { |
1077 | err = nla_put(skb, DCB_ATTR_IEEE_APP, sizeof(itr->app), | 1259 | err = nla_put(skb, DCB_ATTR_IEEE_APP, sizeof(itr->app), |
1078 | &itr->app); | 1260 | &itr->app); |
1079 | if (err) { | 1261 | if (err) { |
1080 | spin_unlock(&dcb_lock); | 1262 | spin_unlock(&dcb_lock); |
1081 | return -EMSGSIZE; | 1263 | goto nla_put_failure; |
1082 | } | 1264 | } |
1083 | } | 1265 | } |
1084 | } | 1266 | } |
@@ -1095,17 +1277,15 @@ static int dcbnl_ieee_fill(struct sk_buff *skb, struct net_device *netdev) | |||
1095 | if (ops->ieee_peer_getets) { | 1277 | if (ops->ieee_peer_getets) { |
1096 | struct ieee_ets ets; | 1278 | struct ieee_ets ets; |
1097 | err = ops->ieee_peer_getets(netdev, &ets); | 1279 | err = ops->ieee_peer_getets(netdev, &ets); |
1098 | if (!err && | 1280 | if (!err) |
1099 | nla_put(skb, DCB_ATTR_IEEE_PEER_ETS, sizeof(ets), &ets)) | 1281 | NLA_PUT(skb, DCB_ATTR_IEEE_PEER_ETS, sizeof(ets), &ets); |
1100 | return -EMSGSIZE; | ||
1101 | } | 1282 | } |
1102 | 1283 | ||
1103 | if (ops->ieee_peer_getpfc) { | 1284 | if (ops->ieee_peer_getpfc) { |
1104 | struct ieee_pfc pfc; | 1285 | struct ieee_pfc pfc; |
1105 | err = ops->ieee_peer_getpfc(netdev, &pfc); | 1286 | err = ops->ieee_peer_getpfc(netdev, &pfc); |
1106 | if (!err && | 1287 | if (!err) |
1107 | nla_put(skb, DCB_ATTR_IEEE_PEER_PFC, sizeof(pfc), &pfc)) | 1288 | NLA_PUT(skb, DCB_ATTR_IEEE_PEER_PFC, sizeof(pfc), &pfc); |
1108 | return -EMSGSIZE; | ||
1109 | } | 1289 | } |
1110 | 1290 | ||
1111 | if (ops->peer_getappinfo && ops->peer_getapptable) { | 1291 | if (ops->peer_getappinfo && ops->peer_getapptable) { |
@@ -1114,17 +1294,20 @@ static int dcbnl_ieee_fill(struct sk_buff *skb, struct net_device *netdev) | |||
1114 | DCB_ATTR_IEEE_APP_UNSPEC, | 1294 | DCB_ATTR_IEEE_APP_UNSPEC, |
1115 | DCB_ATTR_IEEE_APP); | 1295 | DCB_ATTR_IEEE_APP); |
1116 | if (err) | 1296 | if (err) |
1117 | return -EMSGSIZE; | 1297 | goto nla_put_failure; |
1118 | } | 1298 | } |
1119 | 1299 | ||
1120 | nla_nest_end(skb, ieee); | 1300 | nla_nest_end(skb, ieee); |
1121 | if (dcbx >= 0) { | 1301 | if (dcbx >= 0) { |
1122 | err = nla_put_u8(skb, DCB_ATTR_DCBX, dcbx); | 1302 | err = nla_put_u8(skb, DCB_ATTR_DCBX, dcbx); |
1123 | if (err) | 1303 | if (err) |
1124 | return -EMSGSIZE; | 1304 | goto nla_put_failure; |
1125 | } | 1305 | } |
1126 | 1306 | ||
1127 | return 0; | 1307 | return 0; |
1308 | |||
1309 | nla_put_failure: | ||
1310 | return err; | ||
1128 | } | 1311 | } |
1129 | 1312 | ||
1130 | static int dcbnl_cee_pg_fill(struct sk_buff *skb, struct net_device *dev, | 1313 | static int dcbnl_cee_pg_fill(struct sk_buff *skb, struct net_device *dev, |
@@ -1136,13 +1319,13 @@ static int dcbnl_cee_pg_fill(struct sk_buff *skb, struct net_device *dev, | |||
1136 | struct nlattr *pg = nla_nest_start(skb, i); | 1319 | struct nlattr *pg = nla_nest_start(skb, i); |
1137 | 1320 | ||
1138 | if (!pg) | 1321 | if (!pg) |
1139 | return -EMSGSIZE; | 1322 | goto nla_put_failure; |
1140 | 1323 | ||
1141 | for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) { | 1324 | for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) { |
1142 | struct nlattr *tc_nest = nla_nest_start(skb, i); | 1325 | struct nlattr *tc_nest = nla_nest_start(skb, i); |
1143 | 1326 | ||
1144 | if (!tc_nest) | 1327 | if (!tc_nest) |
1145 | return -EMSGSIZE; | 1328 | goto nla_put_failure; |
1146 | 1329 | ||
1147 | pgid = DCB_ATTR_VALUE_UNDEFINED; | 1330 | pgid = DCB_ATTR_VALUE_UNDEFINED; |
1148 | prio = DCB_ATTR_VALUE_UNDEFINED; | 1331 | prio = DCB_ATTR_VALUE_UNDEFINED; |
@@ -1156,11 +1339,10 @@ static int dcbnl_cee_pg_fill(struct sk_buff *skb, struct net_device *dev, | |||
1156 | ops->getpgtccfgtx(dev, i - DCB_PG_ATTR_TC_0, | 1339 | ops->getpgtccfgtx(dev, i - DCB_PG_ATTR_TC_0, |
1157 | &prio, &pgid, &tc_pct, &up_map); | 1340 | &prio, &pgid, &tc_pct, &up_map); |
1158 | 1341 | ||
1159 | if (nla_put_u8(skb, DCB_TC_ATTR_PARAM_PGID, pgid) || | 1342 | NLA_PUT_U8(skb, DCB_TC_ATTR_PARAM_PGID, pgid); |
1160 | nla_put_u8(skb, DCB_TC_ATTR_PARAM_UP_MAPPING, up_map) || | 1343 | NLA_PUT_U8(skb, DCB_TC_ATTR_PARAM_UP_MAPPING, up_map); |
1161 | nla_put_u8(skb, DCB_TC_ATTR_PARAM_STRICT_PRIO, prio) || | 1344 | NLA_PUT_U8(skb, DCB_TC_ATTR_PARAM_STRICT_PRIO, prio); |
1162 | nla_put_u8(skb, DCB_TC_ATTR_PARAM_BW_PCT, tc_pct)) | 1345 | NLA_PUT_U8(skb, DCB_TC_ATTR_PARAM_BW_PCT, tc_pct); |
1163 | return -EMSGSIZE; | ||
1164 | nla_nest_end(skb, tc_nest); | 1346 | nla_nest_end(skb, tc_nest); |
1165 | } | 1347 | } |
1166 | 1348 | ||
@@ -1173,11 +1355,13 @@ static int dcbnl_cee_pg_fill(struct sk_buff *skb, struct net_device *dev, | |||
1173 | else | 1355 | else |
1174 | ops->getpgbwgcfgtx(dev, i - DCB_PG_ATTR_BW_ID_0, | 1356 | ops->getpgbwgcfgtx(dev, i - DCB_PG_ATTR_BW_ID_0, |
1175 | &tc_pct); | 1357 | &tc_pct); |
1176 | if (nla_put_u8(skb, i, tc_pct)) | 1358 | NLA_PUT_U8(skb, i, tc_pct); |
1177 | return -EMSGSIZE; | ||
1178 | } | 1359 | } |
1179 | nla_nest_end(skb, pg); | 1360 | nla_nest_end(skb, pg); |
1180 | return 0; | 1361 | return 0; |
1362 | |||
1363 | nla_put_failure: | ||
1364 | return -EMSGSIZE; | ||
1181 | } | 1365 | } |
1182 | 1366 | ||
1183 | static int dcbnl_cee_fill(struct sk_buff *skb, struct net_device *netdev) | 1367 | static int dcbnl_cee_fill(struct sk_buff *skb, struct net_device *netdev) |
@@ -1188,8 +1372,8 @@ static int dcbnl_cee_fill(struct sk_buff *skb, struct net_device *netdev) | |||
1188 | int dcbx, i, err = -EMSGSIZE; | 1372 | int dcbx, i, err = -EMSGSIZE; |
1189 | u8 value; | 1373 | u8 value; |
1190 | 1374 | ||
1191 | if (nla_put_string(skb, DCB_ATTR_IFNAME, netdev->name)) | 1375 | NLA_PUT_STRING(skb, DCB_ATTR_IFNAME, netdev->name); |
1192 | goto nla_put_failure; | 1376 | |
1193 | cee = nla_nest_start(skb, DCB_ATTR_CEE); | 1377 | cee = nla_nest_start(skb, DCB_ATTR_CEE); |
1194 | if (!cee) | 1378 | if (!cee) |
1195 | goto nla_put_failure; | 1379 | goto nla_put_failure; |
@@ -1216,8 +1400,7 @@ static int dcbnl_cee_fill(struct sk_buff *skb, struct net_device *netdev) | |||
1216 | 1400 | ||
1217 | for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) { | 1401 | 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); | 1402 | ops->getpfccfg(netdev, i - DCB_PFC_UP_ATTR_0, &value); |
1219 | if (nla_put_u8(skb, i, value)) | 1403 | NLA_PUT_U8(skb, i, value); |
1220 | goto nla_put_failure; | ||
1221 | } | 1404 | } |
1222 | nla_nest_end(skb, pfc_nest); | 1405 | nla_nest_end(skb, pfc_nest); |
1223 | } | 1406 | } |
@@ -1229,7 +1412,7 @@ static int dcbnl_cee_fill(struct sk_buff *skb, struct net_device *netdev) | |||
1229 | goto dcb_unlock; | 1412 | goto dcb_unlock; |
1230 | 1413 | ||
1231 | list_for_each_entry(itr, &dcb_app_list, list) { | 1414 | list_for_each_entry(itr, &dcb_app_list, list) { |
1232 | if (itr->ifindex == netdev->ifindex) { | 1415 | if (strncmp(itr->name, netdev->name, IFNAMSIZ) == 0) { |
1233 | struct nlattr *app_nest = nla_nest_start(skb, | 1416 | struct nlattr *app_nest = nla_nest_start(skb, |
1234 | DCB_ATTR_APP); | 1417 | DCB_ATTR_APP); |
1235 | if (!app_nest) | 1418 | if (!app_nest) |
@@ -1270,9 +1453,8 @@ static int dcbnl_cee_fill(struct sk_buff *skb, struct net_device *netdev) | |||
1270 | 1453 | ||
1271 | for (i = DCB_FEATCFG_ATTR_ALL + 1; i <= DCB_FEATCFG_ATTR_MAX; | 1454 | for (i = DCB_FEATCFG_ATTR_ALL + 1; i <= DCB_FEATCFG_ATTR_MAX; |
1272 | i++) | 1455 | i++) |
1273 | if (!ops->getfeatcfg(netdev, i, &value) && | 1456 | if (!ops->getfeatcfg(netdev, i, &value)) |
1274 | nla_put_u8(skb, i, value)) | 1457 | NLA_PUT_U8(skb, i, value); |
1275 | goto nla_put_failure; | ||
1276 | 1458 | ||
1277 | nla_nest_end(skb, feat); | 1459 | nla_nest_end(skb, feat); |
1278 | } | 1460 | } |
@@ -1281,17 +1463,15 @@ static int dcbnl_cee_fill(struct sk_buff *skb, struct net_device *netdev) | |||
1281 | if (ops->cee_peer_getpg) { | 1463 | if (ops->cee_peer_getpg) { |
1282 | struct cee_pg pg; | 1464 | struct cee_pg pg; |
1283 | err = ops->cee_peer_getpg(netdev, &pg); | 1465 | err = ops->cee_peer_getpg(netdev, &pg); |
1284 | if (!err && | 1466 | if (!err) |
1285 | nla_put(skb, DCB_ATTR_CEE_PEER_PG, sizeof(pg), &pg)) | 1467 | NLA_PUT(skb, DCB_ATTR_CEE_PEER_PG, sizeof(pg), &pg); |
1286 | goto nla_put_failure; | ||
1287 | } | 1468 | } |
1288 | 1469 | ||
1289 | if (ops->cee_peer_getpfc) { | 1470 | if (ops->cee_peer_getpfc) { |
1290 | struct cee_pfc pfc; | 1471 | struct cee_pfc pfc; |
1291 | err = ops->cee_peer_getpfc(netdev, &pfc); | 1472 | err = ops->cee_peer_getpfc(netdev, &pfc); |
1292 | if (!err && | 1473 | if (!err) |
1293 | nla_put(skb, DCB_ATTR_CEE_PEER_PFC, sizeof(pfc), &pfc)) | 1474 | NLA_PUT(skb, DCB_ATTR_CEE_PEER_PFC, sizeof(pfc), &pfc); |
1294 | goto nla_put_failure; | ||
1295 | } | 1475 | } |
1296 | 1476 | ||
1297 | if (ops->peer_getappinfo && ops->peer_getapptable) { | 1477 | if (ops->peer_getappinfo && ops->peer_getapptable) { |
@@ -1319,21 +1499,32 @@ nla_put_failure: | |||
1319 | } | 1499 | } |
1320 | 1500 | ||
1321 | static int dcbnl_notify(struct net_device *dev, int event, int cmd, | 1501 | static int dcbnl_notify(struct net_device *dev, int event, int cmd, |
1322 | u32 seq, u32 portid, int dcbx_ver) | 1502 | u32 seq, u32 pid, int dcbx_ver) |
1323 | { | 1503 | { |
1324 | struct net *net = dev_net(dev); | 1504 | struct net *net = dev_net(dev); |
1325 | struct sk_buff *skb; | 1505 | struct sk_buff *skb; |
1326 | struct nlmsghdr *nlh; | 1506 | struct nlmsghdr *nlh; |
1507 | struct dcbmsg *dcb; | ||
1327 | const struct dcbnl_rtnl_ops *ops = dev->dcbnl_ops; | 1508 | const struct dcbnl_rtnl_ops *ops = dev->dcbnl_ops; |
1328 | int err; | 1509 | int err; |
1329 | 1510 | ||
1330 | if (!ops) | 1511 | if (!ops) |
1331 | return -EOPNOTSUPP; | 1512 | return -EOPNOTSUPP; |
1332 | 1513 | ||
1333 | skb = dcbnl_newmsg(event, cmd, portid, seq, 0, &nlh); | 1514 | skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
1334 | if (!skb) | 1515 | if (!skb) |
1335 | return -ENOBUFS; | 1516 | return -ENOBUFS; |
1336 | 1517 | ||
1518 | nlh = nlmsg_put(skb, pid, 0, event, sizeof(*dcb), 0); | ||
1519 | if (nlh == NULL) { | ||
1520 | nlmsg_free(skb); | ||
1521 | return -EMSGSIZE; | ||
1522 | } | ||
1523 | |||
1524 | dcb = NLMSG_DATA(nlh); | ||
1525 | dcb->dcb_family = AF_UNSPEC; | ||
1526 | dcb->cmd = cmd; | ||
1527 | |||
1337 | if (dcbx_ver == DCB_CAP_DCBX_VER_IEEE) | 1528 | if (dcbx_ver == DCB_CAP_DCBX_VER_IEEE) |
1338 | err = dcbnl_ieee_fill(skb, dev); | 1529 | err = dcbnl_ieee_fill(skb, dev); |
1339 | else | 1530 | else |
@@ -1341,7 +1532,8 @@ static int dcbnl_notify(struct net_device *dev, int event, int cmd, | |||
1341 | 1532 | ||
1342 | if (err < 0) { | 1533 | if (err < 0) { |
1343 | /* Report error to broadcast listeners */ | 1534 | /* Report error to broadcast listeners */ |
1344 | nlmsg_free(skb); | 1535 | nlmsg_cancel(skb, nlh); |
1536 | kfree_skb(skb); | ||
1345 | rtnl_set_sk_err(net, RTNLGRP_DCB, err); | 1537 | rtnl_set_sk_err(net, RTNLGRP_DCB, err); |
1346 | } else { | 1538 | } else { |
1347 | /* End nlmsg and notify broadcast listeners */ | 1539 | /* End nlmsg and notify broadcast listeners */ |
@@ -1353,16 +1545,16 @@ static int dcbnl_notify(struct net_device *dev, int event, int cmd, | |||
1353 | } | 1545 | } |
1354 | 1546 | ||
1355 | int dcbnl_ieee_notify(struct net_device *dev, int event, int cmd, | 1547 | int dcbnl_ieee_notify(struct net_device *dev, int event, int cmd, |
1356 | u32 seq, u32 portid) | 1548 | u32 seq, u32 pid) |
1357 | { | 1549 | { |
1358 | return dcbnl_notify(dev, event, cmd, seq, portid, DCB_CAP_DCBX_VER_IEEE); | 1550 | return dcbnl_notify(dev, event, cmd, seq, pid, DCB_CAP_DCBX_VER_IEEE); |
1359 | } | 1551 | } |
1360 | EXPORT_SYMBOL(dcbnl_ieee_notify); | 1552 | EXPORT_SYMBOL(dcbnl_ieee_notify); |
1361 | 1553 | ||
1362 | int dcbnl_cee_notify(struct net_device *dev, int event, int cmd, | 1554 | int dcbnl_cee_notify(struct net_device *dev, int event, int cmd, |
1363 | u32 seq, u32 portid) | 1555 | u32 seq, u32 pid) |
1364 | { | 1556 | { |
1365 | return dcbnl_notify(dev, event, cmd, seq, portid, DCB_CAP_DCBX_VER_CEE); | 1557 | return dcbnl_notify(dev, event, cmd, seq, pid, DCB_CAP_DCBX_VER_CEE); |
1366 | } | 1558 | } |
1367 | EXPORT_SYMBOL(dcbnl_cee_notify); | 1559 | EXPORT_SYMBOL(dcbnl_cee_notify); |
1368 | 1560 | ||
@@ -1371,15 +1563,15 @@ EXPORT_SYMBOL(dcbnl_cee_notify); | |||
1371 | * No attempt is made to reconcile the case where only part of the | 1563 | * No attempt is made to reconcile the case where only part of the |
1372 | * cmd can be completed. | 1564 | * cmd can be completed. |
1373 | */ | 1565 | */ |
1374 | static int dcbnl_ieee_set(struct net_device *netdev, struct nlmsghdr *nlh, | 1566 | static int dcbnl_ieee_set(struct net_device *netdev, struct nlattr **tb, |
1375 | u32 seq, struct nlattr **tb, struct sk_buff *skb) | 1567 | u32 pid, u32 seq, u16 flags) |
1376 | { | 1568 | { |
1377 | const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; | 1569 | const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; |
1378 | struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1]; | 1570 | struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1]; |
1379 | int err; | 1571 | int err = -EOPNOTSUPP; |
1380 | 1572 | ||
1381 | if (!ops) | 1573 | if (!ops) |
1382 | return -EOPNOTSUPP; | 1574 | return err; |
1383 | 1575 | ||
1384 | if (!tb[DCB_ATTR_IEEE]) | 1576 | if (!tb[DCB_ATTR_IEEE]) |
1385 | return -EINVAL; | 1577 | return -EINVAL; |
@@ -1396,14 +1588,6 @@ static int dcbnl_ieee_set(struct net_device *netdev, struct nlmsghdr *nlh, | |||
1396 | goto err; | 1588 | goto err; |
1397 | } | 1589 | } |
1398 | 1590 | ||
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) { | 1591 | if (ieee[DCB_ATTR_IEEE_PFC] && ops->ieee_setpfc) { |
1408 | struct ieee_pfc *pfc = nla_data(ieee[DCB_ATTR_IEEE_PFC]); | 1592 | struct ieee_pfc *pfc = nla_data(ieee[DCB_ATTR_IEEE_PFC]); |
1409 | err = ops->ieee_setpfc(netdev, pfc); | 1593 | err = ops->ieee_setpfc(netdev, pfc); |
@@ -1430,28 +1614,58 @@ static int dcbnl_ieee_set(struct net_device *netdev, struct nlmsghdr *nlh, | |||
1430 | } | 1614 | } |
1431 | 1615 | ||
1432 | err: | 1616 | err: |
1433 | err = nla_put_u8(skb, DCB_ATTR_IEEE, err); | 1617 | dcbnl_reply(err, RTM_SETDCB, DCB_CMD_IEEE_SET, DCB_ATTR_IEEE, |
1618 | pid, seq, flags); | ||
1434 | dcbnl_ieee_notify(netdev, RTM_SETDCB, DCB_CMD_IEEE_SET, seq, 0); | 1619 | dcbnl_ieee_notify(netdev, RTM_SETDCB, DCB_CMD_IEEE_SET, seq, 0); |
1435 | return err; | 1620 | return err; |
1436 | } | 1621 | } |
1437 | 1622 | ||
1438 | static int dcbnl_ieee_get(struct net_device *netdev, struct nlmsghdr *nlh, | 1623 | static int dcbnl_ieee_get(struct net_device *netdev, struct nlattr **tb, |
1439 | u32 seq, struct nlattr **tb, struct sk_buff *skb) | 1624 | u32 pid, u32 seq, u16 flags) |
1440 | { | 1625 | { |
1626 | struct net *net = dev_net(netdev); | ||
1627 | struct sk_buff *skb; | ||
1628 | struct nlmsghdr *nlh; | ||
1629 | struct dcbmsg *dcb; | ||
1441 | const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; | 1630 | const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; |
1631 | int err; | ||
1442 | 1632 | ||
1443 | if (!ops) | 1633 | if (!ops) |
1444 | return -EOPNOTSUPP; | 1634 | return -EOPNOTSUPP; |
1445 | 1635 | ||
1446 | return dcbnl_ieee_fill(skb, netdev); | 1636 | skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
1637 | if (!skb) | ||
1638 | return -ENOBUFS; | ||
1639 | |||
1640 | nlh = nlmsg_put(skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); | ||
1641 | if (nlh == NULL) { | ||
1642 | nlmsg_free(skb); | ||
1643 | return -EMSGSIZE; | ||
1644 | } | ||
1645 | |||
1646 | dcb = NLMSG_DATA(nlh); | ||
1647 | dcb->dcb_family = AF_UNSPEC; | ||
1648 | dcb->cmd = DCB_CMD_IEEE_GET; | ||
1649 | |||
1650 | err = dcbnl_ieee_fill(skb, netdev); | ||
1651 | |||
1652 | if (err < 0) { | ||
1653 | nlmsg_cancel(skb, nlh); | ||
1654 | kfree_skb(skb); | ||
1655 | } else { | ||
1656 | nlmsg_end(skb, nlh); | ||
1657 | err = rtnl_unicast(skb, net, pid); | ||
1658 | } | ||
1659 | |||
1660 | return err; | ||
1447 | } | 1661 | } |
1448 | 1662 | ||
1449 | static int dcbnl_ieee_del(struct net_device *netdev, struct nlmsghdr *nlh, | 1663 | static int dcbnl_ieee_del(struct net_device *netdev, struct nlattr **tb, |
1450 | u32 seq, struct nlattr **tb, struct sk_buff *skb) | 1664 | u32 pid, u32 seq, u16 flags) |
1451 | { | 1665 | { |
1452 | const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; | 1666 | const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; |
1453 | struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1]; | 1667 | struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1]; |
1454 | int err; | 1668 | int err = -EOPNOTSUPP; |
1455 | 1669 | ||
1456 | if (!ops) | 1670 | if (!ops) |
1457 | return -EOPNOTSUPP; | 1671 | return -EOPNOTSUPP; |
@@ -1484,26 +1698,32 @@ static int dcbnl_ieee_del(struct net_device *netdev, struct nlmsghdr *nlh, | |||
1484 | } | 1698 | } |
1485 | 1699 | ||
1486 | err: | 1700 | err: |
1487 | err = nla_put_u8(skb, DCB_ATTR_IEEE, err); | 1701 | dcbnl_reply(err, RTM_SETDCB, DCB_CMD_IEEE_DEL, DCB_ATTR_IEEE, |
1702 | pid, seq, flags); | ||
1488 | dcbnl_ieee_notify(netdev, RTM_SETDCB, DCB_CMD_IEEE_DEL, seq, 0); | 1703 | dcbnl_ieee_notify(netdev, RTM_SETDCB, DCB_CMD_IEEE_DEL, seq, 0); |
1489 | return err; | 1704 | return err; |
1490 | } | 1705 | } |
1491 | 1706 | ||
1492 | 1707 | ||
1493 | /* DCBX configuration */ | 1708 | /* DCBX configuration */ |
1494 | static int dcbnl_getdcbx(struct net_device *netdev, struct nlmsghdr *nlh, | 1709 | static int dcbnl_getdcbx(struct net_device *netdev, struct nlattr **tb, |
1495 | u32 seq, struct nlattr **tb, struct sk_buff *skb) | 1710 | u32 pid, u32 seq, u16 flags) |
1496 | { | 1711 | { |
1712 | int ret; | ||
1713 | |||
1497 | if (!netdev->dcbnl_ops->getdcbx) | 1714 | if (!netdev->dcbnl_ops->getdcbx) |
1498 | return -EOPNOTSUPP; | 1715 | return -EOPNOTSUPP; |
1499 | 1716 | ||
1500 | return nla_put_u8(skb, DCB_ATTR_DCBX, | 1717 | ret = dcbnl_reply(netdev->dcbnl_ops->getdcbx(netdev), RTM_GETDCB, |
1501 | netdev->dcbnl_ops->getdcbx(netdev)); | 1718 | DCB_CMD_GDCBX, DCB_ATTR_DCBX, pid, seq, flags); |
1719 | |||
1720 | return ret; | ||
1502 | } | 1721 | } |
1503 | 1722 | ||
1504 | static int dcbnl_setdcbx(struct net_device *netdev, struct nlmsghdr *nlh, | 1723 | static int dcbnl_setdcbx(struct net_device *netdev, struct nlattr **tb, |
1505 | u32 seq, struct nlattr **tb, struct sk_buff *skb) | 1724 | u32 pid, u32 seq, u16 flags) |
1506 | { | 1725 | { |
1726 | int ret; | ||
1507 | u8 value; | 1727 | u8 value; |
1508 | 1728 | ||
1509 | if (!netdev->dcbnl_ops->setdcbx) | 1729 | if (!netdev->dcbnl_ops->setdcbx) |
@@ -1514,13 +1734,19 @@ static int dcbnl_setdcbx(struct net_device *netdev, struct nlmsghdr *nlh, | |||
1514 | 1734 | ||
1515 | value = nla_get_u8(tb[DCB_ATTR_DCBX]); | 1735 | value = nla_get_u8(tb[DCB_ATTR_DCBX]); |
1516 | 1736 | ||
1517 | return nla_put_u8(skb, DCB_ATTR_DCBX, | 1737 | ret = dcbnl_reply(netdev->dcbnl_ops->setdcbx(netdev, value), |
1518 | netdev->dcbnl_ops->setdcbx(netdev, value)); | 1738 | RTM_SETDCB, DCB_CMD_SDCBX, DCB_ATTR_DCBX, |
1739 | pid, seq, flags); | ||
1740 | |||
1741 | return ret; | ||
1519 | } | 1742 | } |
1520 | 1743 | ||
1521 | static int dcbnl_getfeatcfg(struct net_device *netdev, struct nlmsghdr *nlh, | 1744 | static int dcbnl_getfeatcfg(struct net_device *netdev, struct nlattr **tb, |
1522 | u32 seq, struct nlattr **tb, struct sk_buff *skb) | 1745 | u32 pid, u32 seq, u16 flags) |
1523 | { | 1746 | { |
1747 | struct sk_buff *dcbnl_skb; | ||
1748 | struct nlmsghdr *nlh; | ||
1749 | struct dcbmsg *dcb; | ||
1524 | struct nlattr *data[DCB_FEATCFG_ATTR_MAX + 1], *nest; | 1750 | struct nlattr *data[DCB_FEATCFG_ATTR_MAX + 1], *nest; |
1525 | u8 value; | 1751 | u8 value; |
1526 | int ret, i; | 1752 | int ret, i; |
@@ -1535,11 +1761,25 @@ static int dcbnl_getfeatcfg(struct net_device *netdev, struct nlmsghdr *nlh, | |||
1535 | ret = nla_parse_nested(data, DCB_FEATCFG_ATTR_MAX, tb[DCB_ATTR_FEATCFG], | 1761 | ret = nla_parse_nested(data, DCB_FEATCFG_ATTR_MAX, tb[DCB_ATTR_FEATCFG], |
1536 | dcbnl_featcfg_nest); | 1762 | dcbnl_featcfg_nest); |
1537 | if (ret) | 1763 | if (ret) |
1538 | return ret; | 1764 | goto err_out; |
1539 | 1765 | ||
1540 | nest = nla_nest_start(skb, DCB_ATTR_FEATCFG); | 1766 | dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
1541 | if (!nest) | 1767 | if (!dcbnl_skb) { |
1542 | return -EMSGSIZE; | 1768 | ret = -ENOBUFS; |
1769 | goto err_out; | ||
1770 | } | ||
1771 | |||
1772 | nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); | ||
1773 | |||
1774 | dcb = NLMSG_DATA(nlh); | ||
1775 | dcb->dcb_family = AF_UNSPEC; | ||
1776 | dcb->cmd = DCB_CMD_GFEATCFG; | ||
1777 | |||
1778 | nest = nla_nest_start(dcbnl_skb, DCB_ATTR_FEATCFG); | ||
1779 | if (!nest) { | ||
1780 | ret = -EMSGSIZE; | ||
1781 | goto nla_put_failure; | ||
1782 | } | ||
1543 | 1783 | ||
1544 | if (data[DCB_FEATCFG_ATTR_ALL]) | 1784 | if (data[DCB_FEATCFG_ATTR_ALL]) |
1545 | getall = 1; | 1785 | getall = 1; |
@@ -1550,21 +1790,28 @@ static int dcbnl_getfeatcfg(struct net_device *netdev, struct nlmsghdr *nlh, | |||
1550 | 1790 | ||
1551 | ret = netdev->dcbnl_ops->getfeatcfg(netdev, i, &value); | 1791 | ret = netdev->dcbnl_ops->getfeatcfg(netdev, i, &value); |
1552 | if (!ret) | 1792 | if (!ret) |
1553 | ret = nla_put_u8(skb, i, value); | 1793 | ret = nla_put_u8(dcbnl_skb, i, value); |
1554 | 1794 | ||
1555 | if (ret) { | 1795 | if (ret) { |
1556 | nla_nest_cancel(skb, nest); | 1796 | nla_nest_cancel(dcbnl_skb, nest); |
1557 | goto nla_put_failure; | 1797 | goto nla_put_failure; |
1558 | } | 1798 | } |
1559 | } | 1799 | } |
1560 | nla_nest_end(skb, nest); | 1800 | nla_nest_end(dcbnl_skb, nest); |
1561 | 1801 | ||
1802 | nlmsg_end(dcbnl_skb, nlh); | ||
1803 | |||
1804 | return rtnl_unicast(dcbnl_skb, &init_net, pid); | ||
1562 | nla_put_failure: | 1805 | nla_put_failure: |
1806 | nlmsg_cancel(dcbnl_skb, nlh); | ||
1807 | nlmsg_failure: | ||
1808 | kfree_skb(dcbnl_skb); | ||
1809 | err_out: | ||
1563 | return ret; | 1810 | return ret; |
1564 | } | 1811 | } |
1565 | 1812 | ||
1566 | static int dcbnl_setfeatcfg(struct net_device *netdev, struct nlmsghdr *nlh, | 1813 | static int dcbnl_setfeatcfg(struct net_device *netdev, struct nlattr **tb, |
1567 | u32 seq, struct nlattr **tb, struct sk_buff *skb) | 1814 | u32 pid, u32 seq, u16 flags) |
1568 | { | 1815 | { |
1569 | struct nlattr *data[DCB_FEATCFG_ATTR_MAX + 1]; | 1816 | struct nlattr *data[DCB_FEATCFG_ATTR_MAX + 1]; |
1570 | int ret, i; | 1817 | int ret, i; |
@@ -1594,154 +1841,199 @@ static int dcbnl_setfeatcfg(struct net_device *netdev, struct nlmsghdr *nlh, | |||
1594 | goto err; | 1841 | goto err; |
1595 | } | 1842 | } |
1596 | err: | 1843 | err: |
1597 | ret = nla_put_u8(skb, DCB_ATTR_FEATCFG, ret); | 1844 | dcbnl_reply(ret, RTM_SETDCB, DCB_CMD_SFEATCFG, DCB_ATTR_FEATCFG, |
1845 | pid, seq, flags); | ||
1598 | 1846 | ||
1599 | return ret; | 1847 | return ret; |
1600 | } | 1848 | } |
1601 | 1849 | ||
1602 | /* Handle CEE DCBX GET commands. */ | 1850 | /* Handle CEE DCBX GET commands. */ |
1603 | static int dcbnl_cee_get(struct net_device *netdev, struct nlmsghdr *nlh, | 1851 | static int dcbnl_cee_get(struct net_device *netdev, struct nlattr **tb, |
1604 | u32 seq, struct nlattr **tb, struct sk_buff *skb) | 1852 | u32 pid, u32 seq, u16 flags) |
1605 | { | 1853 | { |
1854 | struct net *net = dev_net(netdev); | ||
1855 | struct sk_buff *skb; | ||
1856 | struct nlmsghdr *nlh; | ||
1857 | struct dcbmsg *dcb; | ||
1606 | const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; | 1858 | const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; |
1859 | int err; | ||
1607 | 1860 | ||
1608 | if (!ops) | 1861 | if (!ops) |
1609 | return -EOPNOTSUPP; | 1862 | return -EOPNOTSUPP; |
1610 | 1863 | ||
1611 | return dcbnl_cee_fill(skb, netdev); | 1864 | skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
1612 | } | 1865 | if (!skb) |
1866 | return -ENOBUFS; | ||
1613 | 1867 | ||
1614 | struct reply_func { | 1868 | nlh = nlmsg_put(skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); |
1615 | /* reply netlink message type */ | 1869 | if (nlh == NULL) { |
1616 | int type; | 1870 | nlmsg_free(skb); |
1871 | return -EMSGSIZE; | ||
1872 | } | ||
1617 | 1873 | ||
1618 | /* function to fill message contents */ | 1874 | dcb = NLMSG_DATA(nlh); |
1619 | int (*cb)(struct net_device *, struct nlmsghdr *, u32, | 1875 | dcb->dcb_family = AF_UNSPEC; |
1620 | struct nlattr **, struct sk_buff *); | 1876 | dcb->cmd = DCB_CMD_CEE_GET; |
1621 | }; | ||
1622 | 1877 | ||
1623 | static const struct reply_func reply_funcs[DCB_CMD_MAX+1] = { | 1878 | err = dcbnl_cee_fill(skb, netdev); |
1624 | [DCB_CMD_GSTATE] = { RTM_GETDCB, dcbnl_getstate }, | 1879 | |
1625 | [DCB_CMD_SSTATE] = { RTM_SETDCB, dcbnl_setstate }, | 1880 | if (err < 0) { |
1626 | [DCB_CMD_PFC_GCFG] = { RTM_GETDCB, dcbnl_getpfccfg }, | 1881 | nlmsg_cancel(skb, nlh); |
1627 | [DCB_CMD_PFC_SCFG] = { RTM_SETDCB, dcbnl_setpfccfg }, | 1882 | nlmsg_free(skb); |
1628 | [DCB_CMD_GPERM_HWADDR] = { RTM_GETDCB, dcbnl_getperm_hwaddr }, | 1883 | } else { |
1629 | [DCB_CMD_GCAP] = { RTM_GETDCB, dcbnl_getcap }, | 1884 | nlmsg_end(skb, nlh); |
1630 | [DCB_CMD_GNUMTCS] = { RTM_GETDCB, dcbnl_getnumtcs }, | 1885 | err = rtnl_unicast(skb, net, pid); |
1631 | [DCB_CMD_SNUMTCS] = { RTM_SETDCB, dcbnl_setnumtcs }, | 1886 | } |
1632 | [DCB_CMD_PFC_GSTATE] = { RTM_GETDCB, dcbnl_getpfcstate }, | 1887 | return err; |
1633 | [DCB_CMD_PFC_SSTATE] = { RTM_SETDCB, dcbnl_setpfcstate }, | 1888 | } |
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 | 1889 | ||
1653 | static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | 1890 | static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) |
1654 | { | 1891 | { |
1655 | struct net *net = sock_net(skb->sk); | 1892 | struct net *net = sock_net(skb->sk); |
1656 | struct net_device *netdev; | 1893 | struct net_device *netdev; |
1657 | struct dcbmsg *dcb = nlmsg_data(nlh); | 1894 | struct dcbmsg *dcb = (struct dcbmsg *)NLMSG_DATA(nlh); |
1658 | struct nlattr *tb[DCB_ATTR_MAX + 1]; | 1895 | struct nlattr *tb[DCB_ATTR_MAX + 1]; |
1659 | u32 portid = skb ? NETLINK_CB(skb).portid : 0; | 1896 | u32 pid = skb ? NETLINK_CB(skb).pid : 0; |
1660 | int ret = -EINVAL; | 1897 | int ret = -EINVAL; |
1661 | struct sk_buff *reply_skb; | ||
1662 | struct nlmsghdr *reply_nlh = NULL; | ||
1663 | const struct reply_func *fn; | ||
1664 | 1898 | ||
1665 | if ((nlh->nlmsg_type == RTM_SETDCB) && !capable(CAP_NET_ADMIN)) | 1899 | if (!net_eq(net, &init_net)) |
1666 | return -EPERM; | 1900 | return -EINVAL; |
1667 | 1901 | ||
1668 | ret = nlmsg_parse(nlh, sizeof(*dcb), tb, DCB_ATTR_MAX, | 1902 | ret = nlmsg_parse(nlh, sizeof(*dcb), tb, DCB_ATTR_MAX, |
1669 | dcbnl_rtnl_policy); | 1903 | dcbnl_rtnl_policy); |
1670 | if (ret < 0) | 1904 | if (ret < 0) |
1671 | return ret; | 1905 | return ret; |
1672 | 1906 | ||
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]) | 1907 | if (!tb[DCB_ATTR_IFNAME]) |
1682 | return -EINVAL; | 1908 | return -EINVAL; |
1683 | 1909 | ||
1684 | netdev = dev_get_by_name(net, nla_data(tb[DCB_ATTR_IFNAME])); | 1910 | netdev = dev_get_by_name(&init_net, nla_data(tb[DCB_ATTR_IFNAME])); |
1685 | if (!netdev) | 1911 | if (!netdev) |
1686 | return -ENODEV; | 1912 | return -EINVAL; |
1687 | 1913 | ||
1688 | if (!netdev->dcbnl_ops) { | 1914 | if (!netdev->dcbnl_ops) |
1689 | ret = -EOPNOTSUPP; | 1915 | goto errout; |
1690 | goto out; | ||
1691 | } | ||
1692 | 1916 | ||
1693 | reply_skb = dcbnl_newmsg(fn->type, dcb->cmd, portid, nlh->nlmsg_seq, | 1917 | switch (dcb->cmd) { |
1694 | nlh->nlmsg_flags, &reply_nlh); | 1918 | case DCB_CMD_GSTATE: |
1695 | if (!reply_skb) { | 1919 | ret = dcbnl_getstate(netdev, tb, pid, nlh->nlmsg_seq, |
1696 | ret = -ENOBUFS; | 1920 | nlh->nlmsg_flags); |
1921 | goto out; | ||
1922 | case DCB_CMD_PFC_GCFG: | ||
1923 | ret = dcbnl_getpfccfg(netdev, tb, pid, nlh->nlmsg_seq, | ||
1924 | nlh->nlmsg_flags); | ||
1925 | goto out; | ||
1926 | case DCB_CMD_GPERM_HWADDR: | ||
1927 | ret = dcbnl_getperm_hwaddr(netdev, tb, pid, nlh->nlmsg_seq, | ||
1928 | nlh->nlmsg_flags); | ||
1929 | goto out; | ||
1930 | case DCB_CMD_PGTX_GCFG: | ||
1931 | ret = dcbnl_pgtx_getcfg(netdev, tb, pid, nlh->nlmsg_seq, | ||
1932 | nlh->nlmsg_flags); | ||
1933 | goto out; | ||
1934 | case DCB_CMD_PGRX_GCFG: | ||
1935 | ret = dcbnl_pgrx_getcfg(netdev, tb, pid, nlh->nlmsg_seq, | ||
1936 | nlh->nlmsg_flags); | ||
1937 | goto out; | ||
1938 | case DCB_CMD_BCN_GCFG: | ||
1939 | ret = dcbnl_bcn_getcfg(netdev, tb, pid, nlh->nlmsg_seq, | ||
1940 | nlh->nlmsg_flags); | ||
1941 | goto out; | ||
1942 | case DCB_CMD_SSTATE: | ||
1943 | ret = dcbnl_setstate(netdev, tb, pid, nlh->nlmsg_seq, | ||
1944 | nlh->nlmsg_flags); | ||
1945 | goto out; | ||
1946 | case DCB_CMD_PFC_SCFG: | ||
1947 | ret = dcbnl_setpfccfg(netdev, tb, pid, nlh->nlmsg_seq, | ||
1948 | nlh->nlmsg_flags); | ||
1697 | goto out; | 1949 | goto out; |
1698 | } | ||
1699 | 1950 | ||
1700 | ret = fn->cb(netdev, nlh, nlh->nlmsg_seq, tb, reply_skb); | 1951 | case DCB_CMD_SET_ALL: |
1701 | if (ret < 0) { | 1952 | ret = dcbnl_setall(netdev, tb, pid, nlh->nlmsg_seq, |
1702 | nlmsg_free(reply_skb); | 1953 | nlh->nlmsg_flags); |
1954 | goto out; | ||
1955 | case DCB_CMD_PGTX_SCFG: | ||
1956 | ret = dcbnl_pgtx_setcfg(netdev, tb, pid, nlh->nlmsg_seq, | ||
1957 | nlh->nlmsg_flags); | ||
1958 | goto out; | ||
1959 | case DCB_CMD_PGRX_SCFG: | ||
1960 | ret = dcbnl_pgrx_setcfg(netdev, tb, pid, nlh->nlmsg_seq, | ||
1961 | nlh->nlmsg_flags); | ||
1962 | goto out; | ||
1963 | case DCB_CMD_GCAP: | ||
1964 | ret = dcbnl_getcap(netdev, tb, pid, nlh->nlmsg_seq, | ||
1965 | nlh->nlmsg_flags); | ||
1966 | goto out; | ||
1967 | case DCB_CMD_GNUMTCS: | ||
1968 | ret = dcbnl_getnumtcs(netdev, tb, pid, nlh->nlmsg_seq, | ||
1969 | nlh->nlmsg_flags); | ||
1970 | goto out; | ||
1971 | case DCB_CMD_SNUMTCS: | ||
1972 | ret = dcbnl_setnumtcs(netdev, tb, pid, nlh->nlmsg_seq, | ||
1973 | nlh->nlmsg_flags); | ||
1974 | goto out; | ||
1975 | case DCB_CMD_PFC_GSTATE: | ||
1976 | ret = dcbnl_getpfcstate(netdev, tb, pid, nlh->nlmsg_seq, | ||
1977 | nlh->nlmsg_flags); | ||
1978 | goto out; | ||
1979 | case DCB_CMD_PFC_SSTATE: | ||
1980 | ret = dcbnl_setpfcstate(netdev, tb, pid, nlh->nlmsg_seq, | ||
1981 | nlh->nlmsg_flags); | ||
1982 | goto out; | ||
1983 | case DCB_CMD_BCN_SCFG: | ||
1984 | ret = dcbnl_bcn_setcfg(netdev, tb, pid, nlh->nlmsg_seq, | ||
1985 | nlh->nlmsg_flags); | ||
1986 | goto out; | ||
1987 | case DCB_CMD_GAPP: | ||
1988 | ret = dcbnl_getapp(netdev, tb, pid, nlh->nlmsg_seq, | ||
1989 | nlh->nlmsg_flags); | ||
1990 | goto out; | ||
1991 | case DCB_CMD_SAPP: | ||
1992 | ret = dcbnl_setapp(netdev, tb, pid, nlh->nlmsg_seq, | ||
1993 | nlh->nlmsg_flags); | ||
1994 | goto out; | ||
1995 | case DCB_CMD_IEEE_SET: | ||
1996 | ret = dcbnl_ieee_set(netdev, tb, pid, nlh->nlmsg_seq, | ||
1997 | nlh->nlmsg_flags); | ||
1998 | goto out; | ||
1999 | case DCB_CMD_IEEE_GET: | ||
2000 | ret = dcbnl_ieee_get(netdev, tb, pid, nlh->nlmsg_seq, | ||
2001 | nlh->nlmsg_flags); | ||
2002 | goto out; | ||
2003 | case DCB_CMD_IEEE_DEL: | ||
2004 | ret = dcbnl_ieee_del(netdev, tb, pid, nlh->nlmsg_seq, | ||
2005 | nlh->nlmsg_flags); | ||
2006 | goto out; | ||
2007 | case DCB_CMD_GDCBX: | ||
2008 | ret = dcbnl_getdcbx(netdev, tb, pid, nlh->nlmsg_seq, | ||
2009 | nlh->nlmsg_flags); | ||
2010 | goto out; | ||
2011 | case DCB_CMD_SDCBX: | ||
2012 | ret = dcbnl_setdcbx(netdev, tb, pid, nlh->nlmsg_seq, | ||
2013 | nlh->nlmsg_flags); | ||
2014 | goto out; | ||
2015 | case DCB_CMD_GFEATCFG: | ||
2016 | ret = dcbnl_getfeatcfg(netdev, tb, pid, nlh->nlmsg_seq, | ||
2017 | nlh->nlmsg_flags); | ||
1703 | goto out; | 2018 | goto out; |
2019 | case DCB_CMD_SFEATCFG: | ||
2020 | ret = dcbnl_setfeatcfg(netdev, tb, pid, nlh->nlmsg_seq, | ||
2021 | nlh->nlmsg_flags); | ||
2022 | goto out; | ||
2023 | case DCB_CMD_CEE_GET: | ||
2024 | ret = dcbnl_cee_get(netdev, tb, pid, nlh->nlmsg_seq, | ||
2025 | nlh->nlmsg_flags); | ||
2026 | goto out; | ||
2027 | default: | ||
2028 | goto errout; | ||
1704 | } | 2029 | } |
1705 | 2030 | errout: | |
1706 | nlmsg_end(reply_skb, reply_nlh); | 2031 | ret = -EINVAL; |
1707 | |||
1708 | ret = rtnl_unicast(reply_skb, net, portid); | ||
1709 | out: | 2032 | out: |
1710 | dev_put(netdev); | 2033 | dev_put(netdev); |
1711 | return ret; | 2034 | return ret; |
1712 | } | 2035 | } |
1713 | 2036 | ||
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 | |||
1745 | /** | 2037 | /** |
1746 | * dcb_getapp - retrieve the DCBX application user priority | 2038 | * dcb_getapp - retrieve the DCBX application user priority |
1747 | * | 2039 | * |
@@ -1755,8 +2047,14 @@ u8 dcb_getapp(struct net_device *dev, struct dcb_app *app) | |||
1755 | u8 prio = 0; | 2047 | u8 prio = 0; |
1756 | 2048 | ||
1757 | spin_lock(&dcb_lock); | 2049 | spin_lock(&dcb_lock); |
1758 | if ((itr = dcb_app_lookup(app, dev->ifindex, 0))) | 2050 | list_for_each_entry(itr, &dcb_app_list, list) { |
1759 | prio = itr->app.priority; | 2051 | if (itr->app.selector == app->selector && |
2052 | itr->app.protocol == app->protocol && | ||
2053 | (strncmp(itr->name, dev->name, IFNAMSIZ) == 0)) { | ||
2054 | prio = itr->app.priority; | ||
2055 | break; | ||
2056 | } | ||
2057 | } | ||
1760 | spin_unlock(&dcb_lock); | 2058 | spin_unlock(&dcb_lock); |
1761 | 2059 | ||
1762 | return prio; | 2060 | return prio; |
@@ -1774,32 +2072,42 @@ int dcb_setapp(struct net_device *dev, struct dcb_app *new) | |||
1774 | { | 2072 | { |
1775 | struct dcb_app_type *itr; | 2073 | struct dcb_app_type *itr; |
1776 | struct dcb_app_type event; | 2074 | struct dcb_app_type event; |
1777 | int err = 0; | ||
1778 | 2075 | ||
1779 | event.ifindex = dev->ifindex; | 2076 | memcpy(&event.name, dev->name, sizeof(event.name)); |
1780 | memcpy(&event.app, new, sizeof(event.app)); | 2077 | memcpy(&event.app, new, sizeof(event.app)); |
1781 | if (dev->dcbnl_ops->getdcbx) | ||
1782 | event.dcbx = dev->dcbnl_ops->getdcbx(dev); | ||
1783 | 2078 | ||
1784 | spin_lock(&dcb_lock); | 2079 | spin_lock(&dcb_lock); |
1785 | /* Search for existing match and replace */ | 2080 | /* Search for existing match and replace */ |
1786 | if ((itr = dcb_app_lookup(new, dev->ifindex, 0))) { | 2081 | list_for_each_entry(itr, &dcb_app_list, list) { |
1787 | if (new->priority) | 2082 | if (itr->app.selector == new->selector && |
1788 | itr->app.priority = new->priority; | 2083 | itr->app.protocol == new->protocol && |
1789 | else { | 2084 | (strncmp(itr->name, dev->name, IFNAMSIZ) == 0)) { |
1790 | list_del(&itr->list); | 2085 | if (new->priority) |
1791 | kfree(itr); | 2086 | itr->app.priority = new->priority; |
2087 | else { | ||
2088 | list_del(&itr->list); | ||
2089 | kfree(itr); | ||
2090 | } | ||
2091 | goto out; | ||
1792 | } | 2092 | } |
1793 | goto out; | ||
1794 | } | 2093 | } |
1795 | /* App type does not exist add new application type */ | 2094 | /* App type does not exist add new application type */ |
1796 | if (new->priority) | 2095 | if (new->priority) { |
1797 | err = dcb_app_add(new, dev->ifindex); | 2096 | struct dcb_app_type *entry; |
2097 | entry = kmalloc(sizeof(struct dcb_app_type), GFP_ATOMIC); | ||
2098 | if (!entry) { | ||
2099 | spin_unlock(&dcb_lock); | ||
2100 | return -ENOMEM; | ||
2101 | } | ||
2102 | |||
2103 | memcpy(&entry->app, new, sizeof(*new)); | ||
2104 | strncpy(entry->name, dev->name, IFNAMSIZ); | ||
2105 | list_add(&entry->list, &dcb_app_list); | ||
2106 | } | ||
1798 | out: | 2107 | out: |
1799 | spin_unlock(&dcb_lock); | 2108 | spin_unlock(&dcb_lock); |
1800 | if (!err) | 2109 | call_dcbevent_notifiers(DCB_APP_EVENT, &event); |
1801 | call_dcbevent_notifiers(DCB_APP_EVENT, &event); | 2110 | return 0; |
1802 | return err; | ||
1803 | } | 2111 | } |
1804 | EXPORT_SYMBOL(dcb_setapp); | 2112 | EXPORT_SYMBOL(dcb_setapp); |
1805 | 2113 | ||
@@ -1816,8 +2124,13 @@ u8 dcb_ieee_getapp_mask(struct net_device *dev, struct dcb_app *app) | |||
1816 | u8 prio = 0; | 2124 | u8 prio = 0; |
1817 | 2125 | ||
1818 | spin_lock(&dcb_lock); | 2126 | spin_lock(&dcb_lock); |
1819 | if ((itr = dcb_app_lookup(app, dev->ifindex, 0))) | 2127 | list_for_each_entry(itr, &dcb_app_list, list) { |
1820 | prio |= 1 << itr->app.priority; | 2128 | if (itr->app.selector == app->selector && |
2129 | itr->app.protocol == app->protocol && | ||
2130 | (strncmp(itr->name, dev->name, IFNAMSIZ) == 0)) { | ||
2131 | prio |= 1 << itr->app.priority; | ||
2132 | } | ||
2133 | } | ||
1821 | spin_unlock(&dcb_lock); | 2134 | spin_unlock(&dcb_lock); |
1822 | 2135 | ||
1823 | return prio; | 2136 | return prio; |
@@ -1833,22 +2146,35 @@ EXPORT_SYMBOL(dcb_ieee_getapp_mask); | |||
1833 | */ | 2146 | */ |
1834 | int dcb_ieee_setapp(struct net_device *dev, struct dcb_app *new) | 2147 | int dcb_ieee_setapp(struct net_device *dev, struct dcb_app *new) |
1835 | { | 2148 | { |
2149 | struct dcb_app_type *itr, *entry; | ||
1836 | struct dcb_app_type event; | 2150 | struct dcb_app_type event; |
1837 | int err = 0; | 2151 | int err = 0; |
1838 | 2152 | ||
1839 | event.ifindex = dev->ifindex; | 2153 | memcpy(&event.name, dev->name, sizeof(event.name)); |
1840 | memcpy(&event.app, new, sizeof(event.app)); | 2154 | memcpy(&event.app, new, sizeof(event.app)); |
1841 | if (dev->dcbnl_ops->getdcbx) | ||
1842 | event.dcbx = dev->dcbnl_ops->getdcbx(dev); | ||
1843 | 2155 | ||
1844 | spin_lock(&dcb_lock); | 2156 | spin_lock(&dcb_lock); |
1845 | /* Search for existing match and abort if found */ | 2157 | /* Search for existing match and abort if found */ |
1846 | if (dcb_app_lookup(new, dev->ifindex, new->priority)) { | 2158 | list_for_each_entry(itr, &dcb_app_list, list) { |
1847 | err = -EEXIST; | 2159 | if (itr->app.selector == new->selector && |
2160 | itr->app.protocol == new->protocol && | ||
2161 | itr->app.priority == new->priority && | ||
2162 | (strncmp(itr->name, dev->name, IFNAMSIZ) == 0)) { | ||
2163 | err = -EEXIST; | ||
2164 | goto out; | ||
2165 | } | ||
2166 | } | ||
2167 | |||
2168 | /* App entry does not exist add new entry */ | ||
2169 | entry = kmalloc(sizeof(struct dcb_app_type), GFP_ATOMIC); | ||
2170 | if (!entry) { | ||
2171 | err = -ENOMEM; | ||
1848 | goto out; | 2172 | goto out; |
1849 | } | 2173 | } |
1850 | 2174 | ||
1851 | err = dcb_app_add(new, dev->ifindex); | 2175 | memcpy(&entry->app, new, sizeof(*new)); |
2176 | strncpy(entry->name, dev->name, IFNAMSIZ); | ||
2177 | list_add(&entry->list, &dcb_app_list); | ||
1852 | out: | 2178 | out: |
1853 | spin_unlock(&dcb_lock); | 2179 | spin_unlock(&dcb_lock); |
1854 | if (!err) | 2180 | if (!err) |
@@ -1868,19 +2194,24 @@ int dcb_ieee_delapp(struct net_device *dev, struct dcb_app *del) | |||
1868 | struct dcb_app_type event; | 2194 | struct dcb_app_type event; |
1869 | int err = -ENOENT; | 2195 | int err = -ENOENT; |
1870 | 2196 | ||
1871 | event.ifindex = dev->ifindex; | 2197 | memcpy(&event.name, dev->name, sizeof(event.name)); |
1872 | memcpy(&event.app, del, sizeof(event.app)); | 2198 | memcpy(&event.app, del, sizeof(event.app)); |
1873 | if (dev->dcbnl_ops->getdcbx) | ||
1874 | event.dcbx = dev->dcbnl_ops->getdcbx(dev); | ||
1875 | 2199 | ||
1876 | spin_lock(&dcb_lock); | 2200 | spin_lock(&dcb_lock); |
1877 | /* Search for existing match and remove it. */ | 2201 | /* Search for existing match and remove it. */ |
1878 | if ((itr = dcb_app_lookup(del, dev->ifindex, del->priority))) { | 2202 | list_for_each_entry(itr, &dcb_app_list, list) { |
1879 | list_del(&itr->list); | 2203 | if (itr->app.selector == del->selector && |
1880 | kfree(itr); | 2204 | itr->app.protocol == del->protocol && |
1881 | err = 0; | 2205 | itr->app.priority == del->priority && |
2206 | (strncmp(itr->name, dev->name, IFNAMSIZ) == 0)) { | ||
2207 | list_del(&itr->list); | ||
2208 | kfree(itr); | ||
2209 | err = 0; | ||
2210 | goto out; | ||
2211 | } | ||
1882 | } | 2212 | } |
1883 | 2213 | ||
2214 | out: | ||
1884 | spin_unlock(&dcb_lock); | 2215 | spin_unlock(&dcb_lock); |
1885 | if (!err) | 2216 | if (!err) |
1886 | call_dcbevent_notifiers(DCB_APP_EVENT, &event); | 2217 | call_dcbevent_notifiers(DCB_APP_EVENT, &event); |