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 */ 23 24 #include <linux/kernel.h> 25 #include <linux/if_arp.h> 26 #include <linux/netdevice.h> 27 #include <net/netlink.h> 28 #include <net/genetlink.h> 29 #include <linux/nl802154.h> 30 #include <net/ieee802154/af_ieee802154.h> 31 #include <net/ieee802154/nl802154.h> 32 #include <net/ieee802154/netdevice.h> 33 34 static unsigned int ieee802154_seq_num; 35 36 static struct genl_family ieee802154_coordinator_family = { 37 .id = GENL_ID_GENERATE, 38 .hdrsize = 0, 39 .name = IEEE802154_NL_NAME, 40 .version = 1, 41 .maxattr = IEEE802154_ATTR_MAX, 42 }; 43 44 static struct genl_multicast_group ieee802154_coord_mcgrp = { 45 .name = IEEE802154_MCAST_COORD_NAME, 46 }; 47 48 static struct genl_multicast_group ieee802154_beacon_mcgrp = { 49 .name = IEEE802154_MCAST_BEACON_NAME, 50 }; 51 52 /* Requests to userspace */ 53 static struct sk_buff *ieee802154_nl_create(int flags, u8 req) 54 { 55 void *hdr; 56 struct sk_buff *msg = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); 57 58 if (!msg) 59 return NULL; 60 61 hdr = genlmsg_put(msg, 0, ieee802154_seq_num++, 62 &ieee802154_coordinator_family, flags, req); 63 if (!hdr) { 64 nlmsg_free(msg); 65 return NULL; 66 } 67 68 return msg; 69 } 70 71 static int ieee802154_nl_finish(struct sk_buff *msg) 72 { 73 /* XXX: nlh is right at the start of msg */ 74 void *hdr = genlmsg_data(NLMSG_DATA(msg->data)); 75 76 if (!genlmsg_end(msg, hdr)) 77 goto out; 78 79 return genlmsg_multicast(msg, 0, ieee802154_coord_mcgrp.id, 80 GFP_ATOMIC); 81 out: 82 nlmsg_free(msg); 83 return -ENOBUFS; 84 } 85 86 int ieee802154_nl_assoc_indic(struct net_device *dev, 87 struct ieee802154_addr *addr, u8 cap) 88 { 89 struct sk_buff *msg; 90 91 pr_debug("%s\n", __func__); 92 93 if (addr->addr_type != IEEE802154_ADDR_LONG) { 94 pr_err("%s: received non-long source address!\n", __func__); 95 return -EINVAL; 96 } 97 98 msg = ieee802154_nl_create(0, IEEE802154_ASSOCIATE_INDIC); 99 if (!msg) 100 return -ENOBUFS; 101 102 NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); 103 NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); 104 NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, 105 dev->dev_addr); 106 107 NLA_PUT(msg, IEEE802154_ATTR_SRC_HW_ADDR, IEEE802154_ADDR_LEN, 108 addr->hwaddr); 109 110 NLA_PUT_U8(msg, IEEE802154_ATTR_CAPABILITY, cap); 111 112 return ieee802154_nl_finish(msg); 113 114 nla_put_failure: 115 nlmsg_free(msg); 116 return -ENOBUFS; 117 } 118 EXPORT_SYMBOL(ieee802154_nl_assoc_indic); 119 120 int ieee802154_nl_assoc_confirm(struct net_device *dev, u16 short_addr, 121 u8 status) 122 { 123 struct sk_buff *msg; 124 125 pr_debug("%s\n", __func__); 126 127 msg = ieee802154_nl_create(0, IEEE802154_ASSOCIATE_CONF); 128 if (!msg) 129 return -ENOBUFS; 130 131 NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); 132 NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); 133 NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, 134 dev->dev_addr); 135 136 NLA_PUT_U16(msg, IEEE802154_ATTR_SHORT_ADDR, short_addr); 137 NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status); 138 139 return ieee802154_nl_finish(msg); 140 141 nla_put_failure: 142 nlmsg_free(msg); 143 return -ENOBUFS; 144 } 145 EXPORT_SYMBOL(ieee802154_nl_assoc_confirm); 146 147 int ieee802154_nl_disassoc_indic(struct net_device *dev, 148 struct ieee802154_addr *addr, u8 reason) 149 { 150 struct sk_buff *msg; 151 152 pr_debug("%s\n", __func__); 153 154 msg = ieee802154_nl_create(0, IEEE802154_DISASSOCIATE_INDIC); 155 if (!msg) 156 return -ENOBUFS; 157 158 NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); 159 NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); 160 NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, 161 dev->dev_addr); 162 163 if (addr->addr_type == IEEE802154_ADDR_LONG) 164 NLA_PUT(msg, IEEE802154_ATTR_SRC_HW_ADDR, IEEE802154_ADDR_LEN, 165 addr->hwaddr); 166 else 167 NLA_PUT_U16(msg, IEEE802154_ATTR_SRC_SHORT_ADDR, 168 addr->short_addr); 169 170 NLA_PUT_U8(msg, IEEE802154_ATTR_REASON, reason); 171 172 return ieee802154_nl_finish(msg); 173 174 nla_put_failure: 175 nlmsg_free(msg); 176 return -ENOBUFS; 177 } 178 EXPORT_SYMBOL(ieee802154_nl_disassoc_indic); 179 180 int ieee802154_nl_disassoc_confirm(struct net_device *dev, u8 status) 181 { 182 struct sk_buff *msg; 183 184 pr_debug("%s\n", __func__); 185 186 msg = ieee802154_nl_create(0, IEEE802154_DISASSOCIATE_CONF); 187 if (!msg) 188 return -ENOBUFS; 189 190 NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); 191 NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); 192 NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, 193 dev->dev_addr); 194 195 NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status); 196 197 return ieee802154_nl_finish(msg); 198 199 nla_put_failure: 200 nlmsg_free(msg); 201 return -ENOBUFS; 202 } 203 EXPORT_SYMBOL(ieee802154_nl_disassoc_confirm); 204 205 int ieee802154_nl_beacon_indic(struct net_device *dev, 206 u16 panid, u16 coord_addr) 207 { 208 struct sk_buff *msg; 209 210 pr_debug("%s\n", __func__); 211 212 msg = ieee802154_nl_create(0, IEEE802154_BEACON_NOTIFY_INDIC); 213 if (!msg) 214 return -ENOBUFS; 215 216 NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); 217 NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); 218 NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, 219 dev->dev_addr); 220 NLA_PUT_U16(msg, IEEE802154_ATTR_COORD_SHORT_ADDR, coord_addr); 221 NLA_PUT_U16(msg, IEEE802154_ATTR_COORD_PAN_ID, panid); 222 223 return ieee802154_nl_finish(msg); 224 225 nla_put_failure: 226 nlmsg_free(msg); 227 return -ENOBUFS; 228 } 229 EXPORT_SYMBOL(ieee802154_nl_beacon_indic); 230 231 int ieee802154_nl_scan_confirm(struct net_device *dev, 232 u8 status, u8 scan_type, u32 unscanned, 233 u8 *edl/* , struct list_head *pan_desc_list */) 234 { 235 struct sk_buff *msg; 236 237 pr_debug("%s\n", __func__); 238 239 msg = ieee802154_nl_create(0, IEEE802154_SCAN_CONF); 240 if (!msg) 241 return -ENOBUFS; 242 243 NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); 244 NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); 245 NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, 246 dev->dev_addr); 247 248 NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status); 249 NLA_PUT_U8(msg, IEEE802154_ATTR_SCAN_TYPE, scan_type); 250 NLA_PUT_U32(msg, IEEE802154_ATTR_CHANNELS, unscanned); 251 252 if (edl) 253 NLA_PUT(msg, IEEE802154_ATTR_ED_LIST, 27, edl); 254 255 return ieee802154_nl_finish(msg); 256 257 nla_put_failure: 258 nlmsg_free(msg); 259 return -ENOBUFS; 260 } 261 EXPORT_SYMBOL(ieee802154_nl_scan_confirm); 262 263 /* Requests from userspace */ 264 static struct net_device *ieee802154_nl_get_dev(struct genl_info *info) 265 { 266 struct net_device *dev; 267 268 if (info->attrs[IEEE802154_ATTR_DEV_NAME]) { 269 char name[IFNAMSIZ + 1]; 270 nla_strlcpy(name, info->attrs[IEEE802154_ATTR_DEV_NAME], 271 sizeof(name)); 272 dev = dev_get_by_name(&init_net, name); 273 } else if (info->attrs[IEEE802154_ATTR_DEV_INDEX]) 274 dev = dev_get_by_index(&init_net, 275 nla_get_u32(info->attrs[IEEE802154_ATTR_DEV_INDEX])); 276 else 277 return NULL; 278 279 if (dev->type != ARPHRD_IEEE802154) { 280 dev_put(dev); 281 return NULL; 282 } 283 284 return dev; 285 } 286 287 static int ieee802154_associate_req(struct sk_buff *skb, 288 struct genl_info *info) 289 { 290 struct net_device *dev; 291 struct ieee802154_addr addr; 292 int ret = -EINVAL; 293 294 if (!info->attrs[IEEE802154_ATTR_CHANNEL] || 295 !info->attrs[IEEE802154_ATTR_COORD_PAN_ID] || 296 (!info->attrs[IEEE802154_ATTR_COORD_HW_ADDR] && 297 !info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]) || 298 !info->attrs[IEEE802154_ATTR_CAPABILITY]) 299 return -EINVAL; 300 301 dev = ieee802154_nl_get_dev(info); 302 if (!dev) 303 return -ENODEV; 304 305 if (info->attrs[IEEE802154_ATTR_COORD_HW_ADDR]) { 306 addr.addr_type = IEEE802154_ADDR_LONG; 307 nla_memcpy(addr.hwaddr, 308 info->attrs[IEEE802154_ATTR_COORD_HW_ADDR], 309 IEEE802154_ADDR_LEN); 310 } else { 311 addr.addr_type = IEEE802154_ADDR_SHORT; 312 addr.short_addr = nla_get_u16( 313 info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]); 314 } 315 addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]); 316 317 ret = ieee802154_mlme_ops(dev)->assoc_req(dev, &addr, 318 nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]), 319 nla_get_u8(info->attrs[IEEE802154_ATTR_CAPABILITY])); 320 321 dev_put(dev); 322 return ret; 323 } 324 325 static int ieee802154_associate_resp(struct sk_buff *skb, 326 struct genl_info *info) 327 { 328 struct net_device *dev; 329 struct ieee802154_addr addr; 330 int ret = -EINVAL; 331 332 if (!info->attrs[IEEE802154_ATTR_STATUS] || 333 !info->attrs[IEEE802154_ATTR_DEST_HW_ADDR] || 334 !info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]) 335 return -EINVAL; 336 337 dev = ieee802154_nl_get_dev(info); 338 if (!dev) 339 return -ENODEV; 340 341 addr.addr_type = IEEE802154_ADDR_LONG; 342 nla_memcpy(addr.hwaddr, info->attrs[IEEE802154_ATTR_DEST_HW_ADDR], 343 IEEE802154_ADDR_LEN); 344 addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev); 345 346 347 ret = ieee802154_mlme_ops(dev)->assoc_resp(dev, &addr, 348 nla_get_u16(info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]), 349 nla_get_u8(info->attrs[IEEE802154_ATTR_STATUS])); 350 351 dev_put(dev); 352 return ret; 353 } 354 355 static int ieee802154_disassociate_req(struct sk_buff *skb, 356 struct genl_info *info) 357 { 358 struct net_device *dev; 359 struct ieee802154_addr addr; 360 int ret = -EINVAL; 361 362 if ((!info->attrs[IEEE802154_ATTR_DEST_HW_ADDR] && 363 !info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]) || 364 !info->attrs[IEEE802154_ATTR_REASON]) 365 return -EINVAL; 366 367 dev = ieee802154_nl_get_dev(info); 368 if (!dev) 369 return -ENODEV; 370 371 if (info->attrs[IEEE802154_ATTR_DEST_HW_ADDR]) { 372 addr.addr_type = IEEE802154_ADDR_LONG; 373 nla_memcpy(addr.hwaddr, 374 info->attrs[IEEE802154_ATTR_DEST_HW_ADDR], 375 IEEE802154_ADDR_LEN); 376 } else { 377 addr.addr_type = IEEE802154_ADDR_SHORT; 378 addr.short_addr = nla_get_u16( 379 info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]); 380 } 381 addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev); 382 383 ret = ieee802154_mlme_ops(dev)->disassoc_req(dev, &addr, 384 nla_get_u8(info->attrs[IEEE802154_ATTR_REASON])); 385 386 dev_put(dev); 387 return ret; 388 } 389 390 /* 391 * PANid, channel, beacon_order = 15, superframe_order = 15, 392 * PAN_coordinator, battery_life_extension = 0, 393 * coord_realignment = 0, security_enable = 0 394 */ 395 static int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info) 396 { 397 struct net_device *dev; 398 struct ieee802154_addr addr; 399 400 u8 channel, bcn_ord, sf_ord; 401 int pan_coord, blx, coord_realign; 402 int ret; 403 404 if (!info->attrs[IEEE802154_ATTR_COORD_PAN_ID] || 405 !info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR] || 406 !info->attrs[IEEE802154_ATTR_CHANNEL] || 407 !info->attrs[IEEE802154_ATTR_BCN_ORD] || 408 !info->attrs[IEEE802154_ATTR_SF_ORD] || 409 !info->attrs[IEEE802154_ATTR_PAN_COORD] || 410 !info->attrs[IEEE802154_ATTR_BAT_EXT] || 411 !info->attrs[IEEE802154_ATTR_COORD_REALIGN] 412 ) 413 return -EINVAL; 414 415 dev = ieee802154_nl_get_dev(info); 416 if (!dev) 417 return -ENODEV; 418 419 addr.addr_type = IEEE802154_ADDR_SHORT; 420 addr.short_addr = nla_get_u16( 421 info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]); 422 addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]); 423 424 channel = nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]); 425 bcn_ord = nla_get_u8(info->attrs[IEEE802154_ATTR_BCN_ORD]); 426 sf_ord = nla_get_u8(info->attrs[IEEE802154_ATTR_SF_ORD]); 427 pan_coord = nla_get_u8(info->attrs[IEEE802154_ATTR_PAN_COORD]); 428 blx = nla_get_u8(info->attrs[IEEE802154_ATTR_BAT_EXT]); 429 coord_realign = nla_get_u8(info->attrs[IEEE802154_ATTR_COORD_REALIGN]); 430 431 ret = ieee802154_mlme_ops(dev)->start_req(dev, &addr, channel, 432 bcn_ord, sf_ord, pan_coord, blx, coord_realign); 433 434 dev_put(dev); 435 return ret; 436 } 437 438 static int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info) 439 { 440 struct net_device *dev; 441 int ret; 442 u8 type; 443 u32 channels; 444 u8 duration; 445 446 if (!info->attrs[IEEE802154_ATTR_SCAN_TYPE] || 447 !info->attrs[IEEE802154_ATTR_CHANNELS] || 448 !info->attrs[IEEE802154_ATTR_DURATION]) 449 return -EINVAL; 450 451 dev = ieee802154_nl_get_dev(info); 452 if (!dev) 453 return -ENODEV; 454 455 type = nla_get_u8(info->attrs[IEEE802154_ATTR_SCAN_TYPE]); 456 channels = nla_get_u32(info->attrs[IEEE802154_ATTR_CHANNELS]); 457 duration = nla_get_u8(info->attrs[IEEE802154_ATTR_DURATION]); 458 459 ret = ieee802154_mlme_ops(dev)->scan_req(dev, type, channels, 460 duration); 461 462 dev_put(dev); 463 return ret; 464 } 465 466 #define IEEE802154_OP(_cmd, _func) \ 467 { \ 468 .cmd = _cmd, \ 469 .policy = ieee802154_policy, \ 470 .doit = _func, \ 471 .dumpit = NULL, \ 472 .flags = GENL_ADMIN_PERM, \ 473 } 474 475 static struct genl_ops ieee802154_coordinator_ops[] = { 476 IEEE802154_OP(IEEE802154_ASSOCIATE_REQ, ieee802154_associate_req), 477 IEEE802154_OP(IEEE802154_ASSOCIATE_RESP, ieee802154_associate_resp), 478 IEEE802154_OP(IEEE802154_DISASSOCIATE_REQ, ieee802154_disassociate_req), 479 IEEE802154_OP(IEEE802154_SCAN_REQ, ieee802154_scan_req), 480 IEEE802154_OP(IEEE802154_START_REQ, ieee802154_start_req), 481 }; 482 483 static int __init ieee802154_nl_init(void) 484 { 485 int rc; 486 int i; 487 488 rc = genl_register_family(&ieee802154_coordinator_family); 489 if (rc) 490 goto fail; 491 492 rc = genl_register_mc_group(&ieee802154_coordinator_family, 493 &ieee802154_coord_mcgrp); 494 if (rc) 495 goto fail; 496 497 rc = genl_register_mc_group(&ieee802154_coordinator_family, 498 &ieee802154_beacon_mcgrp); 499 if (rc) 500 goto fail; 501 502 503 for (i = 0; i < ARRAY_SIZE(ieee802154_coordinator_ops); i++) { 504 rc = genl_register_ops(&ieee802154_coordinator_family, 505 &ieee802154_coordinator_ops[i]); 506 if (rc) 507 goto fail; 508 } 509 510 return 0; 511 512 fail: 513 genl_unregister_family(&ieee802154_coordinator_family); 514 return rc; 515 } 516 module_init(ieee802154_nl_init); 517 518 static void __exit ieee802154_nl_exit(void) 519 { 520 genl_unregister_family(&ieee802154_coordinator_family); 521 } 522 module_exit(ieee802154_nl_exit); 523 524