diff options
author | Dmitry Baryshkov <dbaryshkov@gmail.com> | 2009-08-06 22:58:40 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-08-13 00:54:49 -0400 |
commit | 8e753dd0a82bd266256c20a20b98dfa48f98d21e (patch) | |
tree | 939747b18a115f392e729530b4b06e4398c0d333 /net | |
parent | 48a2f112db5349efb2efadbd94b8cc31a9db84e1 (diff) |
nl802154: add support for dumping WPAN interface information
Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/ieee802154/netlink.c | 106 |
1 files changed, 104 insertions, 2 deletions
diff --git a/net/ieee802154/netlink.c b/net/ieee802154/netlink.c index a615b9d13212..3fe02b394ad6 100644 --- a/net/ieee802154/netlink.c +++ b/net/ieee802154/netlink.c | |||
@@ -19,6 +19,7 @@ | |||
19 | * Written by: | 19 | * Written by: |
20 | * Sergey Lapin <slapin@ossfans.org> | 20 | * Sergey Lapin <slapin@ossfans.org> |
21 | * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> | 21 | * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> |
22 | * Maxim Osipov <maxim.osipov@siemens.com> | ||
22 | */ | 23 | */ |
23 | 24 | ||
24 | #include <linux/kernel.h> | 25 | #include <linux/kernel.h> |
@@ -26,6 +27,7 @@ | |||
26 | #include <linux/netdevice.h> | 27 | #include <linux/netdevice.h> |
27 | #include <net/netlink.h> | 28 | #include <net/netlink.h> |
28 | #include <net/genetlink.h> | 29 | #include <net/genetlink.h> |
30 | #include <net/sock.h> | ||
29 | #include <linux/nl802154.h> | 31 | #include <linux/nl802154.h> |
30 | #include <net/af_ieee802154.h> | 32 | #include <net/af_ieee802154.h> |
31 | #include <net/nl802154.h> | 33 | #include <net/nl802154.h> |
@@ -73,7 +75,7 @@ static int ieee802154_nl_finish(struct sk_buff *msg) | |||
73 | /* XXX: nlh is right at the start of msg */ | 75 | /* XXX: nlh is right at the start of msg */ |
74 | void *hdr = genlmsg_data(NLMSG_DATA(msg->data)); | 76 | void *hdr = genlmsg_data(NLMSG_DATA(msg->data)); |
75 | 77 | ||
76 | if (!genlmsg_end(msg, hdr)) | 78 | if (genlmsg_end(msg, hdr) < 0) |
77 | goto out; | 79 | goto out; |
78 | 80 | ||
79 | return genlmsg_multicast(msg, 0, ieee802154_coord_mcgrp.id, | 81 | return genlmsg_multicast(msg, 0, ieee802154_coord_mcgrp.id, |
@@ -260,6 +262,35 @@ nla_put_failure: | |||
260 | } | 262 | } |
261 | EXPORT_SYMBOL(ieee802154_nl_scan_confirm); | 263 | EXPORT_SYMBOL(ieee802154_nl_scan_confirm); |
262 | 264 | ||
265 | static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 pid, | ||
266 | u32 seq, int flags, struct net_device *dev) | ||
267 | { | ||
268 | void *hdr; | ||
269 | |||
270 | pr_debug("%s\n", __func__); | ||
271 | |||
272 | hdr = genlmsg_put(msg, 0, seq, &ieee802154_coordinator_family, flags, | ||
273 | IEEE802154_LIST_IFACE); | ||
274 | if (!hdr) | ||
275 | goto out; | ||
276 | |||
277 | NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); | ||
278 | NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); | ||
279 | |||
280 | NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, | ||
281 | dev->dev_addr); | ||
282 | NLA_PUT_U16(msg, IEEE802154_ATTR_SHORT_ADDR, | ||
283 | ieee802154_mlme_ops(dev)->get_short_addr(dev)); | ||
284 | NLA_PUT_U16(msg, IEEE802154_ATTR_PAN_ID, | ||
285 | ieee802154_mlme_ops(dev)->get_pan_id(dev)); | ||
286 | return genlmsg_end(msg, hdr); | ||
287 | |||
288 | nla_put_failure: | ||
289 | genlmsg_cancel(msg, hdr); | ||
290 | out: | ||
291 | return -EMSGSIZE; | ||
292 | } | ||
293 | |||
263 | /* Requests from userspace */ | 294 | /* Requests from userspace */ |
264 | static struct net_device *ieee802154_nl_get_dev(struct genl_info *info) | 295 | static struct net_device *ieee802154_nl_get_dev(struct genl_info *info) |
265 | { | 296 | { |
@@ -272,7 +303,7 @@ static struct net_device *ieee802154_nl_get_dev(struct genl_info *info) | |||
272 | dev = dev_get_by_name(&init_net, name); | 303 | dev = dev_get_by_name(&init_net, name); |
273 | } else if (info->attrs[IEEE802154_ATTR_DEV_INDEX]) | 304 | } else if (info->attrs[IEEE802154_ATTR_DEV_INDEX]) |
274 | dev = dev_get_by_index(&init_net, | 305 | dev = dev_get_by_index(&init_net, |
275 | nla_get_u32(info->attrs[IEEE802154_ATTR_DEV_INDEX])); | 306 | nla_get_u32(info->attrs[IEEE802154_ATTR_DEV_INDEX])); |
276 | else | 307 | else |
277 | return NULL; | 308 | return NULL; |
278 | 309 | ||
@@ -466,6 +497,67 @@ static int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info) | |||
466 | return ret; | 497 | return ret; |
467 | } | 498 | } |
468 | 499 | ||
500 | static int ieee802154_list_iface(struct sk_buff *skb, | ||
501 | struct genl_info *info) | ||
502 | { | ||
503 | /* Request for interface name, index, type, IEEE address, | ||
504 | PAN Id, short address */ | ||
505 | struct sk_buff *msg; | ||
506 | struct net_device *dev = NULL; | ||
507 | int rc = -ENOBUFS; | ||
508 | |||
509 | pr_debug("%s\n", __func__); | ||
510 | |||
511 | dev = ieee802154_nl_get_dev(info); | ||
512 | if (!dev) | ||
513 | return -ENODEV; | ||
514 | |||
515 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | ||
516 | if (!msg) | ||
517 | goto out_dev; | ||
518 | |||
519 | rc = ieee802154_nl_fill_iface(msg, info->snd_pid, info->snd_seq, | ||
520 | 0, dev); | ||
521 | if (rc < 0) | ||
522 | goto out_free; | ||
523 | |||
524 | dev_put(dev); | ||
525 | |||
526 | return genlmsg_unicast(&init_net, msg, info->snd_pid); | ||
527 | out_free: | ||
528 | nlmsg_free(msg); | ||
529 | out_dev: | ||
530 | dev_put(dev); | ||
531 | return rc; | ||
532 | |||
533 | } | ||
534 | |||
535 | static int ieee802154_dump_iface(struct sk_buff *skb, | ||
536 | struct netlink_callback *cb) | ||
537 | { | ||
538 | struct net *net = sock_net(skb->sk); | ||
539 | struct net_device *dev; | ||
540 | int idx; | ||
541 | int s_idx = cb->args[0]; | ||
542 | |||
543 | pr_debug("%s\n", __func__); | ||
544 | |||
545 | idx = 0; | ||
546 | for_each_netdev(net, dev) { | ||
547 | if (idx < s_idx || (dev->type != ARPHRD_IEEE802154)) | ||
548 | goto cont; | ||
549 | |||
550 | if (ieee802154_nl_fill_iface(skb, NETLINK_CB(cb->skb).pid, | ||
551 | cb->nlh->nlmsg_seq, NLM_F_MULTI, dev) < 0) | ||
552 | break; | ||
553 | cont: | ||
554 | idx++; | ||
555 | } | ||
556 | cb->args[0] = idx; | ||
557 | |||
558 | return skb->len; | ||
559 | } | ||
560 | |||
469 | #define IEEE802154_OP(_cmd, _func) \ | 561 | #define IEEE802154_OP(_cmd, _func) \ |
470 | { \ | 562 | { \ |
471 | .cmd = _cmd, \ | 563 | .cmd = _cmd, \ |
@@ -475,12 +567,22 @@ static int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info) | |||
475 | .flags = GENL_ADMIN_PERM, \ | 567 | .flags = GENL_ADMIN_PERM, \ |
476 | } | 568 | } |
477 | 569 | ||
570 | #define IEEE802154_DUMP(_cmd, _func, _dump) \ | ||
571 | { \ | ||
572 | .cmd = _cmd, \ | ||
573 | .policy = ieee802154_policy, \ | ||
574 | .doit = _func, \ | ||
575 | .dumpit = _dump, \ | ||
576 | } | ||
577 | |||
478 | static struct genl_ops ieee802154_coordinator_ops[] = { | 578 | static struct genl_ops ieee802154_coordinator_ops[] = { |
479 | IEEE802154_OP(IEEE802154_ASSOCIATE_REQ, ieee802154_associate_req), | 579 | IEEE802154_OP(IEEE802154_ASSOCIATE_REQ, ieee802154_associate_req), |
480 | IEEE802154_OP(IEEE802154_ASSOCIATE_RESP, ieee802154_associate_resp), | 580 | IEEE802154_OP(IEEE802154_ASSOCIATE_RESP, ieee802154_associate_resp), |
481 | IEEE802154_OP(IEEE802154_DISASSOCIATE_REQ, ieee802154_disassociate_req), | 581 | IEEE802154_OP(IEEE802154_DISASSOCIATE_REQ, ieee802154_disassociate_req), |
482 | IEEE802154_OP(IEEE802154_SCAN_REQ, ieee802154_scan_req), | 582 | IEEE802154_OP(IEEE802154_SCAN_REQ, ieee802154_scan_req), |
483 | IEEE802154_OP(IEEE802154_START_REQ, ieee802154_start_req), | 583 | IEEE802154_OP(IEEE802154_START_REQ, ieee802154_start_req), |
584 | IEEE802154_DUMP(IEEE802154_LIST_IFACE, ieee802154_list_iface, | ||
585 | ieee802154_dump_iface), | ||
484 | }; | 586 | }; |
485 | 587 | ||
486 | static int __init ieee802154_nl_init(void) | 588 | static int __init ieee802154_nl_init(void) |