diff options
-rw-r--r-- | net/ieee802154/nl802154.c | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c index 32e884732eb1..46df7dca92d9 100644 --- a/net/ieee802154/nl802154.c +++ b/net/ieee802154/nl802154.c | |||
@@ -198,6 +198,8 @@ static const struct nla_policy nl802154_policy[NL802154_ATTR_MAX+1] = { | |||
198 | .len = 20-1 }, | 198 | .len = 20-1 }, |
199 | 199 | ||
200 | [NL802154_ATTR_IFINDEX] = { .type = NLA_U32 }, | 200 | [NL802154_ATTR_IFINDEX] = { .type = NLA_U32 }, |
201 | [NL802154_ATTR_IFTYPE] = { .type = NLA_U32 }, | ||
202 | [NL802154_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 }, | ||
201 | 203 | ||
202 | [NL802154_ATTR_WPAN_DEV] = { .type = NLA_U64 }, | 204 | [NL802154_ATTR_WPAN_DEV] = { .type = NLA_U64 }, |
203 | 205 | ||
@@ -209,6 +211,18 @@ static const struct nla_policy nl802154_policy[NL802154_ATTR_MAX+1] = { | |||
209 | [NL802154_ATTR_CCA_MODE] = { .type = NLA_U8, }, | 211 | [NL802154_ATTR_CCA_MODE] = { .type = NLA_U8, }, |
210 | 212 | ||
211 | [NL802154_ATTR_SUPPORTED_CHANNEL] = { .type = NLA_U32, }, | 213 | [NL802154_ATTR_SUPPORTED_CHANNEL] = { .type = NLA_U32, }, |
214 | |||
215 | [NL802154_ATTR_PAN_ID] = { .type = NLA_U16, }, | ||
216 | [NL802154_ATTR_EXTENDED_ADDR] = { .type = NLA_U64 }, | ||
217 | [NL802154_ATTR_SHORT_ADDR] = { .type = NLA_U16, }, | ||
218 | |||
219 | [NL802154_ATTR_MIN_BE] = { .type = NLA_U8, }, | ||
220 | [NL802154_ATTR_MAX_BE] = { .type = NLA_U8, }, | ||
221 | [NL802154_ATTR_MAX_CSMA_BACKOFFS] = { .type = NLA_U8, }, | ||
222 | |||
223 | [NL802154_ATTR_MAX_FRAME_RETRIES] = { .type = NLA_S8, }, | ||
224 | |||
225 | [NL802154_ATTR_LBT_MODE] = { .type = NLA_U8, }, | ||
212 | }; | 226 | }; |
213 | 227 | ||
214 | /* message building helper */ | 228 | /* message building helper */ |
@@ -414,6 +428,128 @@ static int nl802154_get_wpan_phy(struct sk_buff *skb, struct genl_info *info) | |||
414 | return genlmsg_reply(msg, info); | 428 | return genlmsg_reply(msg, info); |
415 | } | 429 | } |
416 | 430 | ||
431 | static inline u64 wpan_dev_id(struct wpan_dev *wpan_dev) | ||
432 | { | ||
433 | return (u64)wpan_dev->identifier | | ||
434 | ((u64)wpan_phy_to_rdev(wpan_dev->wpan_phy)->wpan_phy_idx << 32); | ||
435 | } | ||
436 | |||
437 | static int | ||
438 | nl802154_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flags, | ||
439 | struct cfg802154_registered_device *rdev, | ||
440 | struct wpan_dev *wpan_dev) | ||
441 | { | ||
442 | struct net_device *dev = wpan_dev->netdev; | ||
443 | void *hdr; | ||
444 | |||
445 | hdr = nl802154hdr_put(msg, portid, seq, flags, | ||
446 | NL802154_CMD_NEW_INTERFACE); | ||
447 | if (!hdr) | ||
448 | return -1; | ||
449 | |||
450 | if (dev && | ||
451 | (nla_put_u32(msg, NL802154_ATTR_IFINDEX, dev->ifindex) || | ||
452 | nla_put_string(msg, NL802154_ATTR_IFNAME, dev->name))) | ||
453 | goto nla_put_failure; | ||
454 | |||
455 | if (nla_put_u32(msg, NL802154_ATTR_WPAN_PHY, rdev->wpan_phy_idx) || | ||
456 | nla_put_u32(msg, NL802154_ATTR_IFTYPE, wpan_dev->iftype) || | ||
457 | nla_put_u64(msg, NL802154_ATTR_WPAN_DEV, wpan_dev_id(wpan_dev)) || | ||
458 | nla_put_u32(msg, NL802154_ATTR_GENERATION, | ||
459 | rdev->devlist_generation ^ | ||
460 | (cfg802154_rdev_list_generation << 2))) | ||
461 | goto nla_put_failure; | ||
462 | |||
463 | /* address settings */ | ||
464 | if (nla_put_le64(msg, NL802154_ATTR_EXTENDED_ADDR, | ||
465 | wpan_dev->extended_addr) || | ||
466 | nla_put_le16(msg, NL802154_ATTR_SHORT_ADDR, | ||
467 | wpan_dev->short_addr) || | ||
468 | nla_put_le16(msg, NL802154_ATTR_PAN_ID, wpan_dev->pan_id)) | ||
469 | goto nla_put_failure; | ||
470 | |||
471 | /* ARET handling */ | ||
472 | if (nla_put_s8(msg, NL802154_ATTR_MAX_FRAME_RETRIES, | ||
473 | wpan_dev->frame_retries) || | ||
474 | nla_put_u8(msg, NL802154_ATTR_MAX_BE, wpan_dev->max_be) || | ||
475 | nla_put_u8(msg, NL802154_ATTR_MAX_CSMA_BACKOFFS, | ||
476 | wpan_dev->csma_retries) || | ||
477 | nla_put_u8(msg, NL802154_ATTR_MIN_BE, wpan_dev->min_be)) | ||
478 | goto nla_put_failure; | ||
479 | |||
480 | /* listen before transmit */ | ||
481 | if (nla_put_u8(msg, NL802154_ATTR_LBT_MODE, wpan_dev->lbt)) | ||
482 | goto nla_put_failure; | ||
483 | |||
484 | return genlmsg_end(msg, hdr); | ||
485 | |||
486 | nla_put_failure: | ||
487 | genlmsg_cancel(msg, hdr); | ||
488 | return -EMSGSIZE; | ||
489 | } | ||
490 | |||
491 | static int | ||
492 | nl802154_dump_interface(struct sk_buff *skb, struct netlink_callback *cb) | ||
493 | { | ||
494 | int wp_idx = 0; | ||
495 | int if_idx = 0; | ||
496 | int wp_start = cb->args[0]; | ||
497 | int if_start = cb->args[1]; | ||
498 | struct cfg802154_registered_device *rdev; | ||
499 | struct wpan_dev *wpan_dev; | ||
500 | |||
501 | rtnl_lock(); | ||
502 | list_for_each_entry(rdev, &cfg802154_rdev_list, list) { | ||
503 | /* TODO netns compare */ | ||
504 | if (wp_idx < wp_start) { | ||
505 | wp_idx++; | ||
506 | continue; | ||
507 | } | ||
508 | if_idx = 0; | ||
509 | |||
510 | list_for_each_entry(wpan_dev, &rdev->wpan_dev_list, list) { | ||
511 | if (if_idx < if_start) { | ||
512 | if_idx++; | ||
513 | continue; | ||
514 | } | ||
515 | if (nl802154_send_iface(skb, NETLINK_CB(cb->skb).portid, | ||
516 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | ||
517 | rdev, wpan_dev) < 0) { | ||
518 | goto out; | ||
519 | } | ||
520 | if_idx++; | ||
521 | } | ||
522 | |||
523 | wp_idx++; | ||
524 | } | ||
525 | out: | ||
526 | rtnl_unlock(); | ||
527 | |||
528 | cb->args[0] = wp_idx; | ||
529 | cb->args[1] = if_idx; | ||
530 | |||
531 | return skb->len; | ||
532 | } | ||
533 | |||
534 | static int nl802154_get_interface(struct sk_buff *skb, struct genl_info *info) | ||
535 | { | ||
536 | struct sk_buff *msg; | ||
537 | struct cfg802154_registered_device *rdev = info->user_ptr[0]; | ||
538 | struct wpan_dev *wdev = info->user_ptr[1]; | ||
539 | |||
540 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
541 | if (!msg) | ||
542 | return -ENOMEM; | ||
543 | |||
544 | if (nl802154_send_iface(msg, info->snd_portid, info->snd_seq, 0, | ||
545 | rdev, wdev) < 0) { | ||
546 | nlmsg_free(msg); | ||
547 | return -ENOBUFS; | ||
548 | } | ||
549 | |||
550 | return genlmsg_reply(msg, info); | ||
551 | } | ||
552 | |||
417 | #define NL802154_FLAG_NEED_WPAN_PHY 0x01 | 553 | #define NL802154_FLAG_NEED_WPAN_PHY 0x01 |
418 | #define NL802154_FLAG_NEED_NETDEV 0x02 | 554 | #define NL802154_FLAG_NEED_NETDEV 0x02 |
419 | #define NL802154_FLAG_NEED_RTNL 0x04 | 555 | #define NL802154_FLAG_NEED_RTNL 0x04 |
@@ -515,6 +651,15 @@ static const struct genl_ops nl802154_ops[] = { | |||
515 | .internal_flags = NL802154_FLAG_NEED_WPAN_PHY | | 651 | .internal_flags = NL802154_FLAG_NEED_WPAN_PHY | |
516 | NL802154_FLAG_NEED_RTNL, | 652 | NL802154_FLAG_NEED_RTNL, |
517 | }, | 653 | }, |
654 | { | ||
655 | .cmd = NL802154_CMD_GET_INTERFACE, | ||
656 | .doit = nl802154_get_interface, | ||
657 | .dumpit = nl802154_dump_interface, | ||
658 | .policy = nl802154_policy, | ||
659 | /* can be retrieved by unprivileged users */ | ||
660 | .internal_flags = NL802154_FLAG_NEED_WPAN_DEV | | ||
661 | NL802154_FLAG_NEED_RTNL, | ||
662 | }, | ||
518 | }; | 663 | }; |
519 | 664 | ||
520 | /* initialisation/exit functions */ | 665 | /* initialisation/exit functions */ |