xref: /openbmc/linux/net/ieee802154/netlink.c (revision fd589a8f)
1 /*
2  * Netlink inteface for IEEE 802.15.4 stack
3  *
4  * Copyright 2007, 2008 Siemens AG
5  *
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.
9  *
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.
14  *
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.
18  *
19  * Written by:
20  * Sergey Lapin <slapin@ossfans.org>
21  * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
22  * Maxim Osipov <maxim.osipov@siemens.com>
23  */
24 
25 #include <linux/kernel.h>
26 #include <linux/if_arp.h>
27 #include <linux/netdevice.h>
28 #include <net/netlink.h>
29 #include <net/genetlink.h>
30 #include <net/sock.h>
31 #include <linux/nl802154.h>
32 #include <net/af_ieee802154.h>
33 #include <net/nl802154.h>
34 #include <net/ieee802154.h>
35 #include <net/ieee802154_netdev.h>
36 
37 static unsigned int ieee802154_seq_num;
38 static DEFINE_SPINLOCK(ieee802154_seq_lock);
39 
40 static struct genl_family ieee802154_coordinator_family = {
41 	.id		= GENL_ID_GENERATE,
42 	.hdrsize	= 0,
43 	.name		= IEEE802154_NL_NAME,
44 	.version	= 1,
45 	.maxattr	= IEEE802154_ATTR_MAX,
46 };
47 
48 static struct genl_multicast_group ieee802154_coord_mcgrp = {
49 	.name		= IEEE802154_MCAST_COORD_NAME,
50 };
51 
52 static struct genl_multicast_group ieee802154_beacon_mcgrp = {
53 	.name		= IEEE802154_MCAST_BEACON_NAME,
54 };
55 
56 /* Requests to userspace */
57 static struct sk_buff *ieee802154_nl_create(int flags, u8 req)
58 {
59 	void *hdr;
60 	struct sk_buff *msg = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC);
61 	unsigned long f;
62 
63 	if (!msg)
64 		return NULL;
65 
66 	spin_lock_irqsave(&ieee802154_seq_lock, f);
67 	hdr = genlmsg_put(msg, 0, ieee802154_seq_num++,
68 			&ieee802154_coordinator_family, flags, req);
69 	spin_unlock_irqrestore(&ieee802154_seq_lock, f);
70 	if (!hdr) {
71 		nlmsg_free(msg);
72 		return NULL;
73 	}
74 
75 	return msg;
76 }
77 
78 static int ieee802154_nl_finish(struct sk_buff *msg)
79 {
80 	/* XXX: nlh is right at the start of msg */
81 	void *hdr = genlmsg_data(NLMSG_DATA(msg->data));
82 
83 	if (genlmsg_end(msg, hdr) < 0)
84 		goto out;
85 
86 	return genlmsg_multicast(msg, 0, ieee802154_coord_mcgrp.id,
87 			GFP_ATOMIC);
88 out:
89 	nlmsg_free(msg);
90 	return -ENOBUFS;
91 }
92 
93 int ieee802154_nl_assoc_indic(struct net_device *dev,
94 		struct ieee802154_addr *addr, u8 cap)
95 {
96 	struct sk_buff *msg;
97 
98 	pr_debug("%s\n", __func__);
99 
100 	if (addr->addr_type != IEEE802154_ADDR_LONG) {
101 		pr_err("%s: received non-long source address!\n", __func__);
102 		return -EINVAL;
103 	}
104 
105 	msg = ieee802154_nl_create(0, IEEE802154_ASSOCIATE_INDIC);
106 	if (!msg)
107 		return -ENOBUFS;
108 
109 	NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
110 	NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
111 	NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
112 			dev->dev_addr);
113 
114 	NLA_PUT(msg, IEEE802154_ATTR_SRC_HW_ADDR, IEEE802154_ADDR_LEN,
115 			addr->hwaddr);
116 
117 	NLA_PUT_U8(msg, IEEE802154_ATTR_CAPABILITY, cap);
118 
119 	return ieee802154_nl_finish(msg);
120 
121 nla_put_failure:
122 	nlmsg_free(msg);
123 	return -ENOBUFS;
124 }
125 EXPORT_SYMBOL(ieee802154_nl_assoc_indic);
126 
127 int ieee802154_nl_assoc_confirm(struct net_device *dev, u16 short_addr,
128 		u8 status)
129 {
130 	struct sk_buff *msg;
131 
132 	pr_debug("%s\n", __func__);
133 
134 	msg = ieee802154_nl_create(0, IEEE802154_ASSOCIATE_CONF);
135 	if (!msg)
136 		return -ENOBUFS;
137 
138 	NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
139 	NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
140 	NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
141 			dev->dev_addr);
142 
143 	NLA_PUT_U16(msg, IEEE802154_ATTR_SHORT_ADDR, short_addr);
144 	NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status);
145 
146 	return ieee802154_nl_finish(msg);
147 
148 nla_put_failure:
149 	nlmsg_free(msg);
150 	return -ENOBUFS;
151 }
152 EXPORT_SYMBOL(ieee802154_nl_assoc_confirm);
153 
154 int ieee802154_nl_disassoc_indic(struct net_device *dev,
155 		struct ieee802154_addr *addr, u8 reason)
156 {
157 	struct sk_buff *msg;
158 
159 	pr_debug("%s\n", __func__);
160 
161 	msg = ieee802154_nl_create(0, IEEE802154_DISASSOCIATE_INDIC);
162 	if (!msg)
163 		return -ENOBUFS;
164 
165 	NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
166 	NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
167 	NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
168 			dev->dev_addr);
169 
170 	if (addr->addr_type == IEEE802154_ADDR_LONG)
171 		NLA_PUT(msg, IEEE802154_ATTR_SRC_HW_ADDR, IEEE802154_ADDR_LEN,
172 				addr->hwaddr);
173 	else
174 		NLA_PUT_U16(msg, IEEE802154_ATTR_SRC_SHORT_ADDR,
175 				addr->short_addr);
176 
177 	NLA_PUT_U8(msg, IEEE802154_ATTR_REASON, reason);
178 
179 	return ieee802154_nl_finish(msg);
180 
181 nla_put_failure:
182 	nlmsg_free(msg);
183 	return -ENOBUFS;
184 }
185 EXPORT_SYMBOL(ieee802154_nl_disassoc_indic);
186 
187 int ieee802154_nl_disassoc_confirm(struct net_device *dev, u8 status)
188 {
189 	struct sk_buff *msg;
190 
191 	pr_debug("%s\n", __func__);
192 
193 	msg = ieee802154_nl_create(0, IEEE802154_DISASSOCIATE_CONF);
194 	if (!msg)
195 		return -ENOBUFS;
196 
197 	NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
198 	NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
199 	NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
200 			dev->dev_addr);
201 
202 	NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status);
203 
204 	return ieee802154_nl_finish(msg);
205 
206 nla_put_failure:
207 	nlmsg_free(msg);
208 	return -ENOBUFS;
209 }
210 EXPORT_SYMBOL(ieee802154_nl_disassoc_confirm);
211 
212 int ieee802154_nl_beacon_indic(struct net_device *dev,
213 		u16 panid, u16 coord_addr)
214 {
215 	struct sk_buff *msg;
216 
217 	pr_debug("%s\n", __func__);
218 
219 	msg = ieee802154_nl_create(0, IEEE802154_BEACON_NOTIFY_INDIC);
220 	if (!msg)
221 		return -ENOBUFS;
222 
223 	NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
224 	NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
225 	NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
226 			dev->dev_addr);
227 	NLA_PUT_U16(msg, IEEE802154_ATTR_COORD_SHORT_ADDR, coord_addr);
228 	NLA_PUT_U16(msg, IEEE802154_ATTR_COORD_PAN_ID, panid);
229 
230 	return ieee802154_nl_finish(msg);
231 
232 nla_put_failure:
233 	nlmsg_free(msg);
234 	return -ENOBUFS;
235 }
236 EXPORT_SYMBOL(ieee802154_nl_beacon_indic);
237 
238 int ieee802154_nl_scan_confirm(struct net_device *dev,
239 		u8 status, u8 scan_type, u32 unscanned, u8 page,
240 		u8 *edl/* , struct list_head *pan_desc_list */)
241 {
242 	struct sk_buff *msg;
243 
244 	pr_debug("%s\n", __func__);
245 
246 	msg = ieee802154_nl_create(0, IEEE802154_SCAN_CONF);
247 	if (!msg)
248 		return -ENOBUFS;
249 
250 	NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
251 	NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
252 	NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
253 			dev->dev_addr);
254 
255 	NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status);
256 	NLA_PUT_U8(msg, IEEE802154_ATTR_SCAN_TYPE, scan_type);
257 	NLA_PUT_U32(msg, IEEE802154_ATTR_CHANNELS, unscanned);
258 	NLA_PUT_U8(msg, IEEE802154_ATTR_PAGE, page);
259 
260 	if (edl)
261 		NLA_PUT(msg, IEEE802154_ATTR_ED_LIST, 27, edl);
262 
263 	return ieee802154_nl_finish(msg);
264 
265 nla_put_failure:
266 	nlmsg_free(msg);
267 	return -ENOBUFS;
268 }
269 EXPORT_SYMBOL(ieee802154_nl_scan_confirm);
270 
271 int ieee802154_nl_start_confirm(struct net_device *dev, u8 status)
272 {
273 	struct sk_buff *msg;
274 
275 	pr_debug("%s\n", __func__);
276 
277 	msg = ieee802154_nl_create(0, IEEE802154_START_CONF);
278 	if (!msg)
279 		return -ENOBUFS;
280 
281 	NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
282 	NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
283 	NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
284 			dev->dev_addr);
285 
286 	NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status);
287 
288 	return ieee802154_nl_finish(msg);
289 
290 nla_put_failure:
291 	nlmsg_free(msg);
292 	return -ENOBUFS;
293 }
294 EXPORT_SYMBOL(ieee802154_nl_start_confirm);
295 
296 static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 pid,
297 	u32 seq, int flags, struct net_device *dev)
298 {
299 	void *hdr;
300 
301 	pr_debug("%s\n", __func__);
302 
303 	hdr = genlmsg_put(msg, 0, seq, &ieee802154_coordinator_family, flags,
304 		IEEE802154_LIST_IFACE);
305 	if (!hdr)
306 		goto out;
307 
308 	NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
309 	NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
310 
311 	NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
312 		dev->dev_addr);
313 	NLA_PUT_U16(msg, IEEE802154_ATTR_SHORT_ADDR,
314 		ieee802154_mlme_ops(dev)->get_short_addr(dev));
315 	NLA_PUT_U16(msg, IEEE802154_ATTR_PAN_ID,
316 		ieee802154_mlme_ops(dev)->get_pan_id(dev));
317 	return genlmsg_end(msg, hdr);
318 
319 nla_put_failure:
320 	genlmsg_cancel(msg, hdr);
321 out:
322 	return -EMSGSIZE;
323 }
324 
325 /* Requests from userspace */
326 static struct net_device *ieee802154_nl_get_dev(struct genl_info *info)
327 {
328 	struct net_device *dev;
329 
330 	if (info->attrs[IEEE802154_ATTR_DEV_NAME]) {
331 		char name[IFNAMSIZ + 1];
332 		nla_strlcpy(name, info->attrs[IEEE802154_ATTR_DEV_NAME],
333 				sizeof(name));
334 		dev = dev_get_by_name(&init_net, name);
335 	} else if (info->attrs[IEEE802154_ATTR_DEV_INDEX])
336 		dev = dev_get_by_index(&init_net,
337 			nla_get_u32(info->attrs[IEEE802154_ATTR_DEV_INDEX]));
338 	else
339 		return NULL;
340 
341 	if (!dev)
342 		return NULL;
343 
344 	if (dev->type != ARPHRD_IEEE802154) {
345 		dev_put(dev);
346 		return NULL;
347 	}
348 
349 	return dev;
350 }
351 
352 static int ieee802154_associate_req(struct sk_buff *skb,
353 		struct genl_info *info)
354 {
355 	struct net_device *dev;
356 	struct ieee802154_addr addr;
357 	u8 page;
358 	int ret = -EINVAL;
359 
360 	if (!info->attrs[IEEE802154_ATTR_CHANNEL] ||
361 	    !info->attrs[IEEE802154_ATTR_COORD_PAN_ID] ||
362 	    (!info->attrs[IEEE802154_ATTR_COORD_HW_ADDR] &&
363 		!info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]) ||
364 	    !info->attrs[IEEE802154_ATTR_CAPABILITY])
365 		return -EINVAL;
366 
367 	dev = ieee802154_nl_get_dev(info);
368 	if (!dev)
369 		return -ENODEV;
370 
371 	if (info->attrs[IEEE802154_ATTR_COORD_HW_ADDR]) {
372 		addr.addr_type = IEEE802154_ADDR_LONG;
373 		nla_memcpy(addr.hwaddr,
374 				info->attrs[IEEE802154_ATTR_COORD_HW_ADDR],
375 				IEEE802154_ADDR_LEN);
376 	} else {
377 		addr.addr_type = IEEE802154_ADDR_SHORT;
378 		addr.short_addr = nla_get_u16(
379 				info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]);
380 	}
381 	addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]);
382 
383 	if (info->attrs[IEEE802154_ATTR_PAGE])
384 		page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]);
385 	else
386 		page = 0;
387 
388 	ret = ieee802154_mlme_ops(dev)->assoc_req(dev, &addr,
389 			nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]),
390 			page,
391 			nla_get_u8(info->attrs[IEEE802154_ATTR_CAPABILITY]));
392 
393 	dev_put(dev);
394 	return ret;
395 }
396 
397 static int ieee802154_associate_resp(struct sk_buff *skb,
398 		struct genl_info *info)
399 {
400 	struct net_device *dev;
401 	struct ieee802154_addr addr;
402 	int ret = -EINVAL;
403 
404 	if (!info->attrs[IEEE802154_ATTR_STATUS] ||
405 	    !info->attrs[IEEE802154_ATTR_DEST_HW_ADDR] ||
406 	    !info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR])
407 		return -EINVAL;
408 
409 	dev = ieee802154_nl_get_dev(info);
410 	if (!dev)
411 		return -ENODEV;
412 
413 	addr.addr_type = IEEE802154_ADDR_LONG;
414 	nla_memcpy(addr.hwaddr, info->attrs[IEEE802154_ATTR_DEST_HW_ADDR],
415 			IEEE802154_ADDR_LEN);
416 	addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
417 
418 
419 	ret = ieee802154_mlme_ops(dev)->assoc_resp(dev, &addr,
420 		nla_get_u16(info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]),
421 		nla_get_u8(info->attrs[IEEE802154_ATTR_STATUS]));
422 
423 	dev_put(dev);
424 	return ret;
425 }
426 
427 static int ieee802154_disassociate_req(struct sk_buff *skb,
428 		struct genl_info *info)
429 {
430 	struct net_device *dev;
431 	struct ieee802154_addr addr;
432 	int ret = -EINVAL;
433 
434 	if ((!info->attrs[IEEE802154_ATTR_DEST_HW_ADDR] &&
435 		!info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]) ||
436 	    !info->attrs[IEEE802154_ATTR_REASON])
437 		return -EINVAL;
438 
439 	dev = ieee802154_nl_get_dev(info);
440 	if (!dev)
441 		return -ENODEV;
442 
443 	if (info->attrs[IEEE802154_ATTR_DEST_HW_ADDR]) {
444 		addr.addr_type = IEEE802154_ADDR_LONG;
445 		nla_memcpy(addr.hwaddr,
446 				info->attrs[IEEE802154_ATTR_DEST_HW_ADDR],
447 				IEEE802154_ADDR_LEN);
448 	} else {
449 		addr.addr_type = IEEE802154_ADDR_SHORT;
450 		addr.short_addr = nla_get_u16(
451 				info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]);
452 	}
453 	addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
454 
455 	ret = ieee802154_mlme_ops(dev)->disassoc_req(dev, &addr,
456 			nla_get_u8(info->attrs[IEEE802154_ATTR_REASON]));
457 
458 	dev_put(dev);
459 	return ret;
460 }
461 
462 /*
463  * PANid, channel, beacon_order = 15, superframe_order = 15,
464  * PAN_coordinator, battery_life_extension = 0,
465  * coord_realignment = 0, security_enable = 0
466 */
467 static int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info)
468 {
469 	struct net_device *dev;
470 	struct ieee802154_addr addr;
471 
472 	u8 channel, bcn_ord, sf_ord;
473 	u8 page;
474 	int pan_coord, blx, coord_realign;
475 	int ret;
476 
477 	if (!info->attrs[IEEE802154_ATTR_COORD_PAN_ID] ||
478 	    !info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR] ||
479 	    !info->attrs[IEEE802154_ATTR_CHANNEL] ||
480 	    !info->attrs[IEEE802154_ATTR_BCN_ORD] ||
481 	    !info->attrs[IEEE802154_ATTR_SF_ORD] ||
482 	    !info->attrs[IEEE802154_ATTR_PAN_COORD] ||
483 	    !info->attrs[IEEE802154_ATTR_BAT_EXT] ||
484 	    !info->attrs[IEEE802154_ATTR_COORD_REALIGN]
485 	 )
486 		return -EINVAL;
487 
488 	dev = ieee802154_nl_get_dev(info);
489 	if (!dev)
490 		return -ENODEV;
491 
492 	addr.addr_type = IEEE802154_ADDR_SHORT;
493 	addr.short_addr = nla_get_u16(
494 			info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]);
495 	addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]);
496 
497 	channel = nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]);
498 	bcn_ord = nla_get_u8(info->attrs[IEEE802154_ATTR_BCN_ORD]);
499 	sf_ord = nla_get_u8(info->attrs[IEEE802154_ATTR_SF_ORD]);
500 	pan_coord = nla_get_u8(info->attrs[IEEE802154_ATTR_PAN_COORD]);
501 	blx = nla_get_u8(info->attrs[IEEE802154_ATTR_BAT_EXT]);
502 	coord_realign = nla_get_u8(info->attrs[IEEE802154_ATTR_COORD_REALIGN]);
503 
504 	if (info->attrs[IEEE802154_ATTR_PAGE])
505 		page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]);
506 	else
507 		page = 0;
508 
509 
510 	if (addr.short_addr == IEEE802154_ADDR_BROADCAST) {
511 		ieee802154_nl_start_confirm(dev, IEEE802154_NO_SHORT_ADDRESS);
512 		dev_put(dev);
513 		return -EINVAL;
514 	}
515 
516 	ret = ieee802154_mlme_ops(dev)->start_req(dev, &addr, channel, page,
517 		bcn_ord, sf_ord, pan_coord, blx, coord_realign);
518 
519 	dev_put(dev);
520 	return ret;
521 }
522 
523 static int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info)
524 {
525 	struct net_device *dev;
526 	int ret;
527 	u8 type;
528 	u32 channels;
529 	u8 duration;
530 	u8 page;
531 
532 	if (!info->attrs[IEEE802154_ATTR_SCAN_TYPE] ||
533 	    !info->attrs[IEEE802154_ATTR_CHANNELS] ||
534 	    !info->attrs[IEEE802154_ATTR_DURATION])
535 		return -EINVAL;
536 
537 	dev = ieee802154_nl_get_dev(info);
538 	if (!dev)
539 		return -ENODEV;
540 
541 	type = nla_get_u8(info->attrs[IEEE802154_ATTR_SCAN_TYPE]);
542 	channels = nla_get_u32(info->attrs[IEEE802154_ATTR_CHANNELS]);
543 	duration = nla_get_u8(info->attrs[IEEE802154_ATTR_DURATION]);
544 
545 	if (info->attrs[IEEE802154_ATTR_PAGE])
546 		page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]);
547 	else
548 		page = 0;
549 
550 
551 	ret = ieee802154_mlme_ops(dev)->scan_req(dev, type, channels, page,
552 			duration);
553 
554 	dev_put(dev);
555 	return ret;
556 }
557 
558 static int ieee802154_list_iface(struct sk_buff *skb,
559 	struct genl_info *info)
560 {
561 	/* Request for interface name, index, type, IEEE address,
562 	   PAN Id, short address */
563 	struct sk_buff *msg;
564 	struct net_device *dev = NULL;
565 	int rc = -ENOBUFS;
566 
567 	pr_debug("%s\n", __func__);
568 
569 	dev = ieee802154_nl_get_dev(info);
570 	if (!dev)
571 		return -ENODEV;
572 
573 	msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
574 	if (!msg)
575 		goto out_dev;
576 
577 	rc = ieee802154_nl_fill_iface(msg, info->snd_pid, info->snd_seq,
578 			0, dev);
579 	if (rc < 0)
580 		goto out_free;
581 
582 	dev_put(dev);
583 
584 	return genlmsg_unicast(&init_net, msg, info->snd_pid);
585 out_free:
586 	nlmsg_free(msg);
587 out_dev:
588 	dev_put(dev);
589 	return rc;
590 
591 }
592 
593 static int ieee802154_dump_iface(struct sk_buff *skb,
594 	struct netlink_callback *cb)
595 {
596 	struct net *net = sock_net(skb->sk);
597 	struct net_device *dev;
598 	int idx;
599 	int s_idx = cb->args[0];
600 
601 	pr_debug("%s\n", __func__);
602 
603 	idx = 0;
604 	for_each_netdev(net, dev) {
605 		if (idx < s_idx || (dev->type != ARPHRD_IEEE802154))
606 			goto cont;
607 
608 		if (ieee802154_nl_fill_iface(skb, NETLINK_CB(cb->skb).pid,
609 			cb->nlh->nlmsg_seq, NLM_F_MULTI, dev) < 0)
610 			break;
611 cont:
612 		idx++;
613 	}
614 	cb->args[0] = idx;
615 
616 	return skb->len;
617 }
618 
619 #define IEEE802154_OP(_cmd, _func)			\
620 	{						\
621 		.cmd	= _cmd,				\
622 		.policy	= ieee802154_policy,		\
623 		.doit	= _func,			\
624 		.dumpit	= NULL,				\
625 		.flags	= GENL_ADMIN_PERM,		\
626 	}
627 
628 #define IEEE802154_DUMP(_cmd, _func, _dump)		\
629 	{						\
630 		.cmd	= _cmd,				\
631 		.policy	= ieee802154_policy,		\
632 		.doit	= _func,			\
633 		.dumpit	= _dump,			\
634 	}
635 
636 static struct genl_ops ieee802154_coordinator_ops[] = {
637 	IEEE802154_OP(IEEE802154_ASSOCIATE_REQ, ieee802154_associate_req),
638 	IEEE802154_OP(IEEE802154_ASSOCIATE_RESP, ieee802154_associate_resp),
639 	IEEE802154_OP(IEEE802154_DISASSOCIATE_REQ, ieee802154_disassociate_req),
640 	IEEE802154_OP(IEEE802154_SCAN_REQ, ieee802154_scan_req),
641 	IEEE802154_OP(IEEE802154_START_REQ, ieee802154_start_req),
642 	IEEE802154_DUMP(IEEE802154_LIST_IFACE, ieee802154_list_iface,
643 							ieee802154_dump_iface),
644 };
645 
646 static int __init ieee802154_nl_init(void)
647 {
648 	int rc;
649 	int i;
650 
651 	rc = genl_register_family(&ieee802154_coordinator_family);
652 	if (rc)
653 		goto fail;
654 
655 	rc = genl_register_mc_group(&ieee802154_coordinator_family,
656 			&ieee802154_coord_mcgrp);
657 	if (rc)
658 		goto fail;
659 
660 	rc = genl_register_mc_group(&ieee802154_coordinator_family,
661 			&ieee802154_beacon_mcgrp);
662 	if (rc)
663 		goto fail;
664 
665 
666 	for (i = 0; i < ARRAY_SIZE(ieee802154_coordinator_ops); i++) {
667 		rc = genl_register_ops(&ieee802154_coordinator_family,
668 				&ieee802154_coordinator_ops[i]);
669 		if (rc)
670 			goto fail;
671 	}
672 
673 	return 0;
674 
675 fail:
676 	genl_unregister_family(&ieee802154_coordinator_family);
677 	return rc;
678 }
679 module_init(ieee802154_nl_init);
680 
681 static void __exit ieee802154_nl_exit(void)
682 {
683 	genl_unregister_family(&ieee802154_coordinator_family);
684 }
685 module_exit(ieee802154_nl_exit);
686 
687 MODULE_LICENSE("GPL v2");
688 MODULE_DESCRIPTION("ieee 802.15.4 configuration interface");
689 
690