11eaa9d03SDmitry Eremin-Solenikov /* 21eaa9d03SDmitry Eremin-Solenikov * Netlink inteface for IEEE 802.15.4 stack 31eaa9d03SDmitry Eremin-Solenikov * 41eaa9d03SDmitry Eremin-Solenikov * Copyright 2007, 2008 Siemens AG 51eaa9d03SDmitry Eremin-Solenikov * 61eaa9d03SDmitry Eremin-Solenikov * This program is free software; you can redistribute it and/or modify 71eaa9d03SDmitry Eremin-Solenikov * it under the terms of the GNU General Public License version 2 81eaa9d03SDmitry Eremin-Solenikov * as published by the Free Software Foundation. 91eaa9d03SDmitry Eremin-Solenikov * 101eaa9d03SDmitry Eremin-Solenikov * This program is distributed in the hope that it will be useful, 111eaa9d03SDmitry Eremin-Solenikov * but WITHOUT ANY WARRANTY; without even the implied warranty of 121eaa9d03SDmitry Eremin-Solenikov * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 131eaa9d03SDmitry Eremin-Solenikov * GNU General Public License for more details. 141eaa9d03SDmitry Eremin-Solenikov * 151eaa9d03SDmitry Eremin-Solenikov * You should have received a copy of the GNU General Public License along 161eaa9d03SDmitry Eremin-Solenikov * with this program; if not, write to the Free Software Foundation, Inc., 171eaa9d03SDmitry Eremin-Solenikov * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 181eaa9d03SDmitry Eremin-Solenikov * 191eaa9d03SDmitry Eremin-Solenikov * Written by: 201eaa9d03SDmitry Eremin-Solenikov * Sergey Lapin <slapin@ossfans.org> 211eaa9d03SDmitry Eremin-Solenikov * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> 221eaa9d03SDmitry Eremin-Solenikov * Maxim Osipov <maxim.osipov@siemens.com> 231eaa9d03SDmitry Eremin-Solenikov */ 241eaa9d03SDmitry Eremin-Solenikov 251eaa9d03SDmitry Eremin-Solenikov #include <linux/kernel.h> 261eaa9d03SDmitry Eremin-Solenikov #include <net/netlink.h> 271eaa9d03SDmitry Eremin-Solenikov #include <net/genetlink.h> 281eaa9d03SDmitry Eremin-Solenikov #include <net/wpan-phy.h> 29*bb1cafb8SDmitry Eremin-Solenikov #include <net/af_ieee802154.h> 30*bb1cafb8SDmitry Eremin-Solenikov #include <net/ieee802154_netdev.h> 31*bb1cafb8SDmitry Eremin-Solenikov #include <net/rtnetlink.h> /* for rtnl_{un,}lock */ 321eaa9d03SDmitry Eremin-Solenikov #include <linux/nl802154.h> 331eaa9d03SDmitry Eremin-Solenikov 341eaa9d03SDmitry Eremin-Solenikov #include "ieee802154.h" 351eaa9d03SDmitry Eremin-Solenikov 361eaa9d03SDmitry Eremin-Solenikov static int ieee802154_nl_fill_phy(struct sk_buff *msg, u32 pid, 371eaa9d03SDmitry Eremin-Solenikov u32 seq, int flags, struct wpan_phy *phy) 381eaa9d03SDmitry Eremin-Solenikov { 391eaa9d03SDmitry Eremin-Solenikov void *hdr; 401eaa9d03SDmitry Eremin-Solenikov int i, pages = 0; 411eaa9d03SDmitry Eremin-Solenikov uint32_t *buf = kzalloc(32 * sizeof(uint32_t), GFP_KERNEL); 421eaa9d03SDmitry Eremin-Solenikov 431eaa9d03SDmitry Eremin-Solenikov pr_debug("%s\n", __func__); 441eaa9d03SDmitry Eremin-Solenikov 451eaa9d03SDmitry Eremin-Solenikov if (!buf) 461eaa9d03SDmitry Eremin-Solenikov goto out; 471eaa9d03SDmitry Eremin-Solenikov 481eaa9d03SDmitry Eremin-Solenikov hdr = genlmsg_put(msg, 0, seq, &nl802154_family, flags, 491eaa9d03SDmitry Eremin-Solenikov IEEE802154_LIST_PHY); 501eaa9d03SDmitry Eremin-Solenikov if (!hdr) 511eaa9d03SDmitry Eremin-Solenikov goto out; 521eaa9d03SDmitry Eremin-Solenikov 531eaa9d03SDmitry Eremin-Solenikov mutex_lock(&phy->pib_lock); 541eaa9d03SDmitry Eremin-Solenikov NLA_PUT_STRING(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy)); 551eaa9d03SDmitry Eremin-Solenikov 561eaa9d03SDmitry Eremin-Solenikov NLA_PUT_U8(msg, IEEE802154_ATTR_PAGE, phy->current_page); 571eaa9d03SDmitry Eremin-Solenikov NLA_PUT_U8(msg, IEEE802154_ATTR_CHANNEL, phy->current_channel); 581eaa9d03SDmitry Eremin-Solenikov for (i = 0; i < 32; i++) { 591eaa9d03SDmitry Eremin-Solenikov if (phy->channels_supported[i]) 601eaa9d03SDmitry Eremin-Solenikov buf[pages++] = phy->channels_supported[i] | (i << 27); 611eaa9d03SDmitry Eremin-Solenikov } 621eaa9d03SDmitry Eremin-Solenikov if (pages) 631eaa9d03SDmitry Eremin-Solenikov NLA_PUT(msg, IEEE802154_ATTR_CHANNEL_PAGE_LIST, 641eaa9d03SDmitry Eremin-Solenikov pages * sizeof(uint32_t), buf); 651eaa9d03SDmitry Eremin-Solenikov 661eaa9d03SDmitry Eremin-Solenikov mutex_unlock(&phy->pib_lock); 671eaa9d03SDmitry Eremin-Solenikov return genlmsg_end(msg, hdr); 681eaa9d03SDmitry Eremin-Solenikov 691eaa9d03SDmitry Eremin-Solenikov nla_put_failure: 701eaa9d03SDmitry Eremin-Solenikov mutex_unlock(&phy->pib_lock); 711eaa9d03SDmitry Eremin-Solenikov genlmsg_cancel(msg, hdr); 721eaa9d03SDmitry Eremin-Solenikov out: 731eaa9d03SDmitry Eremin-Solenikov kfree(buf); 741eaa9d03SDmitry Eremin-Solenikov return -EMSGSIZE; 751eaa9d03SDmitry Eremin-Solenikov } 761eaa9d03SDmitry Eremin-Solenikov 771eaa9d03SDmitry Eremin-Solenikov static int ieee802154_list_phy(struct sk_buff *skb, 781eaa9d03SDmitry Eremin-Solenikov struct genl_info *info) 791eaa9d03SDmitry Eremin-Solenikov { 801eaa9d03SDmitry Eremin-Solenikov /* Request for interface name, index, type, IEEE address, 811eaa9d03SDmitry Eremin-Solenikov PAN Id, short address */ 821eaa9d03SDmitry Eremin-Solenikov struct sk_buff *msg; 831eaa9d03SDmitry Eremin-Solenikov struct wpan_phy *phy; 841eaa9d03SDmitry Eremin-Solenikov const char *name; 851eaa9d03SDmitry Eremin-Solenikov int rc = -ENOBUFS; 861eaa9d03SDmitry Eremin-Solenikov 871eaa9d03SDmitry Eremin-Solenikov pr_debug("%s\n", __func__); 881eaa9d03SDmitry Eremin-Solenikov 891eaa9d03SDmitry Eremin-Solenikov if (!info->attrs[IEEE802154_ATTR_PHY_NAME]) 901eaa9d03SDmitry Eremin-Solenikov return -EINVAL; 911eaa9d03SDmitry Eremin-Solenikov 921eaa9d03SDmitry Eremin-Solenikov name = nla_data(info->attrs[IEEE802154_ATTR_PHY_NAME]); 931eaa9d03SDmitry Eremin-Solenikov if (name[nla_len(info->attrs[IEEE802154_ATTR_PHY_NAME]) - 1] != '\0') 941eaa9d03SDmitry Eremin-Solenikov return -EINVAL; /* phy name should be null-terminated */ 951eaa9d03SDmitry Eremin-Solenikov 961eaa9d03SDmitry Eremin-Solenikov 971eaa9d03SDmitry Eremin-Solenikov phy = wpan_phy_find(name); 981eaa9d03SDmitry Eremin-Solenikov if (!phy) 991eaa9d03SDmitry Eremin-Solenikov return -ENODEV; 1001eaa9d03SDmitry Eremin-Solenikov 1011eaa9d03SDmitry Eremin-Solenikov msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); 1021eaa9d03SDmitry Eremin-Solenikov if (!msg) 1031eaa9d03SDmitry Eremin-Solenikov goto out_dev; 1041eaa9d03SDmitry Eremin-Solenikov 1051eaa9d03SDmitry Eremin-Solenikov rc = ieee802154_nl_fill_phy(msg, info->snd_pid, info->snd_seq, 1061eaa9d03SDmitry Eremin-Solenikov 0, phy); 1071eaa9d03SDmitry Eremin-Solenikov if (rc < 0) 1081eaa9d03SDmitry Eremin-Solenikov goto out_free; 1091eaa9d03SDmitry Eremin-Solenikov 1101eaa9d03SDmitry Eremin-Solenikov wpan_phy_put(phy); 1111eaa9d03SDmitry Eremin-Solenikov 1121eaa9d03SDmitry Eremin-Solenikov return genlmsg_reply(msg, info); 1131eaa9d03SDmitry Eremin-Solenikov out_free: 1141eaa9d03SDmitry Eremin-Solenikov nlmsg_free(msg); 1151eaa9d03SDmitry Eremin-Solenikov out_dev: 1161eaa9d03SDmitry Eremin-Solenikov wpan_phy_put(phy); 1171eaa9d03SDmitry Eremin-Solenikov return rc; 1181eaa9d03SDmitry Eremin-Solenikov 1191eaa9d03SDmitry Eremin-Solenikov } 1201eaa9d03SDmitry Eremin-Solenikov 1211eaa9d03SDmitry Eremin-Solenikov struct dump_phy_data { 1221eaa9d03SDmitry Eremin-Solenikov struct sk_buff *skb; 1231eaa9d03SDmitry Eremin-Solenikov struct netlink_callback *cb; 1241eaa9d03SDmitry Eremin-Solenikov int idx, s_idx; 1251eaa9d03SDmitry Eremin-Solenikov }; 1261eaa9d03SDmitry Eremin-Solenikov 1271eaa9d03SDmitry Eremin-Solenikov static int ieee802154_dump_phy_iter(struct wpan_phy *phy, void *_data) 1281eaa9d03SDmitry Eremin-Solenikov { 1291eaa9d03SDmitry Eremin-Solenikov int rc; 1301eaa9d03SDmitry Eremin-Solenikov struct dump_phy_data *data = _data; 1311eaa9d03SDmitry Eremin-Solenikov 1321eaa9d03SDmitry Eremin-Solenikov pr_debug("%s\n", __func__); 1331eaa9d03SDmitry Eremin-Solenikov 1341eaa9d03SDmitry Eremin-Solenikov if (data->idx++ < data->s_idx) 1351eaa9d03SDmitry Eremin-Solenikov return 0; 1361eaa9d03SDmitry Eremin-Solenikov 1371eaa9d03SDmitry Eremin-Solenikov rc = ieee802154_nl_fill_phy(data->skb, 1381eaa9d03SDmitry Eremin-Solenikov NETLINK_CB(data->cb->skb).pid, 1391eaa9d03SDmitry Eremin-Solenikov data->cb->nlh->nlmsg_seq, 1401eaa9d03SDmitry Eremin-Solenikov NLM_F_MULTI, 1411eaa9d03SDmitry Eremin-Solenikov phy); 1421eaa9d03SDmitry Eremin-Solenikov 1431eaa9d03SDmitry Eremin-Solenikov if (rc < 0) { 1441eaa9d03SDmitry Eremin-Solenikov data->idx--; 1451eaa9d03SDmitry Eremin-Solenikov return rc; 1461eaa9d03SDmitry Eremin-Solenikov } 1471eaa9d03SDmitry Eremin-Solenikov 1481eaa9d03SDmitry Eremin-Solenikov return 0; 1491eaa9d03SDmitry Eremin-Solenikov } 1501eaa9d03SDmitry Eremin-Solenikov 1511eaa9d03SDmitry Eremin-Solenikov static int ieee802154_dump_phy(struct sk_buff *skb, 1521eaa9d03SDmitry Eremin-Solenikov struct netlink_callback *cb) 1531eaa9d03SDmitry Eremin-Solenikov { 1541eaa9d03SDmitry Eremin-Solenikov struct dump_phy_data data = { 1551eaa9d03SDmitry Eremin-Solenikov .cb = cb, 1561eaa9d03SDmitry Eremin-Solenikov .skb = skb, 1571eaa9d03SDmitry Eremin-Solenikov .s_idx = cb->args[0], 1581eaa9d03SDmitry Eremin-Solenikov .idx = 0, 1591eaa9d03SDmitry Eremin-Solenikov }; 1601eaa9d03SDmitry Eremin-Solenikov 1611eaa9d03SDmitry Eremin-Solenikov pr_debug("%s\n", __func__); 1621eaa9d03SDmitry Eremin-Solenikov 1631eaa9d03SDmitry Eremin-Solenikov wpan_phy_for_each(ieee802154_dump_phy_iter, &data); 1641eaa9d03SDmitry Eremin-Solenikov 1651eaa9d03SDmitry Eremin-Solenikov cb->args[0] = data.idx; 1661eaa9d03SDmitry Eremin-Solenikov 1671eaa9d03SDmitry Eremin-Solenikov return skb->len; 1681eaa9d03SDmitry Eremin-Solenikov } 1691eaa9d03SDmitry Eremin-Solenikov 170*bb1cafb8SDmitry Eremin-Solenikov static int ieee802154_add_iface(struct sk_buff *skb, 171*bb1cafb8SDmitry Eremin-Solenikov struct genl_info *info) 172*bb1cafb8SDmitry Eremin-Solenikov { 173*bb1cafb8SDmitry Eremin-Solenikov struct sk_buff *msg; 174*bb1cafb8SDmitry Eremin-Solenikov struct wpan_phy *phy; 175*bb1cafb8SDmitry Eremin-Solenikov const char *name; 176*bb1cafb8SDmitry Eremin-Solenikov const char *devname; 177*bb1cafb8SDmitry Eremin-Solenikov int rc = -ENOBUFS; 178*bb1cafb8SDmitry Eremin-Solenikov struct net_device *dev; 179*bb1cafb8SDmitry Eremin-Solenikov 180*bb1cafb8SDmitry Eremin-Solenikov pr_debug("%s\n", __func__); 181*bb1cafb8SDmitry Eremin-Solenikov 182*bb1cafb8SDmitry Eremin-Solenikov if (!info->attrs[IEEE802154_ATTR_PHY_NAME]) 183*bb1cafb8SDmitry Eremin-Solenikov return -EINVAL; 184*bb1cafb8SDmitry Eremin-Solenikov 185*bb1cafb8SDmitry Eremin-Solenikov name = nla_data(info->attrs[IEEE802154_ATTR_PHY_NAME]); 186*bb1cafb8SDmitry Eremin-Solenikov if (name[nla_len(info->attrs[IEEE802154_ATTR_PHY_NAME]) - 1] != '\0') 187*bb1cafb8SDmitry Eremin-Solenikov return -EINVAL; /* phy name should be null-terminated */ 188*bb1cafb8SDmitry Eremin-Solenikov 189*bb1cafb8SDmitry Eremin-Solenikov if (info->attrs[IEEE802154_ATTR_DEV_NAME]) { 190*bb1cafb8SDmitry Eremin-Solenikov devname = nla_data(info->attrs[IEEE802154_ATTR_DEV_NAME]); 191*bb1cafb8SDmitry Eremin-Solenikov if (devname[nla_len(info->attrs[IEEE802154_ATTR_DEV_NAME]) - 1] 192*bb1cafb8SDmitry Eremin-Solenikov != '\0') 193*bb1cafb8SDmitry Eremin-Solenikov return -EINVAL; /* phy name should be null-terminated */ 194*bb1cafb8SDmitry Eremin-Solenikov } else { 195*bb1cafb8SDmitry Eremin-Solenikov devname = "wpan%d"; 196*bb1cafb8SDmitry Eremin-Solenikov } 197*bb1cafb8SDmitry Eremin-Solenikov 198*bb1cafb8SDmitry Eremin-Solenikov if (strlen(devname) >= IFNAMSIZ) 199*bb1cafb8SDmitry Eremin-Solenikov return -ENAMETOOLONG; 200*bb1cafb8SDmitry Eremin-Solenikov 201*bb1cafb8SDmitry Eremin-Solenikov phy = wpan_phy_find(name); 202*bb1cafb8SDmitry Eremin-Solenikov if (!phy) 203*bb1cafb8SDmitry Eremin-Solenikov return -ENODEV; 204*bb1cafb8SDmitry Eremin-Solenikov 205*bb1cafb8SDmitry Eremin-Solenikov msg = ieee802154_nl_new_reply(info, 0, IEEE802154_ADD_IFACE); 206*bb1cafb8SDmitry Eremin-Solenikov if (!msg) 207*bb1cafb8SDmitry Eremin-Solenikov goto out_dev; 208*bb1cafb8SDmitry Eremin-Solenikov 209*bb1cafb8SDmitry Eremin-Solenikov if (!phy->add_iface) { 210*bb1cafb8SDmitry Eremin-Solenikov rc = -EINVAL; 211*bb1cafb8SDmitry Eremin-Solenikov goto nla_put_failure; 212*bb1cafb8SDmitry Eremin-Solenikov } 213*bb1cafb8SDmitry Eremin-Solenikov 214*bb1cafb8SDmitry Eremin-Solenikov dev = phy->add_iface(phy, devname); 215*bb1cafb8SDmitry Eremin-Solenikov if (IS_ERR(dev)) { 216*bb1cafb8SDmitry Eremin-Solenikov rc = PTR_ERR(dev); 217*bb1cafb8SDmitry Eremin-Solenikov goto nla_put_failure; 218*bb1cafb8SDmitry Eremin-Solenikov } 219*bb1cafb8SDmitry Eremin-Solenikov 220*bb1cafb8SDmitry Eremin-Solenikov NLA_PUT_STRING(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy)); 221*bb1cafb8SDmitry Eremin-Solenikov NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); 222*bb1cafb8SDmitry Eremin-Solenikov 223*bb1cafb8SDmitry Eremin-Solenikov dev_put(dev); 224*bb1cafb8SDmitry Eremin-Solenikov 225*bb1cafb8SDmitry Eremin-Solenikov wpan_phy_put(phy); 226*bb1cafb8SDmitry Eremin-Solenikov 227*bb1cafb8SDmitry Eremin-Solenikov return ieee802154_nl_reply(msg, info); 228*bb1cafb8SDmitry Eremin-Solenikov 229*bb1cafb8SDmitry Eremin-Solenikov nla_put_failure: 230*bb1cafb8SDmitry Eremin-Solenikov nlmsg_free(msg); 231*bb1cafb8SDmitry Eremin-Solenikov out_dev: 232*bb1cafb8SDmitry Eremin-Solenikov wpan_phy_put(phy); 233*bb1cafb8SDmitry Eremin-Solenikov return rc; 234*bb1cafb8SDmitry Eremin-Solenikov } 235*bb1cafb8SDmitry Eremin-Solenikov 236*bb1cafb8SDmitry Eremin-Solenikov static int ieee802154_del_iface(struct sk_buff *skb, 237*bb1cafb8SDmitry Eremin-Solenikov struct genl_info *info) 238*bb1cafb8SDmitry Eremin-Solenikov { 239*bb1cafb8SDmitry Eremin-Solenikov struct sk_buff *msg; 240*bb1cafb8SDmitry Eremin-Solenikov struct wpan_phy *phy; 241*bb1cafb8SDmitry Eremin-Solenikov const char *name; 242*bb1cafb8SDmitry Eremin-Solenikov int rc; 243*bb1cafb8SDmitry Eremin-Solenikov struct net_device *dev; 244*bb1cafb8SDmitry Eremin-Solenikov 245*bb1cafb8SDmitry Eremin-Solenikov pr_debug("%s\n", __func__); 246*bb1cafb8SDmitry Eremin-Solenikov 247*bb1cafb8SDmitry Eremin-Solenikov if (!info->attrs[IEEE802154_ATTR_DEV_NAME]) 248*bb1cafb8SDmitry Eremin-Solenikov return -EINVAL; 249*bb1cafb8SDmitry Eremin-Solenikov 250*bb1cafb8SDmitry Eremin-Solenikov name = nla_data(info->attrs[IEEE802154_ATTR_DEV_NAME]); 251*bb1cafb8SDmitry Eremin-Solenikov if (name[nla_len(info->attrs[IEEE802154_ATTR_DEV_NAME]) - 1] != '\0') 252*bb1cafb8SDmitry Eremin-Solenikov return -EINVAL; /* name should be null-terminated */ 253*bb1cafb8SDmitry Eremin-Solenikov 254*bb1cafb8SDmitry Eremin-Solenikov dev = dev_get_by_name(genl_info_net(info), name); 255*bb1cafb8SDmitry Eremin-Solenikov if (!dev) 256*bb1cafb8SDmitry Eremin-Solenikov return -ENODEV; 257*bb1cafb8SDmitry Eremin-Solenikov 258*bb1cafb8SDmitry Eremin-Solenikov phy = ieee802154_mlme_ops(dev)->get_phy(dev); 259*bb1cafb8SDmitry Eremin-Solenikov BUG_ON(!phy); 260*bb1cafb8SDmitry Eremin-Solenikov 261*bb1cafb8SDmitry Eremin-Solenikov rc = -EINVAL; 262*bb1cafb8SDmitry Eremin-Solenikov /* phy name is optional, but should be checked if it's given */ 263*bb1cafb8SDmitry Eremin-Solenikov if (info->attrs[IEEE802154_ATTR_PHY_NAME]) { 264*bb1cafb8SDmitry Eremin-Solenikov struct wpan_phy *phy2; 265*bb1cafb8SDmitry Eremin-Solenikov 266*bb1cafb8SDmitry Eremin-Solenikov const char *pname = 267*bb1cafb8SDmitry Eremin-Solenikov nla_data(info->attrs[IEEE802154_ATTR_PHY_NAME]); 268*bb1cafb8SDmitry Eremin-Solenikov if (pname[nla_len(info->attrs[IEEE802154_ATTR_PHY_NAME]) - 1] 269*bb1cafb8SDmitry Eremin-Solenikov != '\0') 270*bb1cafb8SDmitry Eremin-Solenikov /* name should be null-terminated */ 271*bb1cafb8SDmitry Eremin-Solenikov goto out_dev; 272*bb1cafb8SDmitry Eremin-Solenikov 273*bb1cafb8SDmitry Eremin-Solenikov phy2 = wpan_phy_find(pname); 274*bb1cafb8SDmitry Eremin-Solenikov if (!phy2) 275*bb1cafb8SDmitry Eremin-Solenikov goto out_dev; 276*bb1cafb8SDmitry Eremin-Solenikov 277*bb1cafb8SDmitry Eremin-Solenikov if (phy != phy2) { 278*bb1cafb8SDmitry Eremin-Solenikov wpan_phy_put(phy2); 279*bb1cafb8SDmitry Eremin-Solenikov goto out_dev; 280*bb1cafb8SDmitry Eremin-Solenikov } 281*bb1cafb8SDmitry Eremin-Solenikov } 282*bb1cafb8SDmitry Eremin-Solenikov 283*bb1cafb8SDmitry Eremin-Solenikov rc = -ENOBUFS; 284*bb1cafb8SDmitry Eremin-Solenikov 285*bb1cafb8SDmitry Eremin-Solenikov msg = ieee802154_nl_new_reply(info, 0, IEEE802154_DEL_IFACE); 286*bb1cafb8SDmitry Eremin-Solenikov if (!msg) 287*bb1cafb8SDmitry Eremin-Solenikov goto out_dev; 288*bb1cafb8SDmitry Eremin-Solenikov 289*bb1cafb8SDmitry Eremin-Solenikov if (!phy->del_iface) { 290*bb1cafb8SDmitry Eremin-Solenikov rc = -EINVAL; 291*bb1cafb8SDmitry Eremin-Solenikov goto nla_put_failure; 292*bb1cafb8SDmitry Eremin-Solenikov } 293*bb1cafb8SDmitry Eremin-Solenikov 294*bb1cafb8SDmitry Eremin-Solenikov rtnl_lock(); 295*bb1cafb8SDmitry Eremin-Solenikov phy->del_iface(phy, dev); 296*bb1cafb8SDmitry Eremin-Solenikov 297*bb1cafb8SDmitry Eremin-Solenikov /* We don't have device anymore */ 298*bb1cafb8SDmitry Eremin-Solenikov dev_put(dev); 299*bb1cafb8SDmitry Eremin-Solenikov dev = NULL; 300*bb1cafb8SDmitry Eremin-Solenikov 301*bb1cafb8SDmitry Eremin-Solenikov rtnl_unlock(); 302*bb1cafb8SDmitry Eremin-Solenikov 303*bb1cafb8SDmitry Eremin-Solenikov 304*bb1cafb8SDmitry Eremin-Solenikov NLA_PUT_STRING(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy)); 305*bb1cafb8SDmitry Eremin-Solenikov NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, name); 306*bb1cafb8SDmitry Eremin-Solenikov 307*bb1cafb8SDmitry Eremin-Solenikov wpan_phy_put(phy); 308*bb1cafb8SDmitry Eremin-Solenikov 309*bb1cafb8SDmitry Eremin-Solenikov return ieee802154_nl_reply(msg, info); 310*bb1cafb8SDmitry Eremin-Solenikov 311*bb1cafb8SDmitry Eremin-Solenikov nla_put_failure: 312*bb1cafb8SDmitry Eremin-Solenikov nlmsg_free(msg); 313*bb1cafb8SDmitry Eremin-Solenikov out_dev: 314*bb1cafb8SDmitry Eremin-Solenikov wpan_phy_put(phy); 315*bb1cafb8SDmitry Eremin-Solenikov if (dev) 316*bb1cafb8SDmitry Eremin-Solenikov dev_put(dev); 317*bb1cafb8SDmitry Eremin-Solenikov 318*bb1cafb8SDmitry Eremin-Solenikov return rc; 319*bb1cafb8SDmitry Eremin-Solenikov } 320*bb1cafb8SDmitry Eremin-Solenikov 3211eaa9d03SDmitry Eremin-Solenikov static struct genl_ops ieee802154_phy_ops[] = { 3221eaa9d03SDmitry Eremin-Solenikov IEEE802154_DUMP(IEEE802154_LIST_PHY, ieee802154_list_phy, 3231eaa9d03SDmitry Eremin-Solenikov ieee802154_dump_phy), 324*bb1cafb8SDmitry Eremin-Solenikov IEEE802154_OP(IEEE802154_ADD_IFACE, ieee802154_add_iface), 325*bb1cafb8SDmitry Eremin-Solenikov IEEE802154_OP(IEEE802154_DEL_IFACE, ieee802154_del_iface), 3261eaa9d03SDmitry Eremin-Solenikov }; 3271eaa9d03SDmitry Eremin-Solenikov 3281eaa9d03SDmitry Eremin-Solenikov /* 3291eaa9d03SDmitry Eremin-Solenikov * No need to unregister as family unregistration will do it. 3301eaa9d03SDmitry Eremin-Solenikov */ 3311eaa9d03SDmitry Eremin-Solenikov int nl802154_phy_register(void) 3321eaa9d03SDmitry Eremin-Solenikov { 3331eaa9d03SDmitry Eremin-Solenikov int i; 3341eaa9d03SDmitry Eremin-Solenikov int rc; 3351eaa9d03SDmitry Eremin-Solenikov 3361eaa9d03SDmitry Eremin-Solenikov for (i = 0; i < ARRAY_SIZE(ieee802154_phy_ops); i++) { 3371eaa9d03SDmitry Eremin-Solenikov rc = genl_register_ops(&nl802154_family, 3381eaa9d03SDmitry Eremin-Solenikov &ieee802154_phy_ops[i]); 3391eaa9d03SDmitry Eremin-Solenikov if (rc) 3401eaa9d03SDmitry Eremin-Solenikov return rc; 3411eaa9d03SDmitry Eremin-Solenikov } 3421eaa9d03SDmitry Eremin-Solenikov 3431eaa9d03SDmitry Eremin-Solenikov return 0; 3441eaa9d03SDmitry Eremin-Solenikov } 345