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