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.c172
1 files changed, 164 insertions, 8 deletions
diff --git a/net/ieee802154/netlink.c b/net/ieee802154/netlink.c
index 27eda9fdf3c2..2106ecbf0308 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,10 +27,12 @@
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/ieee802154/af_ieee802154.h> 32#include <net/af_ieee802154.h>
31#include <net/ieee802154/nl802154.h> 33#include <net/nl802154.h>
32#include <net/ieee802154/netdevice.h> 34#include <net/ieee802154.h>
35#include <net/ieee802154_netdev.h>
33 36
34static unsigned int ieee802154_seq_num; 37static unsigned int ieee802154_seq_num;
35 38
@@ -73,7 +76,7 @@ static int ieee802154_nl_finish(struct sk_buff *msg)
73 /* XXX: nlh is right at the start of msg */ 76 /* XXX: nlh is right at the start of msg */
74 void *hdr = genlmsg_data(NLMSG_DATA(msg->data)); 77 void *hdr = genlmsg_data(NLMSG_DATA(msg->data));
75 78
76 if (!genlmsg_end(msg, hdr)) 79 if (genlmsg_end(msg, hdr) < 0)
77 goto out; 80 goto out;
78 81
79 return genlmsg_multicast(msg, 0, ieee802154_coord_mcgrp.id, 82 return genlmsg_multicast(msg, 0, ieee802154_coord_mcgrp.id,
@@ -229,7 +232,7 @@ nla_put_failure:
229EXPORT_SYMBOL(ieee802154_nl_beacon_indic); 232EXPORT_SYMBOL(ieee802154_nl_beacon_indic);
230 233
231int ieee802154_nl_scan_confirm(struct net_device *dev, 234int ieee802154_nl_scan_confirm(struct net_device *dev,
232 u8 status, u8 scan_type, u32 unscanned, 235 u8 status, u8 scan_type, u32 unscanned, u8 page,
233 u8 *edl/* , struct list_head *pan_desc_list */) 236 u8 *edl/* , struct list_head *pan_desc_list */)
234{ 237{
235 struct sk_buff *msg; 238 struct sk_buff *msg;
@@ -248,6 +251,7 @@ int ieee802154_nl_scan_confirm(struct net_device *dev,
248 NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status); 251 NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status);
249 NLA_PUT_U8(msg, IEEE802154_ATTR_SCAN_TYPE, scan_type); 252 NLA_PUT_U8(msg, IEEE802154_ATTR_SCAN_TYPE, scan_type);
250 NLA_PUT_U32(msg, IEEE802154_ATTR_CHANNELS, unscanned); 253 NLA_PUT_U32(msg, IEEE802154_ATTR_CHANNELS, unscanned);
254 NLA_PUT_U8(msg, IEEE802154_ATTR_PAGE, page);
251 255
252 if (edl) 256 if (edl)
253 NLA_PUT(msg, IEEE802154_ATTR_ED_LIST, 27, edl); 257 NLA_PUT(msg, IEEE802154_ATTR_ED_LIST, 27, edl);
@@ -260,6 +264,60 @@ nla_put_failure:
260} 264}
261EXPORT_SYMBOL(ieee802154_nl_scan_confirm); 265EXPORT_SYMBOL(ieee802154_nl_scan_confirm);
262 266
267int ieee802154_nl_start_confirm(struct net_device *dev, u8 status)
268{
269 struct sk_buff *msg;
270
271 pr_debug("%s\n", __func__);
272
273 msg = ieee802154_nl_create(0, IEEE802154_START_CONF);
274 if (!msg)
275 return -ENOBUFS;
276
277 NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
278 NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
279 NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
280 dev->dev_addr);
281
282 NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status);
283
284 return ieee802154_nl_finish(msg);
285
286nla_put_failure:
287 nlmsg_free(msg);
288 return -ENOBUFS;
289}
290EXPORT_SYMBOL(ieee802154_nl_start_confirm);
291
292static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 pid,
293 u32 seq, int flags, struct net_device *dev)
294{
295 void *hdr;
296
297 pr_debug("%s\n", __func__);
298
299 hdr = genlmsg_put(msg, 0, seq, &ieee802154_coordinator_family, flags,
300 IEEE802154_LIST_IFACE);
301 if (!hdr)
302 goto out;
303
304 NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
305 NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
306
307 NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
308 dev->dev_addr);
309 NLA_PUT_U16(msg, IEEE802154_ATTR_SHORT_ADDR,
310 ieee802154_mlme_ops(dev)->get_short_addr(dev));
311 NLA_PUT_U16(msg, IEEE802154_ATTR_PAN_ID,
312 ieee802154_mlme_ops(dev)->get_pan_id(dev));
313 return genlmsg_end(msg, hdr);
314
315nla_put_failure:
316 genlmsg_cancel(msg, hdr);
317out:
318 return -EMSGSIZE;
319}
320
263/* Requests from userspace */ 321/* Requests from userspace */
264static struct net_device *ieee802154_nl_get_dev(struct genl_info *info) 322static struct net_device *ieee802154_nl_get_dev(struct genl_info *info)
265{ 323{
@@ -272,7 +330,7 @@ static struct net_device *ieee802154_nl_get_dev(struct genl_info *info)
272 dev = dev_get_by_name(&init_net, name); 330 dev = dev_get_by_name(&init_net, name);
273 } else if (info->attrs[IEEE802154_ATTR_DEV_INDEX]) 331 } else if (info->attrs[IEEE802154_ATTR_DEV_INDEX])
274 dev = dev_get_by_index(&init_net, 332 dev = dev_get_by_index(&init_net,
275 nla_get_u32(info->attrs[IEEE802154_ATTR_DEV_INDEX])); 333 nla_get_u32(info->attrs[IEEE802154_ATTR_DEV_INDEX]));
276 else 334 else
277 return NULL; 335 return NULL;
278 336
@@ -292,6 +350,7 @@ static int ieee802154_associate_req(struct sk_buff *skb,
292{ 350{
293 struct net_device *dev; 351 struct net_device *dev;
294 struct ieee802154_addr addr; 352 struct ieee802154_addr addr;
353 u8 page;
295 int ret = -EINVAL; 354 int ret = -EINVAL;
296 355
297 if (!info->attrs[IEEE802154_ATTR_CHANNEL] || 356 if (!info->attrs[IEEE802154_ATTR_CHANNEL] ||
@@ -317,8 +376,14 @@ static int ieee802154_associate_req(struct sk_buff *skb,
317 } 376 }
318 addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]); 377 addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]);
319 378
379 if (info->attrs[IEEE802154_ATTR_PAGE])
380 page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]);
381 else
382 page = 0;
383
320 ret = ieee802154_mlme_ops(dev)->assoc_req(dev, &addr, 384 ret = ieee802154_mlme_ops(dev)->assoc_req(dev, &addr,
321 nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]), 385 nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]),
386 page,
322 nla_get_u8(info->attrs[IEEE802154_ATTR_CAPABILITY])); 387 nla_get_u8(info->attrs[IEEE802154_ATTR_CAPABILITY]));
323 388
324 dev_put(dev); 389 dev_put(dev);
@@ -401,6 +466,7 @@ static int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info)
401 struct ieee802154_addr addr; 466 struct ieee802154_addr addr;
402 467
403 u8 channel, bcn_ord, sf_ord; 468 u8 channel, bcn_ord, sf_ord;
469 u8 page;
404 int pan_coord, blx, coord_realign; 470 int pan_coord, blx, coord_realign;
405 int ret; 471 int ret;
406 472
@@ -431,7 +497,19 @@ static int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info)
431 blx = nla_get_u8(info->attrs[IEEE802154_ATTR_BAT_EXT]); 497 blx = nla_get_u8(info->attrs[IEEE802154_ATTR_BAT_EXT]);
432 coord_realign = nla_get_u8(info->attrs[IEEE802154_ATTR_COORD_REALIGN]); 498 coord_realign = nla_get_u8(info->attrs[IEEE802154_ATTR_COORD_REALIGN]);
433 499
434 ret = ieee802154_mlme_ops(dev)->start_req(dev, &addr, channel, 500 if (info->attrs[IEEE802154_ATTR_PAGE])
501 page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]);
502 else
503 page = 0;
504
505
506 if (addr.short_addr == IEEE802154_ADDR_BROADCAST) {
507 ieee802154_nl_start_confirm(dev, IEEE802154_NO_SHORT_ADDRESS);
508 dev_put(dev);
509 return -EINVAL;
510 }
511
512 ret = ieee802154_mlme_ops(dev)->start_req(dev, &addr, channel, page,
435 bcn_ord, sf_ord, pan_coord, blx, coord_realign); 513 bcn_ord, sf_ord, pan_coord, blx, coord_realign);
436 514
437 dev_put(dev); 515 dev_put(dev);
@@ -445,6 +523,7 @@ static int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info)
445 u8 type; 523 u8 type;
446 u32 channels; 524 u32 channels;
447 u8 duration; 525 u8 duration;
526 u8 page;
448 527
449 if (!info->attrs[IEEE802154_ATTR_SCAN_TYPE] || 528 if (!info->attrs[IEEE802154_ATTR_SCAN_TYPE] ||
450 !info->attrs[IEEE802154_ATTR_CHANNELS] || 529 !info->attrs[IEEE802154_ATTR_CHANNELS] ||
@@ -459,13 +538,80 @@ static int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info)
459 channels = nla_get_u32(info->attrs[IEEE802154_ATTR_CHANNELS]); 538 channels = nla_get_u32(info->attrs[IEEE802154_ATTR_CHANNELS]);
460 duration = nla_get_u8(info->attrs[IEEE802154_ATTR_DURATION]); 539 duration = nla_get_u8(info->attrs[IEEE802154_ATTR_DURATION]);
461 540
462 ret = ieee802154_mlme_ops(dev)->scan_req(dev, type, channels, 541 if (info->attrs[IEEE802154_ATTR_PAGE])
542 page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]);
543 else
544 page = 0;
545
546
547 ret = ieee802154_mlme_ops(dev)->scan_req(dev, type, channels, page,
463 duration); 548 duration);
464 549
465 dev_put(dev); 550 dev_put(dev);
466 return ret; 551 return ret;
467} 552}
468 553
554static int ieee802154_list_iface(struct sk_buff *skb,
555 struct genl_info *info)
556{
557 /* Request for interface name, index, type, IEEE address,
558 PAN Id, short address */
559 struct sk_buff *msg;
560 struct net_device *dev = NULL;
561 int rc = -ENOBUFS;
562
563 pr_debug("%s\n", __func__);
564
565 dev = ieee802154_nl_get_dev(info);
566 if (!dev)
567 return -ENODEV;
568
569 msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
570 if (!msg)
571 goto out_dev;
572
573 rc = ieee802154_nl_fill_iface(msg, info->snd_pid, info->snd_seq,
574 0, dev);
575 if (rc < 0)
576 goto out_free;
577
578 dev_put(dev);
579
580 return genlmsg_unicast(&init_net, msg, info->snd_pid);
581out_free:
582 nlmsg_free(msg);
583out_dev:
584 dev_put(dev);
585 return rc;
586
587}
588
589static int ieee802154_dump_iface(struct sk_buff *skb,
590 struct netlink_callback *cb)
591{
592 struct net *net = sock_net(skb->sk);
593 struct net_device *dev;
594 int idx;
595 int s_idx = cb->args[0];
596
597 pr_debug("%s\n", __func__);
598
599 idx = 0;
600 for_each_netdev(net, dev) {
601 if (idx < s_idx || (dev->type != ARPHRD_IEEE802154))
602 goto cont;
603
604 if (ieee802154_nl_fill_iface(skb, NETLINK_CB(cb->skb).pid,
605 cb->nlh->nlmsg_seq, NLM_F_MULTI, dev) < 0)
606 break;
607cont:
608 idx++;
609 }
610 cb->args[0] = idx;
611
612 return skb->len;
613}
614
469#define IEEE802154_OP(_cmd, _func) \ 615#define IEEE802154_OP(_cmd, _func) \
470 { \ 616 { \
471 .cmd = _cmd, \ 617 .cmd = _cmd, \
@@ -475,12 +621,22 @@ static int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info)
475 .flags = GENL_ADMIN_PERM, \ 621 .flags = GENL_ADMIN_PERM, \
476 } 622 }
477 623
624#define IEEE802154_DUMP(_cmd, _func, _dump) \
625 { \
626 .cmd = _cmd, \
627 .policy = ieee802154_policy, \
628 .doit = _func, \
629 .dumpit = _dump, \
630 }
631
478static struct genl_ops ieee802154_coordinator_ops[] = { 632static struct genl_ops ieee802154_coordinator_ops[] = {
479 IEEE802154_OP(IEEE802154_ASSOCIATE_REQ, ieee802154_associate_req), 633 IEEE802154_OP(IEEE802154_ASSOCIATE_REQ, ieee802154_associate_req),
480 IEEE802154_OP(IEEE802154_ASSOCIATE_RESP, ieee802154_associate_resp), 634 IEEE802154_OP(IEEE802154_ASSOCIATE_RESP, ieee802154_associate_resp),
481 IEEE802154_OP(IEEE802154_DISASSOCIATE_REQ, ieee802154_disassociate_req), 635 IEEE802154_OP(IEEE802154_DISASSOCIATE_REQ, ieee802154_disassociate_req),
482 IEEE802154_OP(IEEE802154_SCAN_REQ, ieee802154_scan_req), 636 IEEE802154_OP(IEEE802154_SCAN_REQ, ieee802154_scan_req),
483 IEEE802154_OP(IEEE802154_START_REQ, ieee802154_start_req), 637 IEEE802154_OP(IEEE802154_START_REQ, ieee802154_start_req),
638 IEEE802154_DUMP(IEEE802154_LIST_IFACE, ieee802154_list_iface,
639 ieee802154_dump_iface),
484}; 640};
485 641
486static int __init ieee802154_nl_init(void) 642static int __init ieee802154_nl_init(void)