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 int ieee802154_nl_assoc_indic(struct net_device *dev,
43 struct ieee802154_addr *addr, u8 cap)
47 pr_debug("%s\n", __func__);
49 if (addr->addr_type != IEEE802154_ADDR_LONG) {
50 pr_err("%s: received non-long source address!\n", __func__);
54 msg = ieee802154_nl_create(0, IEEE802154_ASSOCIATE_INDIC);
58 if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
59 nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
60 nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
62 nla_put(msg, IEEE802154_ATTR_SRC_HW_ADDR, IEEE802154_ADDR_LEN,
64 nla_put_u8(msg, IEEE802154_ATTR_CAPABILITY, cap))
67 return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP);
73 EXPORT_SYMBOL(ieee802154_nl_assoc_indic);
75 int ieee802154_nl_assoc_confirm(struct net_device *dev, u16 short_addr,
80 pr_debug("%s\n", __func__);
82 msg = ieee802154_nl_create(0, IEEE802154_ASSOCIATE_CONF);
86 if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
87 nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
88 nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
90 nla_put_u16(msg, IEEE802154_ATTR_SHORT_ADDR, short_addr) ||
91 nla_put_u8(msg, IEEE802154_ATTR_STATUS, status))
93 return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP);
99 EXPORT_SYMBOL(ieee802154_nl_assoc_confirm);
101 int ieee802154_nl_disassoc_indic(struct net_device *dev,
102 struct ieee802154_addr *addr, u8 reason)
106 pr_debug("%s\n", __func__);
108 msg = ieee802154_nl_create(0, IEEE802154_DISASSOCIATE_INDIC);
112 if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
113 nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
114 nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
116 goto nla_put_failure;
117 if (addr->addr_type == IEEE802154_ADDR_LONG) {
118 if (nla_put(msg, IEEE802154_ATTR_SRC_HW_ADDR, IEEE802154_ADDR_LEN,
120 goto nla_put_failure;
122 if (nla_put_u16(msg, IEEE802154_ATTR_SRC_SHORT_ADDR,
124 goto nla_put_failure;
126 if (nla_put_u8(msg, IEEE802154_ATTR_REASON, reason))
127 goto nla_put_failure;
128 return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP);
134 EXPORT_SYMBOL(ieee802154_nl_disassoc_indic);
136 int ieee802154_nl_disassoc_confirm(struct net_device *dev, u8 status)
140 pr_debug("%s\n", __func__);
142 msg = ieee802154_nl_create(0, IEEE802154_DISASSOCIATE_CONF);
146 if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
147 nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
148 nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
150 nla_put_u8(msg, IEEE802154_ATTR_STATUS, status))
151 goto nla_put_failure;
152 return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP);
158 EXPORT_SYMBOL(ieee802154_nl_disassoc_confirm);
160 int ieee802154_nl_beacon_indic(struct net_device *dev,
161 u16 panid, u16 coord_addr)
165 pr_debug("%s\n", __func__);
167 msg = ieee802154_nl_create(0, IEEE802154_BEACON_NOTIFY_INDIC);
171 if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
172 nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
173 nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
175 nla_put_u16(msg, IEEE802154_ATTR_COORD_SHORT_ADDR, coord_addr) ||
176 nla_put_u16(msg, IEEE802154_ATTR_COORD_PAN_ID, panid))
177 goto nla_put_failure;
178 return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP);
184 EXPORT_SYMBOL(ieee802154_nl_beacon_indic);
186 int ieee802154_nl_scan_confirm(struct net_device *dev,
187 u8 status, u8 scan_type, u32 unscanned, u8 page,
188 u8 *edl/* , struct list_head *pan_desc_list */)
192 pr_debug("%s\n", __func__);
194 msg = ieee802154_nl_create(0, IEEE802154_SCAN_CONF);
198 if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
199 nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
200 nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
202 nla_put_u8(msg, IEEE802154_ATTR_STATUS, status) ||
203 nla_put_u8(msg, IEEE802154_ATTR_SCAN_TYPE, scan_type) ||
204 nla_put_u32(msg, IEEE802154_ATTR_CHANNELS, unscanned) ||
205 nla_put_u8(msg, IEEE802154_ATTR_PAGE, page) ||
207 nla_put(msg, IEEE802154_ATTR_ED_LIST, 27, edl)))
208 goto nla_put_failure;
209 return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP);
215 EXPORT_SYMBOL(ieee802154_nl_scan_confirm);
217 int ieee802154_nl_start_confirm(struct net_device *dev, u8 status)
221 pr_debug("%s\n", __func__);
223 msg = ieee802154_nl_create(0, IEEE802154_START_CONF);
227 if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
228 nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
229 nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
231 nla_put_u8(msg, IEEE802154_ATTR_STATUS, status))
232 goto nla_put_failure;
233 return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP);
239 EXPORT_SYMBOL(ieee802154_nl_start_confirm);
241 static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 portid,
242 u32 seq, int flags, struct net_device *dev)
245 struct wpan_phy *phy;
247 pr_debug("%s\n", __func__);
249 hdr = genlmsg_put(msg, 0, seq, &nl802154_family, flags,
250 IEEE802154_LIST_IFACE);
254 phy = ieee802154_mlme_ops(dev)->get_phy(dev);
257 if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
258 nla_put_string(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy)) ||
259 nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
260 nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
262 nla_put_u16(msg, IEEE802154_ATTR_SHORT_ADDR,
263 ieee802154_mlme_ops(dev)->get_short_addr(dev)) ||
264 nla_put_u16(msg, IEEE802154_ATTR_PAN_ID,
265 ieee802154_mlme_ops(dev)->get_pan_id(dev)))
266 goto nla_put_failure;
268 return genlmsg_end(msg, hdr);
272 genlmsg_cancel(msg, hdr);
277 /* Requests from userspace */
278 static struct net_device *ieee802154_nl_get_dev(struct genl_info *info)
280 struct net_device *dev;
282 if (info->attrs[IEEE802154_ATTR_DEV_NAME]) {
283 char name[IFNAMSIZ + 1];
284 nla_strlcpy(name, info->attrs[IEEE802154_ATTR_DEV_NAME],
286 dev = dev_get_by_name(&init_net, name);
287 } else if (info->attrs[IEEE802154_ATTR_DEV_INDEX])
288 dev = dev_get_by_index(&init_net,
289 nla_get_u32(info->attrs[IEEE802154_ATTR_DEV_INDEX]));
296 if (dev->type != ARPHRD_IEEE802154) {
304 int ieee802154_associate_req(struct sk_buff *skb, struct genl_info *info)
306 struct net_device *dev;
307 struct ieee802154_addr addr;
309 int ret = -EOPNOTSUPP;
311 if (!info->attrs[IEEE802154_ATTR_CHANNEL] ||
312 !info->attrs[IEEE802154_ATTR_COORD_PAN_ID] ||
313 (!info->attrs[IEEE802154_ATTR_COORD_HW_ADDR] &&
314 !info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]) ||
315 !info->attrs[IEEE802154_ATTR_CAPABILITY])
318 dev = ieee802154_nl_get_dev(info);
321 if (!ieee802154_mlme_ops(dev)->assoc_req)
324 if (info->attrs[IEEE802154_ATTR_COORD_HW_ADDR]) {
325 addr.addr_type = IEEE802154_ADDR_LONG;
326 nla_memcpy(addr.hwaddr,
327 info->attrs[IEEE802154_ATTR_COORD_HW_ADDR],
328 IEEE802154_ADDR_LEN);
330 addr.addr_type = IEEE802154_ADDR_SHORT;
331 addr.short_addr = nla_get_u16(
332 info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]);
334 addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]);
336 if (info->attrs[IEEE802154_ATTR_PAGE])
337 page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]);
341 ret = ieee802154_mlme_ops(dev)->assoc_req(dev, &addr,
342 nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]),
344 nla_get_u8(info->attrs[IEEE802154_ATTR_CAPABILITY]));
351 int ieee802154_associate_resp(struct sk_buff *skb, struct genl_info *info)
353 struct net_device *dev;
354 struct ieee802154_addr addr;
355 int ret = -EOPNOTSUPP;
357 if (!info->attrs[IEEE802154_ATTR_STATUS] ||
358 !info->attrs[IEEE802154_ATTR_DEST_HW_ADDR] ||
359 !info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR])
362 dev = ieee802154_nl_get_dev(info);
365 if (!ieee802154_mlme_ops(dev)->assoc_resp)
368 addr.addr_type = IEEE802154_ADDR_LONG;
369 nla_memcpy(addr.hwaddr, info->attrs[IEEE802154_ATTR_DEST_HW_ADDR],
370 IEEE802154_ADDR_LEN);
371 addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
374 ret = ieee802154_mlme_ops(dev)->assoc_resp(dev, &addr,
375 nla_get_u16(info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]),
376 nla_get_u8(info->attrs[IEEE802154_ATTR_STATUS]));
383 int ieee802154_disassociate_req(struct sk_buff *skb, struct genl_info *info)
385 struct net_device *dev;
386 struct ieee802154_addr addr;
387 int ret = -EOPNOTSUPP;
389 if ((!info->attrs[IEEE802154_ATTR_DEST_HW_ADDR] &&
390 !info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]) ||
391 !info->attrs[IEEE802154_ATTR_REASON])
394 dev = ieee802154_nl_get_dev(info);
397 if (!ieee802154_mlme_ops(dev)->disassoc_req)
400 if (info->attrs[IEEE802154_ATTR_DEST_HW_ADDR]) {
401 addr.addr_type = IEEE802154_ADDR_LONG;
402 nla_memcpy(addr.hwaddr,
403 info->attrs[IEEE802154_ATTR_DEST_HW_ADDR],
404 IEEE802154_ADDR_LEN);
406 addr.addr_type = IEEE802154_ADDR_SHORT;
407 addr.short_addr = nla_get_u16(
408 info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]);
410 addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
412 ret = ieee802154_mlme_ops(dev)->disassoc_req(dev, &addr,
413 nla_get_u8(info->attrs[IEEE802154_ATTR_REASON]));
421 * PANid, channel, beacon_order = 15, superframe_order = 15,
422 * PAN_coordinator, battery_life_extension = 0,
423 * coord_realignment = 0, security_enable = 0
425 int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info)
427 struct net_device *dev;
428 struct ieee802154_addr addr;
430 u8 channel, bcn_ord, sf_ord;
432 int pan_coord, blx, coord_realign;
433 int ret = -EOPNOTSUPP;
435 if (!info->attrs[IEEE802154_ATTR_COORD_PAN_ID] ||
436 !info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR] ||
437 !info->attrs[IEEE802154_ATTR_CHANNEL] ||
438 !info->attrs[IEEE802154_ATTR_BCN_ORD] ||
439 !info->attrs[IEEE802154_ATTR_SF_ORD] ||
440 !info->attrs[IEEE802154_ATTR_PAN_COORD] ||
441 !info->attrs[IEEE802154_ATTR_BAT_EXT] ||
442 !info->attrs[IEEE802154_ATTR_COORD_REALIGN]
446 dev = ieee802154_nl_get_dev(info);
449 if (!ieee802154_mlme_ops(dev)->start_req)
452 addr.addr_type = IEEE802154_ADDR_SHORT;
453 addr.short_addr = nla_get_u16(
454 info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]);
455 addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]);
457 channel = nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]);
458 bcn_ord = nla_get_u8(info->attrs[IEEE802154_ATTR_BCN_ORD]);
459 sf_ord = nla_get_u8(info->attrs[IEEE802154_ATTR_SF_ORD]);
460 pan_coord = nla_get_u8(info->attrs[IEEE802154_ATTR_PAN_COORD]);
461 blx = nla_get_u8(info->attrs[IEEE802154_ATTR_BAT_EXT]);
462 coord_realign = nla_get_u8(info->attrs[IEEE802154_ATTR_COORD_REALIGN]);
464 if (info->attrs[IEEE802154_ATTR_PAGE])
465 page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]);
470 if (addr.short_addr == IEEE802154_ADDR_BROADCAST) {
471 ieee802154_nl_start_confirm(dev, IEEE802154_NO_SHORT_ADDRESS);
476 ret = ieee802154_mlme_ops(dev)->start_req(dev, &addr, channel, page,
477 bcn_ord, sf_ord, pan_coord, blx, coord_realign);
484 int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info)
486 struct net_device *dev;
487 int ret = -EOPNOTSUPP;
493 if (!info->attrs[IEEE802154_ATTR_SCAN_TYPE] ||
494 !info->attrs[IEEE802154_ATTR_CHANNELS] ||
495 !info->attrs[IEEE802154_ATTR_DURATION])
498 dev = ieee802154_nl_get_dev(info);
501 if (!ieee802154_mlme_ops(dev)->scan_req)
504 type = nla_get_u8(info->attrs[IEEE802154_ATTR_SCAN_TYPE]);
505 channels = nla_get_u32(info->attrs[IEEE802154_ATTR_CHANNELS]);
506 duration = nla_get_u8(info->attrs[IEEE802154_ATTR_DURATION]);
508 if (info->attrs[IEEE802154_ATTR_PAGE])
509 page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]);
514 ret = ieee802154_mlme_ops(dev)->scan_req(dev, type, channels, page,
522 int ieee802154_list_iface(struct sk_buff *skb, struct genl_info *info)
524 /* Request for interface name, index, type, IEEE address,
525 PAN Id, short address */
527 struct net_device *dev = NULL;
530 pr_debug("%s\n", __func__);
532 dev = ieee802154_nl_get_dev(info);
536 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
540 rc = ieee802154_nl_fill_iface(msg, info->snd_portid, info->snd_seq,
547 return genlmsg_reply(msg, info);
556 int ieee802154_dump_iface(struct sk_buff *skb, struct netlink_callback *cb)
558 struct net *net = sock_net(skb->sk);
559 struct net_device *dev;
561 int s_idx = cb->args[0];
563 pr_debug("%s\n", __func__);
566 for_each_netdev(net, dev) {
567 if (idx < s_idx || (dev->type != ARPHRD_IEEE802154))
570 if (ieee802154_nl_fill_iface(skb, NETLINK_CB(cb->skb).portid,
571 cb->nlh->nlmsg_seq, NLM_F_MULTI, dev) < 0)