2 * Netlink inteface for IEEE 802.15.4 stack
4 * Copyright 2007, 2008 Siemens AG
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 * Sergey Lapin <slapin@ossfans.org>
21 * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
22 * Maxim Osipov <maxim.osipov@siemens.com>
25 #include <linux/gfp.h>
26 #include <linux/kernel.h>
27 #include <linux/if_arp.h>
28 #include <linux/netdevice.h>
29 #include <net/netlink.h>
30 #include <net/genetlink.h>
32 #include <linux/nl802154.h>
33 #include <linux/export.h>
34 #include <net/af_ieee802154.h>
35 #include <net/nl802154.h>
36 #include <net/ieee802154.h>
37 #include <net/ieee802154_netdev.h>
38 #include <net/wpan-phy.h>
40 #include "ieee802154.h"
42 static struct genl_multicast_group ieee802154_coord_mcgrp = {
43 .name = IEEE802154_MCAST_COORD_NAME,
46 static struct genl_multicast_group ieee802154_beacon_mcgrp = {
47 .name = IEEE802154_MCAST_BEACON_NAME,
50 int ieee802154_nl_assoc_indic(struct net_device *dev,
51 struct ieee802154_addr *addr, u8 cap)
55 pr_debug("%s\n", __func__);
57 if (addr->addr_type != IEEE802154_ADDR_LONG) {
58 pr_err("%s: received non-long source address!\n", __func__);
62 msg = ieee802154_nl_create(0, IEEE802154_ASSOCIATE_INDIC);
66 if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
67 nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
68 nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
70 nla_put(msg, IEEE802154_ATTR_SRC_HW_ADDR, IEEE802154_ADDR_LEN,
72 nla_put_u8(msg, IEEE802154_ATTR_CAPABILITY, cap))
75 return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
81 EXPORT_SYMBOL(ieee802154_nl_assoc_indic);
83 int ieee802154_nl_assoc_confirm(struct net_device *dev, u16 short_addr,
88 pr_debug("%s\n", __func__);
90 msg = ieee802154_nl_create(0, IEEE802154_ASSOCIATE_CONF);
94 if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
95 nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
96 nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
98 nla_put_u16(msg, IEEE802154_ATTR_SHORT_ADDR, short_addr) ||
99 nla_put_u8(msg, IEEE802154_ATTR_STATUS, status))
100 goto nla_put_failure;
101 return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
107 EXPORT_SYMBOL(ieee802154_nl_assoc_confirm);
109 int ieee802154_nl_disassoc_indic(struct net_device *dev,
110 struct ieee802154_addr *addr, u8 reason)
114 pr_debug("%s\n", __func__);
116 msg = ieee802154_nl_create(0, IEEE802154_DISASSOCIATE_INDIC);
120 if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
121 nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
122 nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
124 goto nla_put_failure;
125 if (addr->addr_type == IEEE802154_ADDR_LONG) {
126 if (nla_put(msg, IEEE802154_ATTR_SRC_HW_ADDR, IEEE802154_ADDR_LEN,
128 goto nla_put_failure;
130 if (nla_put_u16(msg, IEEE802154_ATTR_SRC_SHORT_ADDR,
132 goto nla_put_failure;
134 if (nla_put_u8(msg, IEEE802154_ATTR_REASON, reason))
135 goto nla_put_failure;
136 return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
142 EXPORT_SYMBOL(ieee802154_nl_disassoc_indic);
144 int ieee802154_nl_disassoc_confirm(struct net_device *dev, u8 status)
148 pr_debug("%s\n", __func__);
150 msg = ieee802154_nl_create(0, IEEE802154_DISASSOCIATE_CONF);
154 if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
155 nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
156 nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
158 nla_put_u8(msg, IEEE802154_ATTR_STATUS, status))
159 goto nla_put_failure;
160 return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
166 EXPORT_SYMBOL(ieee802154_nl_disassoc_confirm);
168 int ieee802154_nl_beacon_indic(struct net_device *dev,
169 u16 panid, u16 coord_addr)
173 pr_debug("%s\n", __func__);
175 msg = ieee802154_nl_create(0, IEEE802154_BEACON_NOTIFY_INDIC);
179 if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
180 nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
181 nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
183 nla_put_u16(msg, IEEE802154_ATTR_COORD_SHORT_ADDR, coord_addr) ||
184 nla_put_u16(msg, IEEE802154_ATTR_COORD_PAN_ID, panid))
185 goto nla_put_failure;
186 return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
192 EXPORT_SYMBOL(ieee802154_nl_beacon_indic);
194 int ieee802154_nl_scan_confirm(struct net_device *dev,
195 u8 status, u8 scan_type, u32 unscanned, u8 page,
196 u8 *edl/* , struct list_head *pan_desc_list */)
200 pr_debug("%s\n", __func__);
202 msg = ieee802154_nl_create(0, IEEE802154_SCAN_CONF);
206 if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
207 nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
208 nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
210 nla_put_u8(msg, IEEE802154_ATTR_STATUS, status) ||
211 nla_put_u8(msg, IEEE802154_ATTR_SCAN_TYPE, scan_type) ||
212 nla_put_u32(msg, IEEE802154_ATTR_CHANNELS, unscanned) ||
213 nla_put_u8(msg, IEEE802154_ATTR_PAGE, page) ||
215 nla_put(msg, IEEE802154_ATTR_ED_LIST, 27, edl)))
216 goto nla_put_failure;
217 return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
223 EXPORT_SYMBOL(ieee802154_nl_scan_confirm);
225 int ieee802154_nl_start_confirm(struct net_device *dev, u8 status)
229 pr_debug("%s\n", __func__);
231 msg = ieee802154_nl_create(0, IEEE802154_START_CONF);
235 if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
236 nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
237 nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
239 nla_put_u8(msg, IEEE802154_ATTR_STATUS, status))
240 goto nla_put_failure;
241 return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
247 EXPORT_SYMBOL(ieee802154_nl_start_confirm);
249 static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 portid,
250 u32 seq, int flags, struct net_device *dev)
253 struct wpan_phy *phy;
255 pr_debug("%s\n", __func__);
257 hdr = genlmsg_put(msg, 0, seq, &nl802154_family, flags,
258 IEEE802154_LIST_IFACE);
262 phy = ieee802154_mlme_ops(dev)->get_phy(dev);
265 if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
266 nla_put_string(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy)) ||
267 nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
268 nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
270 nla_put_u16(msg, IEEE802154_ATTR_SHORT_ADDR,
271 ieee802154_mlme_ops(dev)->get_short_addr(dev)) ||
272 nla_put_u16(msg, IEEE802154_ATTR_PAN_ID,
273 ieee802154_mlme_ops(dev)->get_pan_id(dev)))
274 goto nla_put_failure;
276 return genlmsg_end(msg, hdr);
280 genlmsg_cancel(msg, hdr);
285 /* Requests from userspace */
286 static struct net_device *ieee802154_nl_get_dev(struct genl_info *info)
288 struct net_device *dev;
290 if (info->attrs[IEEE802154_ATTR_DEV_NAME]) {
291 char name[IFNAMSIZ + 1];
292 nla_strlcpy(name, info->attrs[IEEE802154_ATTR_DEV_NAME],
294 dev = dev_get_by_name(&init_net, name);
295 } else if (info->attrs[IEEE802154_ATTR_DEV_INDEX])
296 dev = dev_get_by_index(&init_net,
297 nla_get_u32(info->attrs[IEEE802154_ATTR_DEV_INDEX]));
304 if (dev->type != ARPHRD_IEEE802154) {
312 static int ieee802154_associate_req(struct sk_buff *skb,
313 struct genl_info *info)
315 struct net_device *dev;
316 struct ieee802154_addr addr;
318 int ret = -EOPNOTSUPP;
320 if (!info->attrs[IEEE802154_ATTR_CHANNEL] ||
321 !info->attrs[IEEE802154_ATTR_COORD_PAN_ID] ||
322 (!info->attrs[IEEE802154_ATTR_COORD_HW_ADDR] &&
323 !info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]) ||
324 !info->attrs[IEEE802154_ATTR_CAPABILITY])
327 dev = ieee802154_nl_get_dev(info);
330 if (!ieee802154_mlme_ops(dev)->assoc_req)
333 if (info->attrs[IEEE802154_ATTR_COORD_HW_ADDR]) {
334 addr.addr_type = IEEE802154_ADDR_LONG;
335 nla_memcpy(addr.hwaddr,
336 info->attrs[IEEE802154_ATTR_COORD_HW_ADDR],
337 IEEE802154_ADDR_LEN);
339 addr.addr_type = IEEE802154_ADDR_SHORT;
340 addr.short_addr = nla_get_u16(
341 info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]);
343 addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]);
345 if (info->attrs[IEEE802154_ATTR_PAGE])
346 page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]);
350 ret = ieee802154_mlme_ops(dev)->assoc_req(dev, &addr,
351 nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]),
353 nla_get_u8(info->attrs[IEEE802154_ATTR_CAPABILITY]));
360 static int ieee802154_associate_resp(struct sk_buff *skb,
361 struct genl_info *info)
363 struct net_device *dev;
364 struct ieee802154_addr addr;
365 int ret = -EOPNOTSUPP;
367 if (!info->attrs[IEEE802154_ATTR_STATUS] ||
368 !info->attrs[IEEE802154_ATTR_DEST_HW_ADDR] ||
369 !info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR])
372 dev = ieee802154_nl_get_dev(info);
375 if (!ieee802154_mlme_ops(dev)->assoc_resp)
378 addr.addr_type = IEEE802154_ADDR_LONG;
379 nla_memcpy(addr.hwaddr, info->attrs[IEEE802154_ATTR_DEST_HW_ADDR],
380 IEEE802154_ADDR_LEN);
381 addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
384 ret = ieee802154_mlme_ops(dev)->assoc_resp(dev, &addr,
385 nla_get_u16(info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]),
386 nla_get_u8(info->attrs[IEEE802154_ATTR_STATUS]));
393 static int ieee802154_disassociate_req(struct sk_buff *skb,
394 struct genl_info *info)
396 struct net_device *dev;
397 struct ieee802154_addr addr;
398 int ret = -EOPNOTSUPP;
400 if ((!info->attrs[IEEE802154_ATTR_DEST_HW_ADDR] &&
401 !info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]) ||
402 !info->attrs[IEEE802154_ATTR_REASON])
405 dev = ieee802154_nl_get_dev(info);
408 if (!ieee802154_mlme_ops(dev)->disassoc_req)
411 if (info->attrs[IEEE802154_ATTR_DEST_HW_ADDR]) {
412 addr.addr_type = IEEE802154_ADDR_LONG;
413 nla_memcpy(addr.hwaddr,
414 info->attrs[IEEE802154_ATTR_DEST_HW_ADDR],
415 IEEE802154_ADDR_LEN);
417 addr.addr_type = IEEE802154_ADDR_SHORT;
418 addr.short_addr = nla_get_u16(
419 info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]);
421 addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
423 ret = ieee802154_mlme_ops(dev)->disassoc_req(dev, &addr,
424 nla_get_u8(info->attrs[IEEE802154_ATTR_REASON]));
432 * PANid, channel, beacon_order = 15, superframe_order = 15,
433 * PAN_coordinator, battery_life_extension = 0,
434 * coord_realignment = 0, security_enable = 0
436 static int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info)
438 struct net_device *dev;
439 struct ieee802154_addr addr;
441 u8 channel, bcn_ord, sf_ord;
443 int pan_coord, blx, coord_realign;
444 int ret = -EOPNOTSUPP;
446 if (!info->attrs[IEEE802154_ATTR_COORD_PAN_ID] ||
447 !info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR] ||
448 !info->attrs[IEEE802154_ATTR_CHANNEL] ||
449 !info->attrs[IEEE802154_ATTR_BCN_ORD] ||
450 !info->attrs[IEEE802154_ATTR_SF_ORD] ||
451 !info->attrs[IEEE802154_ATTR_PAN_COORD] ||
452 !info->attrs[IEEE802154_ATTR_BAT_EXT] ||
453 !info->attrs[IEEE802154_ATTR_COORD_REALIGN]
457 dev = ieee802154_nl_get_dev(info);
460 if (!ieee802154_mlme_ops(dev)->start_req)
463 addr.addr_type = IEEE802154_ADDR_SHORT;
464 addr.short_addr = nla_get_u16(
465 info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]);
466 addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]);
468 channel = nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]);
469 bcn_ord = nla_get_u8(info->attrs[IEEE802154_ATTR_BCN_ORD]);
470 sf_ord = nla_get_u8(info->attrs[IEEE802154_ATTR_SF_ORD]);
471 pan_coord = nla_get_u8(info->attrs[IEEE802154_ATTR_PAN_COORD]);
472 blx = nla_get_u8(info->attrs[IEEE802154_ATTR_BAT_EXT]);
473 coord_realign = nla_get_u8(info->attrs[IEEE802154_ATTR_COORD_REALIGN]);
475 if (info->attrs[IEEE802154_ATTR_PAGE])
476 page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]);
481 if (addr.short_addr == IEEE802154_ADDR_BROADCAST) {
482 ieee802154_nl_start_confirm(dev, IEEE802154_NO_SHORT_ADDRESS);
487 ret = ieee802154_mlme_ops(dev)->start_req(dev, &addr, channel, page,
488 bcn_ord, sf_ord, pan_coord, blx, coord_realign);
495 static int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info)
497 struct net_device *dev;
498 int ret = -EOPNOTSUPP;
504 if (!info->attrs[IEEE802154_ATTR_SCAN_TYPE] ||
505 !info->attrs[IEEE802154_ATTR_CHANNELS] ||
506 !info->attrs[IEEE802154_ATTR_DURATION])
509 dev = ieee802154_nl_get_dev(info);
512 if (!ieee802154_mlme_ops(dev)->scan_req)
515 type = nla_get_u8(info->attrs[IEEE802154_ATTR_SCAN_TYPE]);
516 channels = nla_get_u32(info->attrs[IEEE802154_ATTR_CHANNELS]);
517 duration = nla_get_u8(info->attrs[IEEE802154_ATTR_DURATION]);
519 if (info->attrs[IEEE802154_ATTR_PAGE])
520 page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]);
525 ret = ieee802154_mlme_ops(dev)->scan_req(dev, type, channels, page,
533 static int ieee802154_list_iface(struct sk_buff *skb,
534 struct genl_info *info)
536 /* Request for interface name, index, type, IEEE address,
537 PAN Id, short address */
539 struct net_device *dev = NULL;
542 pr_debug("%s\n", __func__);
544 dev = ieee802154_nl_get_dev(info);
548 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
552 rc = ieee802154_nl_fill_iface(msg, info->snd_portid, info->snd_seq,
559 return genlmsg_reply(msg, info);
568 static int ieee802154_dump_iface(struct sk_buff *skb,
569 struct netlink_callback *cb)
571 struct net *net = sock_net(skb->sk);
572 struct net_device *dev;
574 int s_idx = cb->args[0];
576 pr_debug("%s\n", __func__);
579 for_each_netdev(net, dev) {
580 if (idx < s_idx || (dev->type != ARPHRD_IEEE802154))
583 if (ieee802154_nl_fill_iface(skb, NETLINK_CB(cb->skb).portid,
584 cb->nlh->nlmsg_seq, NLM_F_MULTI, dev) < 0)
594 static struct genl_ops ieee802154_coordinator_ops[] = {
595 IEEE802154_OP(IEEE802154_ASSOCIATE_REQ, ieee802154_associate_req),
596 IEEE802154_OP(IEEE802154_ASSOCIATE_RESP, ieee802154_associate_resp),
597 IEEE802154_OP(IEEE802154_DISASSOCIATE_REQ, ieee802154_disassociate_req),
598 IEEE802154_OP(IEEE802154_SCAN_REQ, ieee802154_scan_req),
599 IEEE802154_OP(IEEE802154_START_REQ, ieee802154_start_req),
600 IEEE802154_DUMP(IEEE802154_LIST_IFACE, ieee802154_list_iface,
601 ieee802154_dump_iface),
605 * No need to unregister as family unregistration will do it.
607 int nl802154_mac_register(void)
612 rc = genl_register_mc_group(&nl802154_family,
613 &ieee802154_coord_mcgrp);
617 rc = genl_register_mc_group(&nl802154_family,
618 &ieee802154_beacon_mcgrp);
622 for (i = 0; i < ARRAY_SIZE(ieee802154_coordinator_ops); i++) {
623 rc = genl_register_ops(&nl802154_family,
624 &ieee802154_coordinator_ops[i]);