1 /* 2 * Netlink interface 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 * Written by: 16 * Sergey Lapin <slapin@ossfans.org> 17 * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> 18 * Maxim Osipov <maxim.osipov@siemens.com> 19 */ 20 21 #include <linux/kernel.h> 22 #include <linux/slab.h> 23 #include <linux/if_arp.h> 24 #include <net/netlink.h> 25 #include <net/genetlink.h> 26 #include <net/cfg802154.h> 27 #include <net/af_ieee802154.h> 28 #include <net/ieee802154_netdev.h> 29 #include <net/rtnetlink.h> /* for rtnl_{un,}lock */ 30 #include <linux/nl802154.h> 31 32 #include "ieee802154.h" 33 #include "rdev-ops.h" 34 #include "core.h" 35 36 static int ieee802154_nl_fill_phy(struct sk_buff *msg, u32 portid, 37 u32 seq, int flags, struct wpan_phy *phy) 38 { 39 void *hdr; 40 int i, pages = 0; 41 uint32_t *buf = kzalloc(32 * sizeof(uint32_t), GFP_KERNEL); 42 43 pr_debug("%s\n", __func__); 44 45 if (!buf) 46 return -EMSGSIZE; 47 48 hdr = genlmsg_put(msg, 0, seq, &nl802154_family, flags, 49 IEEE802154_LIST_PHY); 50 if (!hdr) 51 goto out; 52 53 mutex_lock(&phy->pib_lock); 54 if (nla_put_string(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy)) || 55 nla_put_u8(msg, IEEE802154_ATTR_PAGE, phy->current_page) || 56 nla_put_u8(msg, IEEE802154_ATTR_CHANNEL, phy->current_channel)) 57 goto nla_put_failure; 58 for (i = 0; i < 32; i++) { 59 if (phy->channels_supported[i]) 60 buf[pages++] = phy->channels_supported[i] | (i << 27); 61 } 62 if (pages && 63 nla_put(msg, IEEE802154_ATTR_CHANNEL_PAGE_LIST, 64 pages * sizeof(uint32_t), buf)) 65 goto nla_put_failure; 66 mutex_unlock(&phy->pib_lock); 67 kfree(buf); 68 genlmsg_end(msg, hdr); 69 return 0; 70 71 nla_put_failure: 72 mutex_unlock(&phy->pib_lock); 73 genlmsg_cancel(msg, hdr); 74 out: 75 kfree(buf); 76 return -EMSGSIZE; 77 } 78 79 int ieee802154_list_phy(struct sk_buff *skb, struct genl_info *info) 80 { 81 /* Request for interface name, index, type, IEEE address, 82 * PAN Id, short address 83 */ 84 struct sk_buff *msg; 85 struct wpan_phy *phy; 86 const char *name; 87 int rc = -ENOBUFS; 88 89 pr_debug("%s\n", __func__); 90 91 if (!info->attrs[IEEE802154_ATTR_PHY_NAME]) 92 return -EINVAL; 93 94 name = nla_data(info->attrs[IEEE802154_ATTR_PHY_NAME]); 95 if (name[nla_len(info->attrs[IEEE802154_ATTR_PHY_NAME]) - 1] != '\0') 96 return -EINVAL; /* phy name should be null-terminated */ 97 98 phy = wpan_phy_find(name); 99 if (!phy) 100 return -ENODEV; 101 102 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 103 if (!msg) 104 goto out_dev; 105 106 rc = ieee802154_nl_fill_phy(msg, info->snd_portid, info->snd_seq, 107 0, phy); 108 if (rc < 0) 109 goto out_free; 110 111 wpan_phy_put(phy); 112 113 return genlmsg_reply(msg, info); 114 out_free: 115 nlmsg_free(msg); 116 out_dev: 117 wpan_phy_put(phy); 118 return rc; 119 } 120 121 struct dump_phy_data { 122 struct sk_buff *skb; 123 struct netlink_callback *cb; 124 int idx, s_idx; 125 }; 126 127 static int ieee802154_dump_phy_iter(struct wpan_phy *phy, void *_data) 128 { 129 int rc; 130 struct dump_phy_data *data = _data; 131 132 pr_debug("%s\n", __func__); 133 134 if (data->idx++ < data->s_idx) 135 return 0; 136 137 rc = ieee802154_nl_fill_phy(data->skb, 138 NETLINK_CB(data->cb->skb).portid, 139 data->cb->nlh->nlmsg_seq, 140 NLM_F_MULTI, 141 phy); 142 143 if (rc < 0) { 144 data->idx--; 145 return rc; 146 } 147 148 return 0; 149 } 150 151 int ieee802154_dump_phy(struct sk_buff *skb, struct netlink_callback *cb) 152 { 153 struct dump_phy_data data = { 154 .cb = cb, 155 .skb = skb, 156 .s_idx = cb->args[0], 157 .idx = 0, 158 }; 159 160 pr_debug("%s\n", __func__); 161 162 wpan_phy_for_each(ieee802154_dump_phy_iter, &data); 163 164 cb->args[0] = data.idx; 165 166 return skb->len; 167 } 168 169 int ieee802154_add_iface(struct sk_buff *skb, struct genl_info *info) 170 { 171 struct sk_buff *msg; 172 struct wpan_phy *phy; 173 const char *name; 174 const char *devname; 175 int rc = -ENOBUFS; 176 struct net_device *dev; 177 int type = __IEEE802154_DEV_INVALID; 178 179 pr_debug("%s\n", __func__); 180 181 if (!info->attrs[IEEE802154_ATTR_PHY_NAME]) 182 return -EINVAL; 183 184 name = nla_data(info->attrs[IEEE802154_ATTR_PHY_NAME]); 185 if (name[nla_len(info->attrs[IEEE802154_ATTR_PHY_NAME]) - 1] != '\0') 186 return -EINVAL; /* phy name should be null-terminated */ 187 188 if (info->attrs[IEEE802154_ATTR_DEV_NAME]) { 189 devname = nla_data(info->attrs[IEEE802154_ATTR_DEV_NAME]); 190 if (devname[nla_len(info->attrs[IEEE802154_ATTR_DEV_NAME]) - 1] 191 != '\0') 192 return -EINVAL; /* phy name should be null-terminated */ 193 } else { 194 devname = "wpan%d"; 195 } 196 197 if (strlen(devname) >= IFNAMSIZ) 198 return -ENAMETOOLONG; 199 200 phy = wpan_phy_find(name); 201 if (!phy) 202 return -ENODEV; 203 204 msg = ieee802154_nl_new_reply(info, 0, IEEE802154_ADD_IFACE); 205 if (!msg) 206 goto out_dev; 207 208 if (info->attrs[IEEE802154_ATTR_HW_ADDR] && 209 nla_len(info->attrs[IEEE802154_ATTR_HW_ADDR]) != 210 IEEE802154_ADDR_LEN) { 211 rc = -EINVAL; 212 goto nla_put_failure; 213 } 214 215 if (info->attrs[IEEE802154_ATTR_DEV_TYPE]) { 216 type = nla_get_u8(info->attrs[IEEE802154_ATTR_DEV_TYPE]); 217 if (type >= __IEEE802154_DEV_MAX) { 218 rc = -EINVAL; 219 goto nla_put_failure; 220 } 221 } 222 223 dev = rdev_add_virtual_intf_deprecated(wpan_phy_to_rdev(phy), devname, 224 type); 225 if (IS_ERR(dev)) { 226 rc = PTR_ERR(dev); 227 goto nla_put_failure; 228 } 229 dev_hold(dev); 230 231 if (info->attrs[IEEE802154_ATTR_HW_ADDR]) { 232 struct sockaddr addr; 233 234 addr.sa_family = ARPHRD_IEEE802154; 235 nla_memcpy(&addr.sa_data, info->attrs[IEEE802154_ATTR_HW_ADDR], 236 IEEE802154_ADDR_LEN); 237 238 /* strangely enough, some callbacks (inetdev_event) from 239 * dev_set_mac_address require RTNL_LOCK 240 */ 241 rtnl_lock(); 242 rc = dev_set_mac_address(dev, &addr); 243 rtnl_unlock(); 244 if (rc) 245 goto dev_unregister; 246 } 247 248 if (nla_put_string(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy)) || 249 nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name)) 250 goto nla_put_failure; 251 dev_put(dev); 252 253 wpan_phy_put(phy); 254 255 return ieee802154_nl_reply(msg, info); 256 257 dev_unregister: 258 rtnl_lock(); /* del_iface must be called with RTNL lock */ 259 rdev_del_virtual_intf_deprecated(wpan_phy_to_rdev(phy), dev); 260 dev_put(dev); 261 rtnl_unlock(); 262 nla_put_failure: 263 nlmsg_free(msg); 264 out_dev: 265 wpan_phy_put(phy); 266 return rc; 267 } 268 269 int ieee802154_del_iface(struct sk_buff *skb, struct genl_info *info) 270 { 271 struct sk_buff *msg; 272 struct wpan_phy *phy; 273 const char *name; 274 int rc; 275 struct net_device *dev; 276 277 pr_debug("%s\n", __func__); 278 279 if (!info->attrs[IEEE802154_ATTR_DEV_NAME]) 280 return -EINVAL; 281 282 name = nla_data(info->attrs[IEEE802154_ATTR_DEV_NAME]); 283 if (name[nla_len(info->attrs[IEEE802154_ATTR_DEV_NAME]) - 1] != '\0') 284 return -EINVAL; /* name should be null-terminated */ 285 286 dev = dev_get_by_name(genl_info_net(info), name); 287 if (!dev) 288 return -ENODEV; 289 290 phy = dev->ieee802154_ptr->wpan_phy; 291 BUG_ON(!phy); 292 get_device(&phy->dev); 293 294 rc = -EINVAL; 295 /* phy name is optional, but should be checked if it's given */ 296 if (info->attrs[IEEE802154_ATTR_PHY_NAME]) { 297 struct wpan_phy *phy2; 298 299 const char *pname = 300 nla_data(info->attrs[IEEE802154_ATTR_PHY_NAME]); 301 if (pname[nla_len(info->attrs[IEEE802154_ATTR_PHY_NAME]) - 1] 302 != '\0') 303 /* name should be null-terminated */ 304 goto out_dev; 305 306 phy2 = wpan_phy_find(pname); 307 if (!phy2) 308 goto out_dev; 309 310 if (phy != phy2) { 311 wpan_phy_put(phy2); 312 goto out_dev; 313 } 314 } 315 316 rc = -ENOBUFS; 317 318 msg = ieee802154_nl_new_reply(info, 0, IEEE802154_DEL_IFACE); 319 if (!msg) 320 goto out_dev; 321 322 rtnl_lock(); 323 rdev_del_virtual_intf_deprecated(wpan_phy_to_rdev(phy), dev); 324 325 /* We don't have device anymore */ 326 dev_put(dev); 327 dev = NULL; 328 329 rtnl_unlock(); 330 331 if (nla_put_string(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy)) || 332 nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, name)) 333 goto nla_put_failure; 334 wpan_phy_put(phy); 335 336 return ieee802154_nl_reply(msg, info); 337 338 nla_put_failure: 339 nlmsg_free(msg); 340 out_dev: 341 wpan_phy_put(phy); 342 if (dev) 343 dev_put(dev); 344 345 return rc; 346 } 347