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 int nla_put_hwaddr(struct sk_buff
*msg
, int type
, __le64 hwaddr
)
44 return nla_put_u64(msg
, type
, swab64((__force u64
)hwaddr
));
47 static __le64
nla_get_hwaddr(const struct nlattr
*nla
)
49 return ieee802154_devaddr_from_raw(nla_data(nla
));
52 static int nla_put_shortaddr(struct sk_buff
*msg
, int type
, __le16 addr
)
54 return nla_put_u16(msg
, type
, le16_to_cpu(addr
));
57 static __le16
nla_get_shortaddr(const struct nlattr
*nla
)
59 return cpu_to_le16(nla_get_u16(nla
));
62 int ieee802154_nl_assoc_indic(struct net_device
*dev
,
63 struct ieee802154_addr
*addr
, u8 cap
)
67 pr_debug("%s\n", __func__
);
69 if (addr
->mode
!= IEEE802154_ADDR_LONG
) {
70 pr_err("%s: received non-long source address!\n", __func__
);
74 msg
= ieee802154_nl_create(0, IEEE802154_ASSOCIATE_INDIC
);
78 if (nla_put_string(msg
, IEEE802154_ATTR_DEV_NAME
, dev
->name
) ||
79 nla_put_u32(msg
, IEEE802154_ATTR_DEV_INDEX
, dev
->ifindex
) ||
80 nla_put(msg
, IEEE802154_ATTR_HW_ADDR
, IEEE802154_ADDR_LEN
,
82 nla_put_hwaddr(msg
, IEEE802154_ATTR_SRC_HW_ADDR
,
83 addr
->extended_addr
) ||
84 nla_put_u8(msg
, IEEE802154_ATTR_CAPABILITY
, cap
))
87 return ieee802154_nl_mcast(msg
, IEEE802154_COORD_MCGRP
);
93 EXPORT_SYMBOL(ieee802154_nl_assoc_indic
);
95 int ieee802154_nl_assoc_confirm(struct net_device
*dev
, __le16 short_addr
,
100 pr_debug("%s\n", __func__
);
102 msg
= ieee802154_nl_create(0, IEEE802154_ASSOCIATE_CONF
);
106 if (nla_put_string(msg
, IEEE802154_ATTR_DEV_NAME
, dev
->name
) ||
107 nla_put_u32(msg
, IEEE802154_ATTR_DEV_INDEX
, dev
->ifindex
) ||
108 nla_put(msg
, IEEE802154_ATTR_HW_ADDR
, IEEE802154_ADDR_LEN
,
110 nla_put_shortaddr(msg
, IEEE802154_ATTR_SHORT_ADDR
, short_addr
) ||
111 nla_put_u8(msg
, IEEE802154_ATTR_STATUS
, status
))
112 goto nla_put_failure
;
113 return ieee802154_nl_mcast(msg
, IEEE802154_COORD_MCGRP
);
119 EXPORT_SYMBOL(ieee802154_nl_assoc_confirm
);
121 int ieee802154_nl_disassoc_indic(struct net_device
*dev
,
122 struct ieee802154_addr
*addr
, u8 reason
)
126 pr_debug("%s\n", __func__
);
128 msg
= ieee802154_nl_create(0, IEEE802154_DISASSOCIATE_INDIC
);
132 if (nla_put_string(msg
, IEEE802154_ATTR_DEV_NAME
, dev
->name
) ||
133 nla_put_u32(msg
, IEEE802154_ATTR_DEV_INDEX
, dev
->ifindex
) ||
134 nla_put(msg
, IEEE802154_ATTR_HW_ADDR
, IEEE802154_ADDR_LEN
,
136 goto nla_put_failure
;
137 if (addr
->mode
== IEEE802154_ADDR_LONG
) {
138 if (nla_put_hwaddr(msg
, IEEE802154_ATTR_SRC_HW_ADDR
,
139 addr
->extended_addr
))
140 goto nla_put_failure
;
142 if (nla_put_shortaddr(msg
, IEEE802154_ATTR_SRC_SHORT_ADDR
,
144 goto nla_put_failure
;
146 if (nla_put_u8(msg
, IEEE802154_ATTR_REASON
, reason
))
147 goto nla_put_failure
;
148 return ieee802154_nl_mcast(msg
, IEEE802154_COORD_MCGRP
);
154 EXPORT_SYMBOL(ieee802154_nl_disassoc_indic
);
156 int ieee802154_nl_disassoc_confirm(struct net_device
*dev
, u8 status
)
160 pr_debug("%s\n", __func__
);
162 msg
= ieee802154_nl_create(0, IEEE802154_DISASSOCIATE_CONF
);
166 if (nla_put_string(msg
, IEEE802154_ATTR_DEV_NAME
, dev
->name
) ||
167 nla_put_u32(msg
, IEEE802154_ATTR_DEV_INDEX
, dev
->ifindex
) ||
168 nla_put(msg
, IEEE802154_ATTR_HW_ADDR
, IEEE802154_ADDR_LEN
,
170 nla_put_u8(msg
, IEEE802154_ATTR_STATUS
, status
))
171 goto nla_put_failure
;
172 return ieee802154_nl_mcast(msg
, IEEE802154_COORD_MCGRP
);
178 EXPORT_SYMBOL(ieee802154_nl_disassoc_confirm
);
180 int ieee802154_nl_beacon_indic(struct net_device
*dev
, __le16 panid
,
185 pr_debug("%s\n", __func__
);
187 msg
= ieee802154_nl_create(0, IEEE802154_BEACON_NOTIFY_INDIC
);
191 if (nla_put_string(msg
, IEEE802154_ATTR_DEV_NAME
, dev
->name
) ||
192 nla_put_u32(msg
, IEEE802154_ATTR_DEV_INDEX
, dev
->ifindex
) ||
193 nla_put(msg
, IEEE802154_ATTR_HW_ADDR
, IEEE802154_ADDR_LEN
,
195 nla_put_shortaddr(msg
, IEEE802154_ATTR_COORD_SHORT_ADDR
,
197 nla_put_shortaddr(msg
, IEEE802154_ATTR_COORD_PAN_ID
, panid
))
198 goto nla_put_failure
;
199 return ieee802154_nl_mcast(msg
, IEEE802154_COORD_MCGRP
);
205 EXPORT_SYMBOL(ieee802154_nl_beacon_indic
);
207 int ieee802154_nl_scan_confirm(struct net_device
*dev
,
208 u8 status
, u8 scan_type
, u32 unscanned
, u8 page
,
209 u8
*edl
/* , struct list_head *pan_desc_list */)
213 pr_debug("%s\n", __func__
);
215 msg
= ieee802154_nl_create(0, IEEE802154_SCAN_CONF
);
219 if (nla_put_string(msg
, IEEE802154_ATTR_DEV_NAME
, dev
->name
) ||
220 nla_put_u32(msg
, IEEE802154_ATTR_DEV_INDEX
, dev
->ifindex
) ||
221 nla_put(msg
, IEEE802154_ATTR_HW_ADDR
, IEEE802154_ADDR_LEN
,
223 nla_put_u8(msg
, IEEE802154_ATTR_STATUS
, status
) ||
224 nla_put_u8(msg
, IEEE802154_ATTR_SCAN_TYPE
, scan_type
) ||
225 nla_put_u32(msg
, IEEE802154_ATTR_CHANNELS
, unscanned
) ||
226 nla_put_u8(msg
, IEEE802154_ATTR_PAGE
, page
) ||
228 nla_put(msg
, IEEE802154_ATTR_ED_LIST
, 27, edl
)))
229 goto nla_put_failure
;
230 return ieee802154_nl_mcast(msg
, IEEE802154_COORD_MCGRP
);
236 EXPORT_SYMBOL(ieee802154_nl_scan_confirm
);
238 int ieee802154_nl_start_confirm(struct net_device
*dev
, u8 status
)
242 pr_debug("%s\n", __func__
);
244 msg
= ieee802154_nl_create(0, IEEE802154_START_CONF
);
248 if (nla_put_string(msg
, IEEE802154_ATTR_DEV_NAME
, dev
->name
) ||
249 nla_put_u32(msg
, IEEE802154_ATTR_DEV_INDEX
, dev
->ifindex
) ||
250 nla_put(msg
, IEEE802154_ATTR_HW_ADDR
, IEEE802154_ADDR_LEN
,
252 nla_put_u8(msg
, IEEE802154_ATTR_STATUS
, status
))
253 goto nla_put_failure
;
254 return ieee802154_nl_mcast(msg
, IEEE802154_COORD_MCGRP
);
260 EXPORT_SYMBOL(ieee802154_nl_start_confirm
);
262 static int ieee802154_nl_fill_iface(struct sk_buff
*msg
, u32 portid
,
263 u32 seq
, int flags
, struct net_device
*dev
)
266 struct wpan_phy
*phy
;
267 __le16 short_addr
, pan_id
;
269 pr_debug("%s\n", __func__
);
271 hdr
= genlmsg_put(msg
, 0, seq
, &nl802154_family
, flags
,
272 IEEE802154_LIST_IFACE
);
276 phy
= ieee802154_mlme_ops(dev
)->get_phy(dev
);
279 short_addr
= ieee802154_mlme_ops(dev
)->get_short_addr(dev
);
280 pan_id
= ieee802154_mlme_ops(dev
)->get_pan_id(dev
);
282 if (nla_put_string(msg
, IEEE802154_ATTR_DEV_NAME
, dev
->name
) ||
283 nla_put_string(msg
, IEEE802154_ATTR_PHY_NAME
, wpan_phy_name(phy
)) ||
284 nla_put_u32(msg
, IEEE802154_ATTR_DEV_INDEX
, dev
->ifindex
) ||
285 nla_put(msg
, IEEE802154_ATTR_HW_ADDR
, IEEE802154_ADDR_LEN
,
287 nla_put_shortaddr(msg
, IEEE802154_ATTR_SHORT_ADDR
, short_addr
) ||
288 nla_put_shortaddr(msg
, IEEE802154_ATTR_PAN_ID
, pan_id
))
289 goto nla_put_failure
;
291 return genlmsg_end(msg
, hdr
);
295 genlmsg_cancel(msg
, hdr
);
300 /* Requests from userspace */
301 static struct net_device
*ieee802154_nl_get_dev(struct genl_info
*info
)
303 struct net_device
*dev
;
305 if (info
->attrs
[IEEE802154_ATTR_DEV_NAME
]) {
306 char name
[IFNAMSIZ
+ 1];
307 nla_strlcpy(name
, info
->attrs
[IEEE802154_ATTR_DEV_NAME
],
309 dev
= dev_get_by_name(&init_net
, name
);
310 } else if (info
->attrs
[IEEE802154_ATTR_DEV_INDEX
])
311 dev
= dev_get_by_index(&init_net
,
312 nla_get_u32(info
->attrs
[IEEE802154_ATTR_DEV_INDEX
]));
319 if (dev
->type
!= ARPHRD_IEEE802154
) {
327 int ieee802154_associate_req(struct sk_buff
*skb
, struct genl_info
*info
)
329 struct net_device
*dev
;
330 struct ieee802154_addr addr
;
332 int ret
= -EOPNOTSUPP
;
334 if (!info
->attrs
[IEEE802154_ATTR_CHANNEL
] ||
335 !info
->attrs
[IEEE802154_ATTR_COORD_PAN_ID
] ||
336 (!info
->attrs
[IEEE802154_ATTR_COORD_HW_ADDR
] &&
337 !info
->attrs
[IEEE802154_ATTR_COORD_SHORT_ADDR
]) ||
338 !info
->attrs
[IEEE802154_ATTR_CAPABILITY
])
341 dev
= ieee802154_nl_get_dev(info
);
344 if (!ieee802154_mlme_ops(dev
)->assoc_req
)
347 if (info
->attrs
[IEEE802154_ATTR_COORD_HW_ADDR
]) {
348 addr
.mode
= IEEE802154_ADDR_LONG
;
349 addr
.extended_addr
= nla_get_hwaddr(
350 info
->attrs
[IEEE802154_ATTR_COORD_HW_ADDR
]);
352 addr
.mode
= IEEE802154_ADDR_SHORT
;
353 addr
.short_addr
= nla_get_shortaddr(
354 info
->attrs
[IEEE802154_ATTR_COORD_SHORT_ADDR
]);
356 addr
.pan_id
= nla_get_shortaddr(
357 info
->attrs
[IEEE802154_ATTR_COORD_PAN_ID
]);
359 if (info
->attrs
[IEEE802154_ATTR_PAGE
])
360 page
= nla_get_u8(info
->attrs
[IEEE802154_ATTR_PAGE
]);
364 ret
= ieee802154_mlme_ops(dev
)->assoc_req(dev
, &addr
,
365 nla_get_u8(info
->attrs
[IEEE802154_ATTR_CHANNEL
]),
367 nla_get_u8(info
->attrs
[IEEE802154_ATTR_CAPABILITY
]));
374 int ieee802154_associate_resp(struct sk_buff
*skb
, struct genl_info
*info
)
376 struct net_device
*dev
;
377 struct ieee802154_addr addr
;
378 int ret
= -EOPNOTSUPP
;
380 if (!info
->attrs
[IEEE802154_ATTR_STATUS
] ||
381 !info
->attrs
[IEEE802154_ATTR_DEST_HW_ADDR
] ||
382 !info
->attrs
[IEEE802154_ATTR_DEST_SHORT_ADDR
])
385 dev
= ieee802154_nl_get_dev(info
);
388 if (!ieee802154_mlme_ops(dev
)->assoc_resp
)
391 addr
.mode
= IEEE802154_ADDR_LONG
;
392 addr
.extended_addr
= nla_get_hwaddr(
393 info
->attrs
[IEEE802154_ATTR_DEST_HW_ADDR
]);
394 addr
.pan_id
= ieee802154_mlme_ops(dev
)->get_pan_id(dev
);
396 ret
= ieee802154_mlme_ops(dev
)->assoc_resp(dev
, &addr
,
397 nla_get_shortaddr(info
->attrs
[IEEE802154_ATTR_DEST_SHORT_ADDR
]),
398 nla_get_u8(info
->attrs
[IEEE802154_ATTR_STATUS
]));
405 int ieee802154_disassociate_req(struct sk_buff
*skb
, struct genl_info
*info
)
407 struct net_device
*dev
;
408 struct ieee802154_addr addr
;
409 int ret
= -EOPNOTSUPP
;
411 if ((!info
->attrs
[IEEE802154_ATTR_DEST_HW_ADDR
] &&
412 !info
->attrs
[IEEE802154_ATTR_DEST_SHORT_ADDR
]) ||
413 !info
->attrs
[IEEE802154_ATTR_REASON
])
416 dev
= ieee802154_nl_get_dev(info
);
419 if (!ieee802154_mlme_ops(dev
)->disassoc_req
)
422 if (info
->attrs
[IEEE802154_ATTR_DEST_HW_ADDR
]) {
423 addr
.mode
= IEEE802154_ADDR_LONG
;
424 addr
.extended_addr
= nla_get_hwaddr(
425 info
->attrs
[IEEE802154_ATTR_DEST_HW_ADDR
]);
427 addr
.mode
= IEEE802154_ADDR_SHORT
;
428 addr
.short_addr
= nla_get_shortaddr(
429 info
->attrs
[IEEE802154_ATTR_DEST_SHORT_ADDR
]);
431 addr
.pan_id
= ieee802154_mlme_ops(dev
)->get_pan_id(dev
);
433 ret
= ieee802154_mlme_ops(dev
)->disassoc_req(dev
, &addr
,
434 nla_get_u8(info
->attrs
[IEEE802154_ATTR_REASON
]));
442 * PANid, channel, beacon_order = 15, superframe_order = 15,
443 * PAN_coordinator, battery_life_extension = 0,
444 * coord_realignment = 0, security_enable = 0
446 int ieee802154_start_req(struct sk_buff
*skb
, struct genl_info
*info
)
448 struct net_device
*dev
;
449 struct ieee802154_addr addr
;
451 u8 channel
, bcn_ord
, sf_ord
;
453 int pan_coord
, blx
, coord_realign
;
454 int ret
= -EOPNOTSUPP
;
456 if (!info
->attrs
[IEEE802154_ATTR_COORD_PAN_ID
] ||
457 !info
->attrs
[IEEE802154_ATTR_COORD_SHORT_ADDR
] ||
458 !info
->attrs
[IEEE802154_ATTR_CHANNEL
] ||
459 !info
->attrs
[IEEE802154_ATTR_BCN_ORD
] ||
460 !info
->attrs
[IEEE802154_ATTR_SF_ORD
] ||
461 !info
->attrs
[IEEE802154_ATTR_PAN_COORD
] ||
462 !info
->attrs
[IEEE802154_ATTR_BAT_EXT
] ||
463 !info
->attrs
[IEEE802154_ATTR_COORD_REALIGN
]
467 dev
= ieee802154_nl_get_dev(info
);
470 if (!ieee802154_mlme_ops(dev
)->start_req
)
473 addr
.mode
= IEEE802154_ADDR_SHORT
;
474 addr
.short_addr
= nla_get_shortaddr(
475 info
->attrs
[IEEE802154_ATTR_COORD_SHORT_ADDR
]);
476 addr
.pan_id
= nla_get_shortaddr(
477 info
->attrs
[IEEE802154_ATTR_COORD_PAN_ID
]);
479 channel
= nla_get_u8(info
->attrs
[IEEE802154_ATTR_CHANNEL
]);
480 bcn_ord
= nla_get_u8(info
->attrs
[IEEE802154_ATTR_BCN_ORD
]);
481 sf_ord
= nla_get_u8(info
->attrs
[IEEE802154_ATTR_SF_ORD
]);
482 pan_coord
= nla_get_u8(info
->attrs
[IEEE802154_ATTR_PAN_COORD
]);
483 blx
= nla_get_u8(info
->attrs
[IEEE802154_ATTR_BAT_EXT
]);
484 coord_realign
= nla_get_u8(info
->attrs
[IEEE802154_ATTR_COORD_REALIGN
]);
486 if (info
->attrs
[IEEE802154_ATTR_PAGE
])
487 page
= nla_get_u8(info
->attrs
[IEEE802154_ATTR_PAGE
]);
492 if (addr
.short_addr
== cpu_to_le16(IEEE802154_ADDR_BROADCAST
)) {
493 ieee802154_nl_start_confirm(dev
, IEEE802154_NO_SHORT_ADDRESS
);
498 ret
= ieee802154_mlme_ops(dev
)->start_req(dev
, &addr
, channel
, page
,
499 bcn_ord
, sf_ord
, pan_coord
, blx
, coord_realign
);
506 int ieee802154_scan_req(struct sk_buff
*skb
, struct genl_info
*info
)
508 struct net_device
*dev
;
509 int ret
= -EOPNOTSUPP
;
515 if (!info
->attrs
[IEEE802154_ATTR_SCAN_TYPE
] ||
516 !info
->attrs
[IEEE802154_ATTR_CHANNELS
] ||
517 !info
->attrs
[IEEE802154_ATTR_DURATION
])
520 dev
= ieee802154_nl_get_dev(info
);
523 if (!ieee802154_mlme_ops(dev
)->scan_req
)
526 type
= nla_get_u8(info
->attrs
[IEEE802154_ATTR_SCAN_TYPE
]);
527 channels
= nla_get_u32(info
->attrs
[IEEE802154_ATTR_CHANNELS
]);
528 duration
= nla_get_u8(info
->attrs
[IEEE802154_ATTR_DURATION
]);
530 if (info
->attrs
[IEEE802154_ATTR_PAGE
])
531 page
= nla_get_u8(info
->attrs
[IEEE802154_ATTR_PAGE
]);
536 ret
= ieee802154_mlme_ops(dev
)->scan_req(dev
, type
, channels
, page
,
544 int ieee802154_list_iface(struct sk_buff
*skb
, struct genl_info
*info
)
546 /* Request for interface name, index, type, IEEE address,
547 PAN Id, short address */
549 struct net_device
*dev
= NULL
;
552 pr_debug("%s\n", __func__
);
554 dev
= ieee802154_nl_get_dev(info
);
558 msg
= nlmsg_new(NLMSG_DEFAULT_SIZE
, GFP_KERNEL
);
562 rc
= ieee802154_nl_fill_iface(msg
, info
->snd_portid
, info
->snd_seq
,
569 return genlmsg_reply(msg
, info
);
578 int ieee802154_dump_iface(struct sk_buff
*skb
, struct netlink_callback
*cb
)
580 struct net
*net
= sock_net(skb
->sk
);
581 struct net_device
*dev
;
583 int s_idx
= cb
->args
[0];
585 pr_debug("%s\n", __func__
);
588 for_each_netdev(net
, dev
) {
589 if (idx
< s_idx
|| (dev
->type
!= ARPHRD_IEEE802154
))
592 if (ieee802154_nl_fill_iface(skb
, NETLINK_CB(cb
->skb
).portid
,
593 cb
->nlh
->nlmsg_seq
, NLM_F_MULTI
, dev
) < 0)