xref: /openbmc/linux/net/ieee802154/nl-mac.c (revision 1c582d915da13ca21ad375ae04ec1bd6193418b2)
178fe738dSDmitry Eremin-Solenikov /*
278fe738dSDmitry Eremin-Solenikov  * Netlink inteface for IEEE 802.15.4 stack
378fe738dSDmitry Eremin-Solenikov  *
478fe738dSDmitry Eremin-Solenikov  * Copyright 2007, 2008 Siemens AG
578fe738dSDmitry Eremin-Solenikov  *
678fe738dSDmitry Eremin-Solenikov  * This program is free software; you can redistribute it and/or modify
778fe738dSDmitry Eremin-Solenikov  * it under the terms of the GNU General Public License version 2
878fe738dSDmitry Eremin-Solenikov  * as published by the Free Software Foundation.
978fe738dSDmitry Eremin-Solenikov  *
1078fe738dSDmitry Eremin-Solenikov  * This program is distributed in the hope that it will be useful,
1178fe738dSDmitry Eremin-Solenikov  * but WITHOUT ANY WARRANTY; without even the implied warranty of
1278fe738dSDmitry Eremin-Solenikov  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1378fe738dSDmitry Eremin-Solenikov  * GNU General Public License for more details.
1478fe738dSDmitry Eremin-Solenikov  *
1578fe738dSDmitry Eremin-Solenikov  * You should have received a copy of the GNU General Public License along
1678fe738dSDmitry Eremin-Solenikov  * with this program; if not, write to the Free Software Foundation, Inc.,
1778fe738dSDmitry Eremin-Solenikov  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
1878fe738dSDmitry Eremin-Solenikov  *
1978fe738dSDmitry Eremin-Solenikov  * Written by:
2078fe738dSDmitry Eremin-Solenikov  * Sergey Lapin <slapin@ossfans.org>
2178fe738dSDmitry Eremin-Solenikov  * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
2278fe738dSDmitry Eremin-Solenikov  * Maxim Osipov <maxim.osipov@siemens.com>
2378fe738dSDmitry Eremin-Solenikov  */
2478fe738dSDmitry Eremin-Solenikov 
255a0e3ad6STejun Heo #include <linux/gfp.h>
2678fe738dSDmitry Eremin-Solenikov #include <linux/kernel.h>
2778fe738dSDmitry Eremin-Solenikov #include <linux/if_arp.h>
2878fe738dSDmitry Eremin-Solenikov #include <linux/netdevice.h>
2978fe738dSDmitry Eremin-Solenikov #include <net/netlink.h>
3078fe738dSDmitry Eremin-Solenikov #include <net/genetlink.h>
3178fe738dSDmitry Eremin-Solenikov #include <net/sock.h>
3278fe738dSDmitry Eremin-Solenikov #include <linux/nl802154.h>
33bc3b2d7fSPaul Gortmaker #include <linux/export.h>
3478fe738dSDmitry Eremin-Solenikov #include <net/af_ieee802154.h>
3578fe738dSDmitry Eremin-Solenikov #include <net/nl802154.h>
3678fe738dSDmitry Eremin-Solenikov #include <net/ieee802154.h>
3778fe738dSDmitry Eremin-Solenikov #include <net/ieee802154_netdev.h>
380a868b26SDmitry Eremin-Solenikov #include <net/wpan-phy.h>
3978fe738dSDmitry Eremin-Solenikov 
4078fe738dSDmitry Eremin-Solenikov #include "ieee802154.h"
4178fe738dSDmitry Eremin-Solenikov 
42*1c582d91SJohannes Berg struct genl_multicast_group ieee802154_coord_mcgrp = {
4378fe738dSDmitry Eremin-Solenikov 	.name		= IEEE802154_MCAST_COORD_NAME,
4478fe738dSDmitry Eremin-Solenikov };
4578fe738dSDmitry Eremin-Solenikov 
46*1c582d91SJohannes Berg struct genl_multicast_group ieee802154_beacon_mcgrp = {
4778fe738dSDmitry Eremin-Solenikov 	.name		= IEEE802154_MCAST_BEACON_NAME,
4878fe738dSDmitry Eremin-Solenikov };
4978fe738dSDmitry Eremin-Solenikov 
5078fe738dSDmitry Eremin-Solenikov int ieee802154_nl_assoc_indic(struct net_device *dev,
5178fe738dSDmitry Eremin-Solenikov 		struct ieee802154_addr *addr, u8 cap)
5278fe738dSDmitry Eremin-Solenikov {
5378fe738dSDmitry Eremin-Solenikov 	struct sk_buff *msg;
5478fe738dSDmitry Eremin-Solenikov 
5578fe738dSDmitry Eremin-Solenikov 	pr_debug("%s\n", __func__);
5678fe738dSDmitry Eremin-Solenikov 
5778fe738dSDmitry Eremin-Solenikov 	if (addr->addr_type != IEEE802154_ADDR_LONG) {
5878fe738dSDmitry Eremin-Solenikov 		pr_err("%s: received non-long source address!\n", __func__);
5978fe738dSDmitry Eremin-Solenikov 		return -EINVAL;
6078fe738dSDmitry Eremin-Solenikov 	}
6178fe738dSDmitry Eremin-Solenikov 
6278fe738dSDmitry Eremin-Solenikov 	msg = ieee802154_nl_create(0, IEEE802154_ASSOCIATE_INDIC);
6378fe738dSDmitry Eremin-Solenikov 	if (!msg)
6478fe738dSDmitry Eremin-Solenikov 		return -ENOBUFS;
6578fe738dSDmitry Eremin-Solenikov 
66be51da0fSDavid S. Miller 	if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
67be51da0fSDavid S. Miller 	    nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
68be51da0fSDavid S. Miller 	    nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
69be51da0fSDavid S. Miller 		    dev->dev_addr) ||
70be51da0fSDavid S. Miller 	    nla_put(msg, IEEE802154_ATTR_SRC_HW_ADDR, IEEE802154_ADDR_LEN,
71be51da0fSDavid S. Miller 		    addr->hwaddr) ||
72be51da0fSDavid S. Miller 	    nla_put_u8(msg, IEEE802154_ATTR_CAPABILITY, cap))
73be51da0fSDavid S. Miller 		goto nla_put_failure;
7478fe738dSDmitry Eremin-Solenikov 
7578fe738dSDmitry Eremin-Solenikov 	return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
7678fe738dSDmitry Eremin-Solenikov 
7778fe738dSDmitry Eremin-Solenikov nla_put_failure:
7878fe738dSDmitry Eremin-Solenikov 	nlmsg_free(msg);
7978fe738dSDmitry Eremin-Solenikov 	return -ENOBUFS;
8078fe738dSDmitry Eremin-Solenikov }
8178fe738dSDmitry Eremin-Solenikov EXPORT_SYMBOL(ieee802154_nl_assoc_indic);
8278fe738dSDmitry Eremin-Solenikov 
8378fe738dSDmitry Eremin-Solenikov int ieee802154_nl_assoc_confirm(struct net_device *dev, u16 short_addr,
8478fe738dSDmitry Eremin-Solenikov 		u8 status)
8578fe738dSDmitry Eremin-Solenikov {
8678fe738dSDmitry Eremin-Solenikov 	struct sk_buff *msg;
8778fe738dSDmitry Eremin-Solenikov 
8878fe738dSDmitry Eremin-Solenikov 	pr_debug("%s\n", __func__);
8978fe738dSDmitry Eremin-Solenikov 
9078fe738dSDmitry Eremin-Solenikov 	msg = ieee802154_nl_create(0, IEEE802154_ASSOCIATE_CONF);
9178fe738dSDmitry Eremin-Solenikov 	if (!msg)
9278fe738dSDmitry Eremin-Solenikov 		return -ENOBUFS;
9378fe738dSDmitry Eremin-Solenikov 
94be51da0fSDavid S. Miller 	if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
95be51da0fSDavid S. Miller 	    nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
96be51da0fSDavid S. Miller 	    nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
97be51da0fSDavid S. Miller 		    dev->dev_addr) ||
98be51da0fSDavid S. Miller 	    nla_put_u16(msg, IEEE802154_ATTR_SHORT_ADDR, short_addr) ||
99be51da0fSDavid S. Miller 	    nla_put_u8(msg, IEEE802154_ATTR_STATUS, status))
100be51da0fSDavid S. Miller 		goto nla_put_failure;
10178fe738dSDmitry Eremin-Solenikov 	return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
10278fe738dSDmitry Eremin-Solenikov 
10378fe738dSDmitry Eremin-Solenikov nla_put_failure:
10478fe738dSDmitry Eremin-Solenikov 	nlmsg_free(msg);
10578fe738dSDmitry Eremin-Solenikov 	return -ENOBUFS;
10678fe738dSDmitry Eremin-Solenikov }
10778fe738dSDmitry Eremin-Solenikov EXPORT_SYMBOL(ieee802154_nl_assoc_confirm);
10878fe738dSDmitry Eremin-Solenikov 
10978fe738dSDmitry Eremin-Solenikov int ieee802154_nl_disassoc_indic(struct net_device *dev,
11078fe738dSDmitry Eremin-Solenikov 		struct ieee802154_addr *addr, u8 reason)
11178fe738dSDmitry Eremin-Solenikov {
11278fe738dSDmitry Eremin-Solenikov 	struct sk_buff *msg;
11378fe738dSDmitry Eremin-Solenikov 
11478fe738dSDmitry Eremin-Solenikov 	pr_debug("%s\n", __func__);
11578fe738dSDmitry Eremin-Solenikov 
11678fe738dSDmitry Eremin-Solenikov 	msg = ieee802154_nl_create(0, IEEE802154_DISASSOCIATE_INDIC);
11778fe738dSDmitry Eremin-Solenikov 	if (!msg)
11878fe738dSDmitry Eremin-Solenikov 		return -ENOBUFS;
11978fe738dSDmitry Eremin-Solenikov 
120be51da0fSDavid S. Miller 	if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
121be51da0fSDavid S. Miller 	    nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
122be51da0fSDavid S. Miller 	    nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
123be51da0fSDavid S. Miller 		    dev->dev_addr))
124be51da0fSDavid S. Miller 		goto nla_put_failure;
125be51da0fSDavid S. Miller 	if (addr->addr_type == IEEE802154_ADDR_LONG) {
126be51da0fSDavid S. Miller 		if (nla_put(msg, IEEE802154_ATTR_SRC_HW_ADDR, IEEE802154_ADDR_LEN,
127be51da0fSDavid S. Miller 			    addr->hwaddr))
128be51da0fSDavid S. Miller 			goto nla_put_failure;
129be51da0fSDavid S. Miller 	} else {
130be51da0fSDavid S. Miller 		if (nla_put_u16(msg, IEEE802154_ATTR_SRC_SHORT_ADDR,
131be51da0fSDavid S. Miller 				addr->short_addr))
132be51da0fSDavid S. Miller 			goto nla_put_failure;
133be51da0fSDavid S. Miller 	}
134be51da0fSDavid S. Miller 	if (nla_put_u8(msg, IEEE802154_ATTR_REASON, reason))
135be51da0fSDavid S. Miller 		goto nla_put_failure;
13678fe738dSDmitry Eremin-Solenikov 	return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
13778fe738dSDmitry Eremin-Solenikov 
13878fe738dSDmitry Eremin-Solenikov nla_put_failure:
13978fe738dSDmitry Eremin-Solenikov 	nlmsg_free(msg);
14078fe738dSDmitry Eremin-Solenikov 	return -ENOBUFS;
14178fe738dSDmitry Eremin-Solenikov }
14278fe738dSDmitry Eremin-Solenikov EXPORT_SYMBOL(ieee802154_nl_disassoc_indic);
14378fe738dSDmitry Eremin-Solenikov 
14478fe738dSDmitry Eremin-Solenikov int ieee802154_nl_disassoc_confirm(struct net_device *dev, u8 status)
14578fe738dSDmitry Eremin-Solenikov {
14678fe738dSDmitry Eremin-Solenikov 	struct sk_buff *msg;
14778fe738dSDmitry Eremin-Solenikov 
14878fe738dSDmitry Eremin-Solenikov 	pr_debug("%s\n", __func__);
14978fe738dSDmitry Eremin-Solenikov 
15078fe738dSDmitry Eremin-Solenikov 	msg = ieee802154_nl_create(0, IEEE802154_DISASSOCIATE_CONF);
15178fe738dSDmitry Eremin-Solenikov 	if (!msg)
15278fe738dSDmitry Eremin-Solenikov 		return -ENOBUFS;
15378fe738dSDmitry Eremin-Solenikov 
154be51da0fSDavid S. Miller 	if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
155be51da0fSDavid S. Miller 	    nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
156be51da0fSDavid S. Miller 	    nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
157be51da0fSDavid S. Miller 		    dev->dev_addr) ||
158be51da0fSDavid S. Miller 	    nla_put_u8(msg, IEEE802154_ATTR_STATUS, status))
159be51da0fSDavid S. Miller 		goto nla_put_failure;
16078fe738dSDmitry Eremin-Solenikov 	return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
16178fe738dSDmitry Eremin-Solenikov 
16278fe738dSDmitry Eremin-Solenikov nla_put_failure:
16378fe738dSDmitry Eremin-Solenikov 	nlmsg_free(msg);
16478fe738dSDmitry Eremin-Solenikov 	return -ENOBUFS;
16578fe738dSDmitry Eremin-Solenikov }
16678fe738dSDmitry Eremin-Solenikov EXPORT_SYMBOL(ieee802154_nl_disassoc_confirm);
16778fe738dSDmitry Eremin-Solenikov 
16878fe738dSDmitry Eremin-Solenikov int ieee802154_nl_beacon_indic(struct net_device *dev,
16978fe738dSDmitry Eremin-Solenikov 		u16 panid, u16 coord_addr)
17078fe738dSDmitry Eremin-Solenikov {
17178fe738dSDmitry Eremin-Solenikov 	struct sk_buff *msg;
17278fe738dSDmitry Eremin-Solenikov 
17378fe738dSDmitry Eremin-Solenikov 	pr_debug("%s\n", __func__);
17478fe738dSDmitry Eremin-Solenikov 
17578fe738dSDmitry Eremin-Solenikov 	msg = ieee802154_nl_create(0, IEEE802154_BEACON_NOTIFY_INDIC);
17678fe738dSDmitry Eremin-Solenikov 	if (!msg)
17778fe738dSDmitry Eremin-Solenikov 		return -ENOBUFS;
17878fe738dSDmitry Eremin-Solenikov 
179be51da0fSDavid S. Miller 	if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
180be51da0fSDavid S. Miller 	    nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
181be51da0fSDavid S. Miller 	    nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
182be51da0fSDavid S. Miller 		    dev->dev_addr) ||
183be51da0fSDavid S. Miller 	    nla_put_u16(msg, IEEE802154_ATTR_COORD_SHORT_ADDR, coord_addr) ||
184be51da0fSDavid S. Miller 	    nla_put_u16(msg, IEEE802154_ATTR_COORD_PAN_ID, panid))
185be51da0fSDavid S. Miller 		goto nla_put_failure;
18678fe738dSDmitry Eremin-Solenikov 	return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
18778fe738dSDmitry Eremin-Solenikov 
18878fe738dSDmitry Eremin-Solenikov nla_put_failure:
18978fe738dSDmitry Eremin-Solenikov 	nlmsg_free(msg);
19078fe738dSDmitry Eremin-Solenikov 	return -ENOBUFS;
19178fe738dSDmitry Eremin-Solenikov }
19278fe738dSDmitry Eremin-Solenikov EXPORT_SYMBOL(ieee802154_nl_beacon_indic);
19378fe738dSDmitry Eremin-Solenikov 
19478fe738dSDmitry Eremin-Solenikov int ieee802154_nl_scan_confirm(struct net_device *dev,
19578fe738dSDmitry Eremin-Solenikov 		u8 status, u8 scan_type, u32 unscanned, u8 page,
19678fe738dSDmitry Eremin-Solenikov 		u8 *edl/* , struct list_head *pan_desc_list */)
19778fe738dSDmitry Eremin-Solenikov {
19878fe738dSDmitry Eremin-Solenikov 	struct sk_buff *msg;
19978fe738dSDmitry Eremin-Solenikov 
20078fe738dSDmitry Eremin-Solenikov 	pr_debug("%s\n", __func__);
20178fe738dSDmitry Eremin-Solenikov 
20278fe738dSDmitry Eremin-Solenikov 	msg = ieee802154_nl_create(0, IEEE802154_SCAN_CONF);
20378fe738dSDmitry Eremin-Solenikov 	if (!msg)
20478fe738dSDmitry Eremin-Solenikov 		return -ENOBUFS;
20578fe738dSDmitry Eremin-Solenikov 
206be51da0fSDavid S. Miller 	if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
207be51da0fSDavid S. Miller 	    nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
208be51da0fSDavid S. Miller 	    nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
209be51da0fSDavid S. Miller 		    dev->dev_addr) ||
210be51da0fSDavid S. Miller 	    nla_put_u8(msg, IEEE802154_ATTR_STATUS, status) ||
211be51da0fSDavid S. Miller 	    nla_put_u8(msg, IEEE802154_ATTR_SCAN_TYPE, scan_type) ||
212be51da0fSDavid S. Miller 	    nla_put_u32(msg, IEEE802154_ATTR_CHANNELS, unscanned) ||
213be51da0fSDavid S. Miller 	    nla_put_u8(msg, IEEE802154_ATTR_PAGE, page) ||
214be51da0fSDavid S. Miller 	    (edl &&
215be51da0fSDavid S. Miller 	     nla_put(msg, IEEE802154_ATTR_ED_LIST, 27, edl)))
216be51da0fSDavid S. Miller 		goto nla_put_failure;
21778fe738dSDmitry Eremin-Solenikov 	return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
21878fe738dSDmitry Eremin-Solenikov 
21978fe738dSDmitry Eremin-Solenikov nla_put_failure:
22078fe738dSDmitry Eremin-Solenikov 	nlmsg_free(msg);
22178fe738dSDmitry Eremin-Solenikov 	return -ENOBUFS;
22278fe738dSDmitry Eremin-Solenikov }
22378fe738dSDmitry Eremin-Solenikov EXPORT_SYMBOL(ieee802154_nl_scan_confirm);
22478fe738dSDmitry Eremin-Solenikov 
22578fe738dSDmitry Eremin-Solenikov int ieee802154_nl_start_confirm(struct net_device *dev, u8 status)
22678fe738dSDmitry Eremin-Solenikov {
22778fe738dSDmitry Eremin-Solenikov 	struct sk_buff *msg;
22878fe738dSDmitry Eremin-Solenikov 
22978fe738dSDmitry Eremin-Solenikov 	pr_debug("%s\n", __func__);
23078fe738dSDmitry Eremin-Solenikov 
23178fe738dSDmitry Eremin-Solenikov 	msg = ieee802154_nl_create(0, IEEE802154_START_CONF);
23278fe738dSDmitry Eremin-Solenikov 	if (!msg)
23378fe738dSDmitry Eremin-Solenikov 		return -ENOBUFS;
23478fe738dSDmitry Eremin-Solenikov 
235be51da0fSDavid S. Miller 	if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
236be51da0fSDavid S. Miller 	    nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
237be51da0fSDavid S. Miller 	    nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
238be51da0fSDavid S. Miller 		    dev->dev_addr) ||
239be51da0fSDavid S. Miller 	    nla_put_u8(msg, IEEE802154_ATTR_STATUS, status))
240be51da0fSDavid S. Miller 		goto nla_put_failure;
24178fe738dSDmitry Eremin-Solenikov 	return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
24278fe738dSDmitry Eremin-Solenikov 
24378fe738dSDmitry Eremin-Solenikov nla_put_failure:
24478fe738dSDmitry Eremin-Solenikov 	nlmsg_free(msg);
24578fe738dSDmitry Eremin-Solenikov 	return -ENOBUFS;
24678fe738dSDmitry Eremin-Solenikov }
24778fe738dSDmitry Eremin-Solenikov EXPORT_SYMBOL(ieee802154_nl_start_confirm);
24878fe738dSDmitry Eremin-Solenikov 
24915e47304SEric W. Biederman static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 portid,
25078fe738dSDmitry Eremin-Solenikov 	u32 seq, int flags, struct net_device *dev)
25178fe738dSDmitry Eremin-Solenikov {
25278fe738dSDmitry Eremin-Solenikov 	void *hdr;
2530a868b26SDmitry Eremin-Solenikov 	struct wpan_phy *phy;
25478fe738dSDmitry Eremin-Solenikov 
25578fe738dSDmitry Eremin-Solenikov 	pr_debug("%s\n", __func__);
25678fe738dSDmitry Eremin-Solenikov 
25778fe738dSDmitry Eremin-Solenikov 	hdr = genlmsg_put(msg, 0, seq, &nl802154_family, flags,
25878fe738dSDmitry Eremin-Solenikov 		IEEE802154_LIST_IFACE);
25978fe738dSDmitry Eremin-Solenikov 	if (!hdr)
26078fe738dSDmitry Eremin-Solenikov 		goto out;
26178fe738dSDmitry Eremin-Solenikov 
2620a868b26SDmitry Eremin-Solenikov 	phy = ieee802154_mlme_ops(dev)->get_phy(dev);
2630a868b26SDmitry Eremin-Solenikov 	BUG_ON(!phy);
2640a868b26SDmitry Eremin-Solenikov 
265be51da0fSDavid S. Miller 	if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
266be51da0fSDavid S. Miller 	    nla_put_string(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy)) ||
267be51da0fSDavid S. Miller 	    nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
268be51da0fSDavid S. Miller 	    nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
269be51da0fSDavid S. Miller 		    dev->dev_addr) ||
270be51da0fSDavid S. Miller 	    nla_put_u16(msg, IEEE802154_ATTR_SHORT_ADDR,
271be51da0fSDavid S. Miller 			ieee802154_mlme_ops(dev)->get_short_addr(dev)) ||
272be51da0fSDavid S. Miller 	    nla_put_u16(msg, IEEE802154_ATTR_PAN_ID,
273be51da0fSDavid S. Miller 			ieee802154_mlme_ops(dev)->get_pan_id(dev)))
274be51da0fSDavid S. Miller 		goto nla_put_failure;
2750a868b26SDmitry Eremin-Solenikov 	wpan_phy_put(phy);
27678fe738dSDmitry Eremin-Solenikov 	return genlmsg_end(msg, hdr);
27778fe738dSDmitry Eremin-Solenikov 
27878fe738dSDmitry Eremin-Solenikov nla_put_failure:
2790a868b26SDmitry Eremin-Solenikov 	wpan_phy_put(phy);
28078fe738dSDmitry Eremin-Solenikov 	genlmsg_cancel(msg, hdr);
28178fe738dSDmitry Eremin-Solenikov out:
28278fe738dSDmitry Eremin-Solenikov 	return -EMSGSIZE;
28378fe738dSDmitry Eremin-Solenikov }
28478fe738dSDmitry Eremin-Solenikov 
28578fe738dSDmitry Eremin-Solenikov /* Requests from userspace */
28678fe738dSDmitry Eremin-Solenikov static struct net_device *ieee802154_nl_get_dev(struct genl_info *info)
28778fe738dSDmitry Eremin-Solenikov {
28878fe738dSDmitry Eremin-Solenikov 	struct net_device *dev;
28978fe738dSDmitry Eremin-Solenikov 
29078fe738dSDmitry Eremin-Solenikov 	if (info->attrs[IEEE802154_ATTR_DEV_NAME]) {
29178fe738dSDmitry Eremin-Solenikov 		char name[IFNAMSIZ + 1];
29278fe738dSDmitry Eremin-Solenikov 		nla_strlcpy(name, info->attrs[IEEE802154_ATTR_DEV_NAME],
29378fe738dSDmitry Eremin-Solenikov 				sizeof(name));
29478fe738dSDmitry Eremin-Solenikov 		dev = dev_get_by_name(&init_net, name);
29578fe738dSDmitry Eremin-Solenikov 	} else if (info->attrs[IEEE802154_ATTR_DEV_INDEX])
29678fe738dSDmitry Eremin-Solenikov 		dev = dev_get_by_index(&init_net,
29778fe738dSDmitry Eremin-Solenikov 			nla_get_u32(info->attrs[IEEE802154_ATTR_DEV_INDEX]));
29878fe738dSDmitry Eremin-Solenikov 	else
29978fe738dSDmitry Eremin-Solenikov 		return NULL;
30078fe738dSDmitry Eremin-Solenikov 
30178fe738dSDmitry Eremin-Solenikov 	if (!dev)
30278fe738dSDmitry Eremin-Solenikov 		return NULL;
30378fe738dSDmitry Eremin-Solenikov 
30478fe738dSDmitry Eremin-Solenikov 	if (dev->type != ARPHRD_IEEE802154) {
30578fe738dSDmitry Eremin-Solenikov 		dev_put(dev);
30678fe738dSDmitry Eremin-Solenikov 		return NULL;
30778fe738dSDmitry Eremin-Solenikov 	}
30878fe738dSDmitry Eremin-Solenikov 
30978fe738dSDmitry Eremin-Solenikov 	return dev;
31078fe738dSDmitry Eremin-Solenikov }
31178fe738dSDmitry Eremin-Solenikov 
312*1c582d91SJohannes Berg int ieee802154_associate_req(struct sk_buff *skb, struct genl_info *info)
31378fe738dSDmitry Eremin-Solenikov {
31478fe738dSDmitry Eremin-Solenikov 	struct net_device *dev;
31578fe738dSDmitry Eremin-Solenikov 	struct ieee802154_addr addr;
31678fe738dSDmitry Eremin-Solenikov 	u8 page;
31756aa091dSWerner Almesberger 	int ret = -EOPNOTSUPP;
31878fe738dSDmitry Eremin-Solenikov 
31978fe738dSDmitry Eremin-Solenikov 	if (!info->attrs[IEEE802154_ATTR_CHANNEL] ||
32078fe738dSDmitry Eremin-Solenikov 	    !info->attrs[IEEE802154_ATTR_COORD_PAN_ID] ||
32178fe738dSDmitry Eremin-Solenikov 	    (!info->attrs[IEEE802154_ATTR_COORD_HW_ADDR] &&
32278fe738dSDmitry Eremin-Solenikov 		!info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]) ||
32378fe738dSDmitry Eremin-Solenikov 	    !info->attrs[IEEE802154_ATTR_CAPABILITY])
32478fe738dSDmitry Eremin-Solenikov 		return -EINVAL;
32578fe738dSDmitry Eremin-Solenikov 
32678fe738dSDmitry Eremin-Solenikov 	dev = ieee802154_nl_get_dev(info);
32778fe738dSDmitry Eremin-Solenikov 	if (!dev)
32878fe738dSDmitry Eremin-Solenikov 		return -ENODEV;
32956aa091dSWerner Almesberger 	if (!ieee802154_mlme_ops(dev)->assoc_req)
33056aa091dSWerner Almesberger 		goto out;
33178fe738dSDmitry Eremin-Solenikov 
33278fe738dSDmitry Eremin-Solenikov 	if (info->attrs[IEEE802154_ATTR_COORD_HW_ADDR]) {
33378fe738dSDmitry Eremin-Solenikov 		addr.addr_type = IEEE802154_ADDR_LONG;
33478fe738dSDmitry Eremin-Solenikov 		nla_memcpy(addr.hwaddr,
33578fe738dSDmitry Eremin-Solenikov 				info->attrs[IEEE802154_ATTR_COORD_HW_ADDR],
33678fe738dSDmitry Eremin-Solenikov 				IEEE802154_ADDR_LEN);
33778fe738dSDmitry Eremin-Solenikov 	} else {
33878fe738dSDmitry Eremin-Solenikov 		addr.addr_type = IEEE802154_ADDR_SHORT;
33978fe738dSDmitry Eremin-Solenikov 		addr.short_addr = nla_get_u16(
34078fe738dSDmitry Eremin-Solenikov 				info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]);
34178fe738dSDmitry Eremin-Solenikov 	}
34278fe738dSDmitry Eremin-Solenikov 	addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]);
34378fe738dSDmitry Eremin-Solenikov 
34478fe738dSDmitry Eremin-Solenikov 	if (info->attrs[IEEE802154_ATTR_PAGE])
34578fe738dSDmitry Eremin-Solenikov 		page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]);
34678fe738dSDmitry Eremin-Solenikov 	else
34778fe738dSDmitry Eremin-Solenikov 		page = 0;
34878fe738dSDmitry Eremin-Solenikov 
34978fe738dSDmitry Eremin-Solenikov 	ret = ieee802154_mlme_ops(dev)->assoc_req(dev, &addr,
35078fe738dSDmitry Eremin-Solenikov 			nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]),
35178fe738dSDmitry Eremin-Solenikov 			page,
35278fe738dSDmitry Eremin-Solenikov 			nla_get_u8(info->attrs[IEEE802154_ATTR_CAPABILITY]));
35378fe738dSDmitry Eremin-Solenikov 
35456aa091dSWerner Almesberger out:
35578fe738dSDmitry Eremin-Solenikov 	dev_put(dev);
35678fe738dSDmitry Eremin-Solenikov 	return ret;
35778fe738dSDmitry Eremin-Solenikov }
35878fe738dSDmitry Eremin-Solenikov 
359*1c582d91SJohannes Berg int ieee802154_associate_resp(struct sk_buff *skb, struct genl_info *info)
36078fe738dSDmitry Eremin-Solenikov {
36178fe738dSDmitry Eremin-Solenikov 	struct net_device *dev;
36278fe738dSDmitry Eremin-Solenikov 	struct ieee802154_addr addr;
36356aa091dSWerner Almesberger 	int ret = -EOPNOTSUPP;
36478fe738dSDmitry Eremin-Solenikov 
36578fe738dSDmitry Eremin-Solenikov 	if (!info->attrs[IEEE802154_ATTR_STATUS] ||
36678fe738dSDmitry Eremin-Solenikov 	    !info->attrs[IEEE802154_ATTR_DEST_HW_ADDR] ||
36778fe738dSDmitry Eremin-Solenikov 	    !info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR])
36878fe738dSDmitry Eremin-Solenikov 		return -EINVAL;
36978fe738dSDmitry Eremin-Solenikov 
37078fe738dSDmitry Eremin-Solenikov 	dev = ieee802154_nl_get_dev(info);
37178fe738dSDmitry Eremin-Solenikov 	if (!dev)
37278fe738dSDmitry Eremin-Solenikov 		return -ENODEV;
37356aa091dSWerner Almesberger 	if (!ieee802154_mlme_ops(dev)->assoc_resp)
37456aa091dSWerner Almesberger 		goto out;
37578fe738dSDmitry Eremin-Solenikov 
37678fe738dSDmitry Eremin-Solenikov 	addr.addr_type = IEEE802154_ADDR_LONG;
37778fe738dSDmitry Eremin-Solenikov 	nla_memcpy(addr.hwaddr, info->attrs[IEEE802154_ATTR_DEST_HW_ADDR],
37878fe738dSDmitry Eremin-Solenikov 			IEEE802154_ADDR_LEN);
37978fe738dSDmitry Eremin-Solenikov 	addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
38078fe738dSDmitry Eremin-Solenikov 
38178fe738dSDmitry Eremin-Solenikov 
38278fe738dSDmitry Eremin-Solenikov 	ret = ieee802154_mlme_ops(dev)->assoc_resp(dev, &addr,
38378fe738dSDmitry Eremin-Solenikov 		nla_get_u16(info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]),
38478fe738dSDmitry Eremin-Solenikov 		nla_get_u8(info->attrs[IEEE802154_ATTR_STATUS]));
38578fe738dSDmitry Eremin-Solenikov 
38656aa091dSWerner Almesberger out:
38778fe738dSDmitry Eremin-Solenikov 	dev_put(dev);
38878fe738dSDmitry Eremin-Solenikov 	return ret;
38978fe738dSDmitry Eremin-Solenikov }
39078fe738dSDmitry Eremin-Solenikov 
391*1c582d91SJohannes Berg int ieee802154_disassociate_req(struct sk_buff *skb, struct genl_info *info)
39278fe738dSDmitry Eremin-Solenikov {
39378fe738dSDmitry Eremin-Solenikov 	struct net_device *dev;
39478fe738dSDmitry Eremin-Solenikov 	struct ieee802154_addr addr;
39556aa091dSWerner Almesberger 	int ret = -EOPNOTSUPP;
39678fe738dSDmitry Eremin-Solenikov 
39778fe738dSDmitry Eremin-Solenikov 	if ((!info->attrs[IEEE802154_ATTR_DEST_HW_ADDR] &&
39878fe738dSDmitry Eremin-Solenikov 		!info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]) ||
39978fe738dSDmitry Eremin-Solenikov 	    !info->attrs[IEEE802154_ATTR_REASON])
40078fe738dSDmitry Eremin-Solenikov 		return -EINVAL;
40178fe738dSDmitry Eremin-Solenikov 
40278fe738dSDmitry Eremin-Solenikov 	dev = ieee802154_nl_get_dev(info);
40378fe738dSDmitry Eremin-Solenikov 	if (!dev)
40478fe738dSDmitry Eremin-Solenikov 		return -ENODEV;
40556aa091dSWerner Almesberger 	if (!ieee802154_mlme_ops(dev)->disassoc_req)
40656aa091dSWerner Almesberger 		goto out;
40778fe738dSDmitry Eremin-Solenikov 
40878fe738dSDmitry Eremin-Solenikov 	if (info->attrs[IEEE802154_ATTR_DEST_HW_ADDR]) {
40978fe738dSDmitry Eremin-Solenikov 		addr.addr_type = IEEE802154_ADDR_LONG;
41078fe738dSDmitry Eremin-Solenikov 		nla_memcpy(addr.hwaddr,
41178fe738dSDmitry Eremin-Solenikov 				info->attrs[IEEE802154_ATTR_DEST_HW_ADDR],
41278fe738dSDmitry Eremin-Solenikov 				IEEE802154_ADDR_LEN);
41378fe738dSDmitry Eremin-Solenikov 	} else {
41478fe738dSDmitry Eremin-Solenikov 		addr.addr_type = IEEE802154_ADDR_SHORT;
41578fe738dSDmitry Eremin-Solenikov 		addr.short_addr = nla_get_u16(
41678fe738dSDmitry Eremin-Solenikov 				info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]);
41778fe738dSDmitry Eremin-Solenikov 	}
41878fe738dSDmitry Eremin-Solenikov 	addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
41978fe738dSDmitry Eremin-Solenikov 
42078fe738dSDmitry Eremin-Solenikov 	ret = ieee802154_mlme_ops(dev)->disassoc_req(dev, &addr,
42178fe738dSDmitry Eremin-Solenikov 			nla_get_u8(info->attrs[IEEE802154_ATTR_REASON]));
42278fe738dSDmitry Eremin-Solenikov 
42356aa091dSWerner Almesberger out:
42478fe738dSDmitry Eremin-Solenikov 	dev_put(dev);
42578fe738dSDmitry Eremin-Solenikov 	return ret;
42678fe738dSDmitry Eremin-Solenikov }
42778fe738dSDmitry Eremin-Solenikov 
42878fe738dSDmitry Eremin-Solenikov /*
42978fe738dSDmitry Eremin-Solenikov  * PANid, channel, beacon_order = 15, superframe_order = 15,
43078fe738dSDmitry Eremin-Solenikov  * PAN_coordinator, battery_life_extension = 0,
43178fe738dSDmitry Eremin-Solenikov  * coord_realignment = 0, security_enable = 0
43278fe738dSDmitry Eremin-Solenikov */
433*1c582d91SJohannes Berg int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info)
43478fe738dSDmitry Eremin-Solenikov {
43578fe738dSDmitry Eremin-Solenikov 	struct net_device *dev;
43678fe738dSDmitry Eremin-Solenikov 	struct ieee802154_addr addr;
43778fe738dSDmitry Eremin-Solenikov 
43878fe738dSDmitry Eremin-Solenikov 	u8 channel, bcn_ord, sf_ord;
43978fe738dSDmitry Eremin-Solenikov 	u8 page;
44078fe738dSDmitry Eremin-Solenikov 	int pan_coord, blx, coord_realign;
44156aa091dSWerner Almesberger 	int ret = -EOPNOTSUPP;
44278fe738dSDmitry Eremin-Solenikov 
44378fe738dSDmitry Eremin-Solenikov 	if (!info->attrs[IEEE802154_ATTR_COORD_PAN_ID] ||
44478fe738dSDmitry Eremin-Solenikov 	    !info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR] ||
44578fe738dSDmitry Eremin-Solenikov 	    !info->attrs[IEEE802154_ATTR_CHANNEL] ||
44678fe738dSDmitry Eremin-Solenikov 	    !info->attrs[IEEE802154_ATTR_BCN_ORD] ||
44778fe738dSDmitry Eremin-Solenikov 	    !info->attrs[IEEE802154_ATTR_SF_ORD] ||
44878fe738dSDmitry Eremin-Solenikov 	    !info->attrs[IEEE802154_ATTR_PAN_COORD] ||
44978fe738dSDmitry Eremin-Solenikov 	    !info->attrs[IEEE802154_ATTR_BAT_EXT] ||
45078fe738dSDmitry Eremin-Solenikov 	    !info->attrs[IEEE802154_ATTR_COORD_REALIGN]
45178fe738dSDmitry Eremin-Solenikov 	 )
45278fe738dSDmitry Eremin-Solenikov 		return -EINVAL;
45378fe738dSDmitry Eremin-Solenikov 
45478fe738dSDmitry Eremin-Solenikov 	dev = ieee802154_nl_get_dev(info);
45578fe738dSDmitry Eremin-Solenikov 	if (!dev)
45678fe738dSDmitry Eremin-Solenikov 		return -ENODEV;
45756aa091dSWerner Almesberger 	if (!ieee802154_mlme_ops(dev)->start_req)
45856aa091dSWerner Almesberger 		goto out;
45978fe738dSDmitry Eremin-Solenikov 
46078fe738dSDmitry Eremin-Solenikov 	addr.addr_type = IEEE802154_ADDR_SHORT;
46178fe738dSDmitry Eremin-Solenikov 	addr.short_addr = nla_get_u16(
46278fe738dSDmitry Eremin-Solenikov 			info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]);
46378fe738dSDmitry Eremin-Solenikov 	addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]);
46478fe738dSDmitry Eremin-Solenikov 
46578fe738dSDmitry Eremin-Solenikov 	channel = nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]);
46678fe738dSDmitry Eremin-Solenikov 	bcn_ord = nla_get_u8(info->attrs[IEEE802154_ATTR_BCN_ORD]);
46778fe738dSDmitry Eremin-Solenikov 	sf_ord = nla_get_u8(info->attrs[IEEE802154_ATTR_SF_ORD]);
46878fe738dSDmitry Eremin-Solenikov 	pan_coord = nla_get_u8(info->attrs[IEEE802154_ATTR_PAN_COORD]);
46978fe738dSDmitry Eremin-Solenikov 	blx = nla_get_u8(info->attrs[IEEE802154_ATTR_BAT_EXT]);
47078fe738dSDmitry Eremin-Solenikov 	coord_realign = nla_get_u8(info->attrs[IEEE802154_ATTR_COORD_REALIGN]);
47178fe738dSDmitry Eremin-Solenikov 
47278fe738dSDmitry Eremin-Solenikov 	if (info->attrs[IEEE802154_ATTR_PAGE])
47378fe738dSDmitry Eremin-Solenikov 		page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]);
47478fe738dSDmitry Eremin-Solenikov 	else
47578fe738dSDmitry Eremin-Solenikov 		page = 0;
47678fe738dSDmitry Eremin-Solenikov 
47778fe738dSDmitry Eremin-Solenikov 
47878fe738dSDmitry Eremin-Solenikov 	if (addr.short_addr == IEEE802154_ADDR_BROADCAST) {
47978fe738dSDmitry Eremin-Solenikov 		ieee802154_nl_start_confirm(dev, IEEE802154_NO_SHORT_ADDRESS);
48078fe738dSDmitry Eremin-Solenikov 		dev_put(dev);
48178fe738dSDmitry Eremin-Solenikov 		return -EINVAL;
48278fe738dSDmitry Eremin-Solenikov 	}
48378fe738dSDmitry Eremin-Solenikov 
48478fe738dSDmitry Eremin-Solenikov 	ret = ieee802154_mlme_ops(dev)->start_req(dev, &addr, channel, page,
48578fe738dSDmitry Eremin-Solenikov 		bcn_ord, sf_ord, pan_coord, blx, coord_realign);
48678fe738dSDmitry Eremin-Solenikov 
48756aa091dSWerner Almesberger out:
48878fe738dSDmitry Eremin-Solenikov 	dev_put(dev);
48978fe738dSDmitry Eremin-Solenikov 	return ret;
49078fe738dSDmitry Eremin-Solenikov }
49178fe738dSDmitry Eremin-Solenikov 
492*1c582d91SJohannes Berg int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info)
49378fe738dSDmitry Eremin-Solenikov {
49478fe738dSDmitry Eremin-Solenikov 	struct net_device *dev;
49556aa091dSWerner Almesberger 	int ret = -EOPNOTSUPP;
49678fe738dSDmitry Eremin-Solenikov 	u8 type;
49778fe738dSDmitry Eremin-Solenikov 	u32 channels;
49878fe738dSDmitry Eremin-Solenikov 	u8 duration;
49978fe738dSDmitry Eremin-Solenikov 	u8 page;
50078fe738dSDmitry Eremin-Solenikov 
50178fe738dSDmitry Eremin-Solenikov 	if (!info->attrs[IEEE802154_ATTR_SCAN_TYPE] ||
50278fe738dSDmitry Eremin-Solenikov 	    !info->attrs[IEEE802154_ATTR_CHANNELS] ||
50378fe738dSDmitry Eremin-Solenikov 	    !info->attrs[IEEE802154_ATTR_DURATION])
50478fe738dSDmitry Eremin-Solenikov 		return -EINVAL;
50578fe738dSDmitry Eremin-Solenikov 
50678fe738dSDmitry Eremin-Solenikov 	dev = ieee802154_nl_get_dev(info);
50778fe738dSDmitry Eremin-Solenikov 	if (!dev)
50878fe738dSDmitry Eremin-Solenikov 		return -ENODEV;
50956aa091dSWerner Almesberger 	if (!ieee802154_mlme_ops(dev)->scan_req)
51056aa091dSWerner Almesberger 		goto out;
51178fe738dSDmitry Eremin-Solenikov 
51278fe738dSDmitry Eremin-Solenikov 	type = nla_get_u8(info->attrs[IEEE802154_ATTR_SCAN_TYPE]);
51378fe738dSDmitry Eremin-Solenikov 	channels = nla_get_u32(info->attrs[IEEE802154_ATTR_CHANNELS]);
51478fe738dSDmitry Eremin-Solenikov 	duration = nla_get_u8(info->attrs[IEEE802154_ATTR_DURATION]);
51578fe738dSDmitry Eremin-Solenikov 
51678fe738dSDmitry Eremin-Solenikov 	if (info->attrs[IEEE802154_ATTR_PAGE])
51778fe738dSDmitry Eremin-Solenikov 		page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]);
51878fe738dSDmitry Eremin-Solenikov 	else
51978fe738dSDmitry Eremin-Solenikov 		page = 0;
52078fe738dSDmitry Eremin-Solenikov 
52178fe738dSDmitry Eremin-Solenikov 
52278fe738dSDmitry Eremin-Solenikov 	ret = ieee802154_mlme_ops(dev)->scan_req(dev, type, channels, page,
52378fe738dSDmitry Eremin-Solenikov 			duration);
52478fe738dSDmitry Eremin-Solenikov 
52556aa091dSWerner Almesberger out:
52678fe738dSDmitry Eremin-Solenikov 	dev_put(dev);
52778fe738dSDmitry Eremin-Solenikov 	return ret;
52878fe738dSDmitry Eremin-Solenikov }
52978fe738dSDmitry Eremin-Solenikov 
530*1c582d91SJohannes Berg int ieee802154_list_iface(struct sk_buff *skb, struct genl_info *info)
53178fe738dSDmitry Eremin-Solenikov {
53278fe738dSDmitry Eremin-Solenikov 	/* Request for interface name, index, type, IEEE address,
53378fe738dSDmitry Eremin-Solenikov 	   PAN Id, short address */
53478fe738dSDmitry Eremin-Solenikov 	struct sk_buff *msg;
53578fe738dSDmitry Eremin-Solenikov 	struct net_device *dev = NULL;
53678fe738dSDmitry Eremin-Solenikov 	int rc = -ENOBUFS;
53778fe738dSDmitry Eremin-Solenikov 
53878fe738dSDmitry Eremin-Solenikov 	pr_debug("%s\n", __func__);
53978fe738dSDmitry Eremin-Solenikov 
54078fe738dSDmitry Eremin-Solenikov 	dev = ieee802154_nl_get_dev(info);
54178fe738dSDmitry Eremin-Solenikov 	if (!dev)
54278fe738dSDmitry Eremin-Solenikov 		return -ENODEV;
54378fe738dSDmitry Eremin-Solenikov 
54458050fceSThomas Graf 	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
54578fe738dSDmitry Eremin-Solenikov 	if (!msg)
54678fe738dSDmitry Eremin-Solenikov 		goto out_dev;
54778fe738dSDmitry Eremin-Solenikov 
54815e47304SEric W. Biederman 	rc = ieee802154_nl_fill_iface(msg, info->snd_portid, info->snd_seq,
54978fe738dSDmitry Eremin-Solenikov 			0, dev);
55078fe738dSDmitry Eremin-Solenikov 	if (rc < 0)
55178fe738dSDmitry Eremin-Solenikov 		goto out_free;
55278fe738dSDmitry Eremin-Solenikov 
55378fe738dSDmitry Eremin-Solenikov 	dev_put(dev);
55478fe738dSDmitry Eremin-Solenikov 
55578fe738dSDmitry Eremin-Solenikov 	return genlmsg_reply(msg, info);
55678fe738dSDmitry Eremin-Solenikov out_free:
55778fe738dSDmitry Eremin-Solenikov 	nlmsg_free(msg);
55878fe738dSDmitry Eremin-Solenikov out_dev:
55978fe738dSDmitry Eremin-Solenikov 	dev_put(dev);
56078fe738dSDmitry Eremin-Solenikov 	return rc;
56178fe738dSDmitry Eremin-Solenikov 
56278fe738dSDmitry Eremin-Solenikov }
56378fe738dSDmitry Eremin-Solenikov 
564*1c582d91SJohannes Berg int ieee802154_dump_iface(struct sk_buff *skb, struct netlink_callback *cb)
56578fe738dSDmitry Eremin-Solenikov {
56678fe738dSDmitry Eremin-Solenikov 	struct net *net = sock_net(skb->sk);
56778fe738dSDmitry Eremin-Solenikov 	struct net_device *dev;
56878fe738dSDmitry Eremin-Solenikov 	int idx;
56978fe738dSDmitry Eremin-Solenikov 	int s_idx = cb->args[0];
57078fe738dSDmitry Eremin-Solenikov 
57178fe738dSDmitry Eremin-Solenikov 	pr_debug("%s\n", __func__);
57278fe738dSDmitry Eremin-Solenikov 
57378fe738dSDmitry Eremin-Solenikov 	idx = 0;
57478fe738dSDmitry Eremin-Solenikov 	for_each_netdev(net, dev) {
57578fe738dSDmitry Eremin-Solenikov 		if (idx < s_idx || (dev->type != ARPHRD_IEEE802154))
57678fe738dSDmitry Eremin-Solenikov 			goto cont;
57778fe738dSDmitry Eremin-Solenikov 
57815e47304SEric W. Biederman 		if (ieee802154_nl_fill_iface(skb, NETLINK_CB(cb->skb).portid,
57978fe738dSDmitry Eremin-Solenikov 			cb->nlh->nlmsg_seq, NLM_F_MULTI, dev) < 0)
58078fe738dSDmitry Eremin-Solenikov 			break;
58178fe738dSDmitry Eremin-Solenikov cont:
58278fe738dSDmitry Eremin-Solenikov 		idx++;
58378fe738dSDmitry Eremin-Solenikov 	}
58478fe738dSDmitry Eremin-Solenikov 	cb->args[0] = idx;
58578fe738dSDmitry Eremin-Solenikov 
58678fe738dSDmitry Eremin-Solenikov 	return skb->len;
58778fe738dSDmitry Eremin-Solenikov }
588