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)