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