aboutsummaryrefslogtreecommitdiffstats
path: root/net/ieee802154/netlink.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ieee802154/netlink.c')
-rw-r--r--net/ieee802154/netlink.c106
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}
261EXPORT_SYMBOL(ieee802154_nl_scan_confirm); 263EXPORT_SYMBOL(ieee802154_nl_scan_confirm);
262 264
265static 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
288nla_put_failure:
289 genlmsg_cancel(msg, hdr);
290out:
291 return -EMSGSIZE;
292}
293
263/* Requests from userspace */ 294/* Requests from userspace */
264static struct net_device *ieee802154_nl_get_dev(struct genl_info *info) 295static 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
500static 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);
527out_free:
528 nlmsg_free(msg);
529out_dev:
530 dev_put(dev);
531 return rc;
532
533}
534
535static 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;
553cont:
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
478static struct genl_ops ieee802154_coordinator_ops[] = { 578static 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
486static int __init ieee802154_nl_init(void) 588static int __init ieee802154_nl_init(void)