1 /* 2 * Netlink inteface 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 * You should have received a copy of the GNU General Public License along 16 * with this program; if not, write to the Free Software Foundation, Inc., 17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Written by: 20 * Sergey Lapin <slapin@ossfans.org> 21 * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> 22 * Maxim Osipov <maxim.osipov@siemens.com> 23 */ 24 25 #include <linux/gfp.h> 26 #include <linux/kernel.h> 27 #include <linux/if_arp.h> 28 #include <linux/netdevice.h> 29 #include <net/netlink.h> 30 #include <net/genetlink.h> 31 #include <net/sock.h> 32 #include <linux/nl802154.h> 33 #include <linux/export.h> 34 #include <net/af_ieee802154.h> 35 #include <net/nl802154.h> 36 #include <net/ieee802154.h> 37 #include <net/ieee802154_netdev.h> 38 #include <net/wpan-phy.h> 39 40 #include "ieee802154.h" 41 42 int ieee802154_nl_assoc_indic(struct net_device *dev, 43 struct ieee802154_addr *addr, u8 cap) 44 { 45 struct sk_buff *msg; 46 47 pr_debug("%s\n", __func__); 48 49 if (addr->addr_type != IEEE802154_ADDR_LONG) { 50 pr_err("%s: received non-long source address!\n", __func__); 51 return -EINVAL; 52 } 53 54 msg = ieee802154_nl_create(0, IEEE802154_ASSOCIATE_INDIC); 55 if (!msg) 56 return -ENOBUFS; 57 58 if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) || 59 nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) || 60 nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, 61 dev->dev_addr) || 62 nla_put(msg, IEEE802154_ATTR_SRC_HW_ADDR, IEEE802154_ADDR_LEN, 63 addr->hwaddr) || 64 nla_put_u8(msg, IEEE802154_ATTR_CAPABILITY, cap)) 65 goto nla_put_failure; 66 67 return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP); 68 69 nla_put_failure: 70 nlmsg_free(msg); 71 return -ENOBUFS; 72 } 73 EXPORT_SYMBOL(ieee802154_nl_assoc_indic); 74 75 int ieee802154_nl_assoc_confirm(struct net_device *dev, u16 short_addr, 76 u8 status) 77 { 78 struct sk_buff *msg; 79 80 pr_debug("%s\n", __func__); 81 82 msg = ieee802154_nl_create(0, IEEE802154_ASSOCIATE_CONF); 83 if (!msg) 84 return -ENOBUFS; 85 86 if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) || 87 nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) || 88 nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, 89 dev->dev_addr) || 90 nla_put_u16(msg, IEEE802154_ATTR_SHORT_ADDR, short_addr) || 91 nla_put_u8(msg, IEEE802154_ATTR_STATUS, status)) 92 goto nla_put_failure; 93 return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP); 94 95 nla_put_failure: 96 nlmsg_free(msg); 97 return -ENOBUFS; 98 } 99 EXPORT_SYMBOL(ieee802154_nl_assoc_confirm); 100 101 int ieee802154_nl_disassoc_indic(struct net_device *dev, 102 struct ieee802154_addr *addr, u8 reason) 103 { 104 struct sk_buff *msg; 105 106 pr_debug("%s\n", __func__); 107 108 msg = ieee802154_nl_create(0, IEEE802154_DISASSOCIATE_INDIC); 109 if (!msg) 110 return -ENOBUFS; 111 112 if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) || 113 nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) || 114 nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, 115 dev->dev_addr)) 116 goto nla_put_failure; 117 if (addr->addr_type == IEEE802154_ADDR_LONG) { 118 if (nla_put(msg, IEEE802154_ATTR_SRC_HW_ADDR, IEEE802154_ADDR_LEN, 119 addr->hwaddr)) 120 goto nla_put_failure; 121 } else { 122 if (nla_put_u16(msg, IEEE802154_ATTR_SRC_SHORT_ADDR, 123 addr->short_addr)) 124 goto nla_put_failure; 125 } 126 if (nla_put_u8(msg, IEEE802154_ATTR_REASON, reason)) 127 goto nla_put_failure; 128 return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP); 129 130 nla_put_failure: 131 nlmsg_free(msg); 132 return -ENOBUFS; 133 } 134 EXPORT_SYMBOL(ieee802154_nl_disassoc_indic); 135 136 int ieee802154_nl_disassoc_confirm(struct net_device *dev, u8 status) 137 { 138 struct sk_buff *msg; 139 140 pr_debug("%s\n", __func__); 141 142 msg = ieee802154_nl_create(0, IEEE802154_DISASSOCIATE_CONF); 143 if (!msg) 144 return -ENOBUFS; 145 146 if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) || 147 nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) || 148 nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, 149 dev->dev_addr) || 150 nla_put_u8(msg, IEEE802154_ATTR_STATUS, status)) 151 goto nla_put_failure; 152 return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP); 153 154 nla_put_failure: 155 nlmsg_free(msg); 156 return -ENOBUFS; 157 } 158 EXPORT_SYMBOL(ieee802154_nl_disassoc_confirm); 159 160 int ieee802154_nl_beacon_indic(struct net_device *dev, 161 u16 panid, u16 coord_addr) 162 { 163 struct sk_buff *msg; 164 165 pr_debug("%s\n", __func__); 166 167 msg = ieee802154_nl_create(0, IEEE802154_BEACON_NOTIFY_INDIC); 168 if (!msg) 169 return -ENOBUFS; 170 171 if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) || 172 nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) || 173 nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, 174 dev->dev_addr) || 175 nla_put_u16(msg, IEEE802154_ATTR_COORD_SHORT_ADDR, coord_addr) || 176 nla_put_u16(msg, IEEE802154_ATTR_COORD_PAN_ID, panid)) 177 goto nla_put_failure; 178 return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP); 179 180 nla_put_failure: 181 nlmsg_free(msg); 182 return -ENOBUFS; 183 } 184 EXPORT_SYMBOL(ieee802154_nl_beacon_indic); 185 186 int ieee802154_nl_scan_confirm(struct net_device *dev, 187 u8 status, u8 scan_type, u32 unscanned, u8 page, 188 u8 *edl/* , struct list_head *pan_desc_list */) 189 { 190 struct sk_buff *msg; 191 192 pr_debug("%s\n", __func__); 193 194 msg = ieee802154_nl_create(0, IEEE802154_SCAN_CONF); 195 if (!msg) 196 return -ENOBUFS; 197 198 if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) || 199 nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) || 200 nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, 201 dev->dev_addr) || 202 nla_put_u8(msg, IEEE802154_ATTR_STATUS, status) || 203 nla_put_u8(msg, IEEE802154_ATTR_SCAN_TYPE, scan_type) || 204 nla_put_u32(msg, IEEE802154_ATTR_CHANNELS, unscanned) || 205 nla_put_u8(msg, IEEE802154_ATTR_PAGE, page) || 206 (edl && 207 nla_put(msg, IEEE802154_ATTR_ED_LIST, 27, edl))) 208 goto nla_put_failure; 209 return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP); 210 211 nla_put_failure: 212 nlmsg_free(msg); 213 return -ENOBUFS; 214 } 215 EXPORT_SYMBOL(ieee802154_nl_scan_confirm); 216 217 int ieee802154_nl_start_confirm(struct net_device *dev, u8 status) 218 { 219 struct sk_buff *msg; 220 221 pr_debug("%s\n", __func__); 222 223 msg = ieee802154_nl_create(0, IEEE802154_START_CONF); 224 if (!msg) 225 return -ENOBUFS; 226 227 if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) || 228 nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) || 229 nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, 230 dev->dev_addr) || 231 nla_put_u8(msg, IEEE802154_ATTR_STATUS, status)) 232 goto nla_put_failure; 233 return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP); 234 235 nla_put_failure: 236 nlmsg_free(msg); 237 return -ENOBUFS; 238 } 239 EXPORT_SYMBOL(ieee802154_nl_start_confirm); 240 241 static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 portid, 242 u32 seq, int flags, struct net_device *dev) 243 { 244 void *hdr; 245 struct wpan_phy *phy; 246 247 pr_debug("%s\n", __func__); 248 249 hdr = genlmsg_put(msg, 0, seq, &nl802154_family, flags, 250 IEEE802154_LIST_IFACE); 251 if (!hdr) 252 goto out; 253 254 phy = ieee802154_mlme_ops(dev)->get_phy(dev); 255 BUG_ON(!phy); 256 257 if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) || 258 nla_put_string(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy)) || 259 nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) || 260 nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, 261 dev->dev_addr) || 262 nla_put_u16(msg, IEEE802154_ATTR_SHORT_ADDR, 263 ieee802154_mlme_ops(dev)->get_short_addr(dev)) || 264 nla_put_u16(msg, IEEE802154_ATTR_PAN_ID, 265 ieee802154_mlme_ops(dev)->get_pan_id(dev))) 266 goto nla_put_failure; 267 wpan_phy_put(phy); 268 return genlmsg_end(msg, hdr); 269 270 nla_put_failure: 271 wpan_phy_put(phy); 272 genlmsg_cancel(msg, hdr); 273 out: 274 return -EMSGSIZE; 275 } 276 277 /* Requests from userspace */ 278 static struct net_device *ieee802154_nl_get_dev(struct genl_info *info) 279 { 280 struct net_device *dev; 281 282 if (info->attrs[IEEE802154_ATTR_DEV_NAME]) { 283 char name[IFNAMSIZ + 1]; 284 nla_strlcpy(name, info->attrs[IEEE802154_ATTR_DEV_NAME], 285 sizeof(name)); 286 dev = dev_get_by_name(&init_net, name); 287 } else if (info->attrs[IEEE802154_ATTR_DEV_INDEX]) 288 dev = dev_get_by_index(&init_net, 289 nla_get_u32(info->attrs[IEEE802154_ATTR_DEV_INDEX])); 290 else 291 return NULL; 292 293 if (!dev) 294 return NULL; 295 296 if (dev->type != ARPHRD_IEEE802154) { 297 dev_put(dev); 298 return NULL; 299 } 300 301 return dev; 302 } 303 304 int ieee802154_associate_req(struct sk_buff *skb, struct genl_info *info) 305 { 306 struct net_device *dev; 307 struct ieee802154_addr addr; 308 u8 page; 309 int ret = -EOPNOTSUPP; 310 311 if (!info->attrs[IEEE802154_ATTR_CHANNEL] || 312 !info->attrs[IEEE802154_ATTR_COORD_PAN_ID] || 313 (!info->attrs[IEEE802154_ATTR_COORD_HW_ADDR] && 314 !info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]) || 315 !info->attrs[IEEE802154_ATTR_CAPABILITY]) 316 return -EINVAL; 317 318 dev = ieee802154_nl_get_dev(info); 319 if (!dev) 320 return -ENODEV; 321 if (!ieee802154_mlme_ops(dev)->assoc_req) 322 goto out; 323 324 if (info->attrs[IEEE802154_ATTR_COORD_HW_ADDR]) { 325 addr.addr_type = IEEE802154_ADDR_LONG; 326 nla_memcpy(addr.hwaddr, 327 info->attrs[IEEE802154_ATTR_COORD_HW_ADDR], 328 IEEE802154_ADDR_LEN); 329 } else { 330 addr.addr_type = IEEE802154_ADDR_SHORT; 331 addr.short_addr = nla_get_u16( 332 info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]); 333 } 334 addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]); 335 336 if (info->attrs[IEEE802154_ATTR_PAGE]) 337 page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]); 338 else 339 page = 0; 340 341 ret = ieee802154_mlme_ops(dev)->assoc_req(dev, &addr, 342 nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]), 343 page, 344 nla_get_u8(info->attrs[IEEE802154_ATTR_CAPABILITY])); 345 346 out: 347 dev_put(dev); 348 return ret; 349 } 350 351 int ieee802154_associate_resp(struct sk_buff *skb, struct genl_info *info) 352 { 353 struct net_device *dev; 354 struct ieee802154_addr addr; 355 int ret = -EOPNOTSUPP; 356 357 if (!info->attrs[IEEE802154_ATTR_STATUS] || 358 !info->attrs[IEEE802154_ATTR_DEST_HW_ADDR] || 359 !info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]) 360 return -EINVAL; 361 362 dev = ieee802154_nl_get_dev(info); 363 if (!dev) 364 return -ENODEV; 365 if (!ieee802154_mlme_ops(dev)->assoc_resp) 366 goto out; 367 368 addr.addr_type = IEEE802154_ADDR_LONG; 369 nla_memcpy(addr.hwaddr, info->attrs[IEEE802154_ATTR_DEST_HW_ADDR], 370 IEEE802154_ADDR_LEN); 371 addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev); 372 373 374 ret = ieee802154_mlme_ops(dev)->assoc_resp(dev, &addr, 375 nla_get_u16(info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]), 376 nla_get_u8(info->attrs[IEEE802154_ATTR_STATUS])); 377 378 out: 379 dev_put(dev); 380 return ret; 381 } 382 383 int ieee802154_disassociate_req(struct sk_buff *skb, struct genl_info *info) 384 { 385 struct net_device *dev; 386 struct ieee802154_addr addr; 387 int ret = -EOPNOTSUPP; 388 389 if ((!info->attrs[IEEE802154_ATTR_DEST_HW_ADDR] && 390 !info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]) || 391 !info->attrs[IEEE802154_ATTR_REASON]) 392 return -EINVAL; 393 394 dev = ieee802154_nl_get_dev(info); 395 if (!dev) 396 return -ENODEV; 397 if (!ieee802154_mlme_ops(dev)->disassoc_req) 398 goto out; 399 400 if (info->attrs[IEEE802154_ATTR_DEST_HW_ADDR]) { 401 addr.addr_type = IEEE802154_ADDR_LONG; 402 nla_memcpy(addr.hwaddr, 403 info->attrs[IEEE802154_ATTR_DEST_HW_ADDR], 404 IEEE802154_ADDR_LEN); 405 } else { 406 addr.addr_type = IEEE802154_ADDR_SHORT; 407 addr.short_addr = nla_get_u16( 408 info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]); 409 } 410 addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev); 411 412 ret = ieee802154_mlme_ops(dev)->disassoc_req(dev, &addr, 413 nla_get_u8(info->attrs[IEEE802154_ATTR_REASON])); 414 415 out: 416 dev_put(dev); 417 return ret; 418 } 419 420 /* 421 * PANid, channel, beacon_order = 15, superframe_order = 15, 422 * PAN_coordinator, battery_life_extension = 0, 423 * coord_realignment = 0, security_enable = 0 424 */ 425 int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info) 426 { 427 struct net_device *dev; 428 struct ieee802154_addr addr; 429 430 u8 channel, bcn_ord, sf_ord; 431 u8 page; 432 int pan_coord, blx, coord_realign; 433 int ret = -EOPNOTSUPP; 434 435 if (!info->attrs[IEEE802154_ATTR_COORD_PAN_ID] || 436 !info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR] || 437 !info->attrs[IEEE802154_ATTR_CHANNEL] || 438 !info->attrs[IEEE802154_ATTR_BCN_ORD] || 439 !info->attrs[IEEE802154_ATTR_SF_ORD] || 440 !info->attrs[IEEE802154_ATTR_PAN_COORD] || 441 !info->attrs[IEEE802154_ATTR_BAT_EXT] || 442 !info->attrs[IEEE802154_ATTR_COORD_REALIGN] 443 ) 444 return -EINVAL; 445 446 dev = ieee802154_nl_get_dev(info); 447 if (!dev) 448 return -ENODEV; 449 if (!ieee802154_mlme_ops(dev)->start_req) 450 goto out; 451 452 addr.addr_type = IEEE802154_ADDR_SHORT; 453 addr.short_addr = nla_get_u16( 454 info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]); 455 addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]); 456 457 channel = nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]); 458 bcn_ord = nla_get_u8(info->attrs[IEEE802154_ATTR_BCN_ORD]); 459 sf_ord = nla_get_u8(info->attrs[IEEE802154_ATTR_SF_ORD]); 460 pan_coord = nla_get_u8(info->attrs[IEEE802154_ATTR_PAN_COORD]); 461 blx = nla_get_u8(info->attrs[IEEE802154_ATTR_BAT_EXT]); 462 coord_realign = nla_get_u8(info->attrs[IEEE802154_ATTR_COORD_REALIGN]); 463 464 if (info->attrs[IEEE802154_ATTR_PAGE]) 465 page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]); 466 else 467 page = 0; 468 469 470 if (addr.short_addr == IEEE802154_ADDR_BROADCAST) { 471 ieee802154_nl_start_confirm(dev, IEEE802154_NO_SHORT_ADDRESS); 472 dev_put(dev); 473 return -EINVAL; 474 } 475 476 ret = ieee802154_mlme_ops(dev)->start_req(dev, &addr, channel, page, 477 bcn_ord, sf_ord, pan_coord, blx, coord_realign); 478 479 out: 480 dev_put(dev); 481 return ret; 482 } 483 484 int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info) 485 { 486 struct net_device *dev; 487 int ret = -EOPNOTSUPP; 488 u8 type; 489 u32 channels; 490 u8 duration; 491 u8 page; 492 493 if (!info->attrs[IEEE802154_ATTR_SCAN_TYPE] || 494 !info->attrs[IEEE802154_ATTR_CHANNELS] || 495 !info->attrs[IEEE802154_ATTR_DURATION]) 496 return -EINVAL; 497 498 dev = ieee802154_nl_get_dev(info); 499 if (!dev) 500 return -ENODEV; 501 if (!ieee802154_mlme_ops(dev)->scan_req) 502 goto out; 503 504 type = nla_get_u8(info->attrs[IEEE802154_ATTR_SCAN_TYPE]); 505 channels = nla_get_u32(info->attrs[IEEE802154_ATTR_CHANNELS]); 506 duration = nla_get_u8(info->attrs[IEEE802154_ATTR_DURATION]); 507 508 if (info->attrs[IEEE802154_ATTR_PAGE]) 509 page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]); 510 else 511 page = 0; 512 513 514 ret = ieee802154_mlme_ops(dev)->scan_req(dev, type, channels, page, 515 duration); 516 517 out: 518 dev_put(dev); 519 return ret; 520 } 521 522 int ieee802154_list_iface(struct sk_buff *skb, struct genl_info *info) 523 { 524 /* Request for interface name, index, type, IEEE address, 525 PAN Id, short address */ 526 struct sk_buff *msg; 527 struct net_device *dev = NULL; 528 int rc = -ENOBUFS; 529 530 pr_debug("%s\n", __func__); 531 532 dev = ieee802154_nl_get_dev(info); 533 if (!dev) 534 return -ENODEV; 535 536 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 537 if (!msg) 538 goto out_dev; 539 540 rc = ieee802154_nl_fill_iface(msg, info->snd_portid, info->snd_seq, 541 0, dev); 542 if (rc < 0) 543 goto out_free; 544 545 dev_put(dev); 546 547 return genlmsg_reply(msg, info); 548 out_free: 549 nlmsg_free(msg); 550 out_dev: 551 dev_put(dev); 552 return rc; 553 554 } 555 556 int ieee802154_dump_iface(struct sk_buff *skb, struct netlink_callback *cb) 557 { 558 struct net *net = sock_net(skb->sk); 559 struct net_device *dev; 560 int idx; 561 int s_idx = cb->args[0]; 562 563 pr_debug("%s\n", __func__); 564 565 idx = 0; 566 for_each_netdev(net, dev) { 567 if (idx < s_idx || (dev->type != ARPHRD_IEEE802154)) 568 goto cont; 569 570 if (ieee802154_nl_fill_iface(skb, NETLINK_CB(cb->skb).portid, 571 cb->nlh->nlmsg_seq, NLM_F_MULTI, dev) < 0) 572 break; 573 cont: 574 idx++; 575 } 576 cb->args[0] = idx; 577 578 return skb->len; 579 } 580