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/kernel.h> 26 #include <linux/if_arp.h> 27 #include <linux/netdevice.h> 28 #include <net/netlink.h> 29 #include <net/genetlink.h> 30 #include <net/sock.h> 31 #include <linux/nl802154.h> 32 #include <net/af_ieee802154.h> 33 #include <net/nl802154.h> 34 #include <net/ieee802154.h> 35 #include <net/ieee802154_netdev.h> 36 37 static unsigned int ieee802154_seq_num; 38 39 static struct genl_family ieee802154_coordinator_family = { 40 .id = GENL_ID_GENERATE, 41 .hdrsize = 0, 42 .name = IEEE802154_NL_NAME, 43 .version = 1, 44 .maxattr = IEEE802154_ATTR_MAX, 45 }; 46 47 static struct genl_multicast_group ieee802154_coord_mcgrp = { 48 .name = IEEE802154_MCAST_COORD_NAME, 49 }; 50 51 static struct genl_multicast_group ieee802154_beacon_mcgrp = { 52 .name = IEEE802154_MCAST_BEACON_NAME, 53 }; 54 55 /* Requests to userspace */ 56 static struct sk_buff *ieee802154_nl_create(int flags, u8 req) 57 { 58 void *hdr; 59 struct sk_buff *msg = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); 60 61 if (!msg) 62 return NULL; 63 64 hdr = genlmsg_put(msg, 0, ieee802154_seq_num++, 65 &ieee802154_coordinator_family, flags, req); 66 if (!hdr) { 67 nlmsg_free(msg); 68 return NULL; 69 } 70 71 return msg; 72 } 73 74 static int ieee802154_nl_finish(struct sk_buff *msg) 75 { 76 /* XXX: nlh is right at the start of msg */ 77 void *hdr = genlmsg_data(NLMSG_DATA(msg->data)); 78 79 if (genlmsg_end(msg, hdr) < 0) 80 goto out; 81 82 return genlmsg_multicast(msg, 0, ieee802154_coord_mcgrp.id, 83 GFP_ATOMIC); 84 out: 85 nlmsg_free(msg); 86 return -ENOBUFS; 87 } 88 89 int ieee802154_nl_assoc_indic(struct net_device *dev, 90 struct ieee802154_addr *addr, u8 cap) 91 { 92 struct sk_buff *msg; 93 94 pr_debug("%s\n", __func__); 95 96 if (addr->addr_type != IEEE802154_ADDR_LONG) { 97 pr_err("%s: received non-long source address!\n", __func__); 98 return -EINVAL; 99 } 100 101 msg = ieee802154_nl_create(0, IEEE802154_ASSOCIATE_INDIC); 102 if (!msg) 103 return -ENOBUFS; 104 105 NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); 106 NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); 107 NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, 108 dev->dev_addr); 109 110 NLA_PUT(msg, IEEE802154_ATTR_SRC_HW_ADDR, IEEE802154_ADDR_LEN, 111 addr->hwaddr); 112 113 NLA_PUT_U8(msg, IEEE802154_ATTR_CAPABILITY, cap); 114 115 return ieee802154_nl_finish(msg); 116 117 nla_put_failure: 118 nlmsg_free(msg); 119 return -ENOBUFS; 120 } 121 EXPORT_SYMBOL(ieee802154_nl_assoc_indic); 122 123 int ieee802154_nl_assoc_confirm(struct net_device *dev, u16 short_addr, 124 u8 status) 125 { 126 struct sk_buff *msg; 127 128 pr_debug("%s\n", __func__); 129 130 msg = ieee802154_nl_create(0, IEEE802154_ASSOCIATE_CONF); 131 if (!msg) 132 return -ENOBUFS; 133 134 NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); 135 NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); 136 NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, 137 dev->dev_addr); 138 139 NLA_PUT_U16(msg, IEEE802154_ATTR_SHORT_ADDR, short_addr); 140 NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status); 141 142 return ieee802154_nl_finish(msg); 143 144 nla_put_failure: 145 nlmsg_free(msg); 146 return -ENOBUFS; 147 } 148 EXPORT_SYMBOL(ieee802154_nl_assoc_confirm); 149 150 int ieee802154_nl_disassoc_indic(struct net_device *dev, 151 struct ieee802154_addr *addr, u8 reason) 152 { 153 struct sk_buff *msg; 154 155 pr_debug("%s\n", __func__); 156 157 msg = ieee802154_nl_create(0, IEEE802154_DISASSOCIATE_INDIC); 158 if (!msg) 159 return -ENOBUFS; 160 161 NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); 162 NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); 163 NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, 164 dev->dev_addr); 165 166 if (addr->addr_type == IEEE802154_ADDR_LONG) 167 NLA_PUT(msg, IEEE802154_ATTR_SRC_HW_ADDR, IEEE802154_ADDR_LEN, 168 addr->hwaddr); 169 else 170 NLA_PUT_U16(msg, IEEE802154_ATTR_SRC_SHORT_ADDR, 171 addr->short_addr); 172 173 NLA_PUT_U8(msg, IEEE802154_ATTR_REASON, reason); 174 175 return ieee802154_nl_finish(msg); 176 177 nla_put_failure: 178 nlmsg_free(msg); 179 return -ENOBUFS; 180 } 181 EXPORT_SYMBOL(ieee802154_nl_disassoc_indic); 182 183 int ieee802154_nl_disassoc_confirm(struct net_device *dev, u8 status) 184 { 185 struct sk_buff *msg; 186 187 pr_debug("%s\n", __func__); 188 189 msg = ieee802154_nl_create(0, IEEE802154_DISASSOCIATE_CONF); 190 if (!msg) 191 return -ENOBUFS; 192 193 NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); 194 NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); 195 NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, 196 dev->dev_addr); 197 198 NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status); 199 200 return ieee802154_nl_finish(msg); 201 202 nla_put_failure: 203 nlmsg_free(msg); 204 return -ENOBUFS; 205 } 206 EXPORT_SYMBOL(ieee802154_nl_disassoc_confirm); 207 208 int ieee802154_nl_beacon_indic(struct net_device *dev, 209 u16 panid, u16 coord_addr) 210 { 211 struct sk_buff *msg; 212 213 pr_debug("%s\n", __func__); 214 215 msg = ieee802154_nl_create(0, IEEE802154_BEACON_NOTIFY_INDIC); 216 if (!msg) 217 return -ENOBUFS; 218 219 NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); 220 NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); 221 NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, 222 dev->dev_addr); 223 NLA_PUT_U16(msg, IEEE802154_ATTR_COORD_SHORT_ADDR, coord_addr); 224 NLA_PUT_U16(msg, IEEE802154_ATTR_COORD_PAN_ID, panid); 225 226 return ieee802154_nl_finish(msg); 227 228 nla_put_failure: 229 nlmsg_free(msg); 230 return -ENOBUFS; 231 } 232 EXPORT_SYMBOL(ieee802154_nl_beacon_indic); 233 234 int ieee802154_nl_scan_confirm(struct net_device *dev, 235 u8 status, u8 scan_type, u32 unscanned, 236 u8 *edl/* , struct list_head *pan_desc_list */) 237 { 238 struct sk_buff *msg; 239 240 pr_debug("%s\n", __func__); 241 242 msg = ieee802154_nl_create(0, IEEE802154_SCAN_CONF); 243 if (!msg) 244 return -ENOBUFS; 245 246 NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); 247 NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); 248 NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, 249 dev->dev_addr); 250 251 NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status); 252 NLA_PUT_U8(msg, IEEE802154_ATTR_SCAN_TYPE, scan_type); 253 NLA_PUT_U32(msg, IEEE802154_ATTR_CHANNELS, unscanned); 254 255 if (edl) 256 NLA_PUT(msg, IEEE802154_ATTR_ED_LIST, 27, edl); 257 258 return ieee802154_nl_finish(msg); 259 260 nla_put_failure: 261 nlmsg_free(msg); 262 return -ENOBUFS; 263 } 264 EXPORT_SYMBOL(ieee802154_nl_scan_confirm); 265 266 int ieee802154_nl_start_confirm(struct net_device *dev, u8 status) 267 { 268 struct sk_buff *msg; 269 270 pr_debug("%s\n", __func__); 271 272 msg = ieee802154_nl_create(0, IEEE802154_START_CONF); 273 if (!msg) 274 return -ENOBUFS; 275 276 NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); 277 NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); 278 NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, 279 dev->dev_addr); 280 281 NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status); 282 283 return ieee802154_nl_finish(msg); 284 285 nla_put_failure: 286 nlmsg_free(msg); 287 return -ENOBUFS; 288 } 289 EXPORT_SYMBOL(ieee802154_nl_start_confirm); 290 291 static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 pid, 292 u32 seq, int flags, struct net_device *dev) 293 { 294 void *hdr; 295 296 pr_debug("%s\n", __func__); 297 298 hdr = genlmsg_put(msg, 0, seq, &ieee802154_coordinator_family, flags, 299 IEEE802154_LIST_IFACE); 300 if (!hdr) 301 goto out; 302 303 NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); 304 NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); 305 306 NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, 307 dev->dev_addr); 308 NLA_PUT_U16(msg, IEEE802154_ATTR_SHORT_ADDR, 309 ieee802154_mlme_ops(dev)->get_short_addr(dev)); 310 NLA_PUT_U16(msg, IEEE802154_ATTR_PAN_ID, 311 ieee802154_mlme_ops(dev)->get_pan_id(dev)); 312 return genlmsg_end(msg, hdr); 313 314 nla_put_failure: 315 genlmsg_cancel(msg, hdr); 316 out: 317 return -EMSGSIZE; 318 } 319 320 /* Requests from userspace */ 321 static struct net_device *ieee802154_nl_get_dev(struct genl_info *info) 322 { 323 struct net_device *dev; 324 325 if (info->attrs[IEEE802154_ATTR_DEV_NAME]) { 326 char name[IFNAMSIZ + 1]; 327 nla_strlcpy(name, info->attrs[IEEE802154_ATTR_DEV_NAME], 328 sizeof(name)); 329 dev = dev_get_by_name(&init_net, name); 330 } else if (info->attrs[IEEE802154_ATTR_DEV_INDEX]) 331 dev = dev_get_by_index(&init_net, 332 nla_get_u32(info->attrs[IEEE802154_ATTR_DEV_INDEX])); 333 else 334 return NULL; 335 336 if (!dev) 337 return NULL; 338 339 if (dev->type != ARPHRD_IEEE802154) { 340 dev_put(dev); 341 return NULL; 342 } 343 344 return dev; 345 } 346 347 static int ieee802154_associate_req(struct sk_buff *skb, 348 struct genl_info *info) 349 { 350 struct net_device *dev; 351 struct ieee802154_addr addr; 352 int ret = -EINVAL; 353 354 if (!info->attrs[IEEE802154_ATTR_CHANNEL] || 355 !info->attrs[IEEE802154_ATTR_COORD_PAN_ID] || 356 (!info->attrs[IEEE802154_ATTR_COORD_HW_ADDR] && 357 !info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]) || 358 !info->attrs[IEEE802154_ATTR_CAPABILITY]) 359 return -EINVAL; 360 361 dev = ieee802154_nl_get_dev(info); 362 if (!dev) 363 return -ENODEV; 364 365 if (info->attrs[IEEE802154_ATTR_COORD_HW_ADDR]) { 366 addr.addr_type = IEEE802154_ADDR_LONG; 367 nla_memcpy(addr.hwaddr, 368 info->attrs[IEEE802154_ATTR_COORD_HW_ADDR], 369 IEEE802154_ADDR_LEN); 370 } else { 371 addr.addr_type = IEEE802154_ADDR_SHORT; 372 addr.short_addr = nla_get_u16( 373 info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]); 374 } 375 addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]); 376 377 ret = ieee802154_mlme_ops(dev)->assoc_req(dev, &addr, 378 nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]), 379 nla_get_u8(info->attrs[IEEE802154_ATTR_CAPABILITY])); 380 381 dev_put(dev); 382 return ret; 383 } 384 385 static int ieee802154_associate_resp(struct sk_buff *skb, 386 struct genl_info *info) 387 { 388 struct net_device *dev; 389 struct ieee802154_addr addr; 390 int ret = -EINVAL; 391 392 if (!info->attrs[IEEE802154_ATTR_STATUS] || 393 !info->attrs[IEEE802154_ATTR_DEST_HW_ADDR] || 394 !info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]) 395 return -EINVAL; 396 397 dev = ieee802154_nl_get_dev(info); 398 if (!dev) 399 return -ENODEV; 400 401 addr.addr_type = IEEE802154_ADDR_LONG; 402 nla_memcpy(addr.hwaddr, info->attrs[IEEE802154_ATTR_DEST_HW_ADDR], 403 IEEE802154_ADDR_LEN); 404 addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev); 405 406 407 ret = ieee802154_mlme_ops(dev)->assoc_resp(dev, &addr, 408 nla_get_u16(info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]), 409 nla_get_u8(info->attrs[IEEE802154_ATTR_STATUS])); 410 411 dev_put(dev); 412 return ret; 413 } 414 415 static int ieee802154_disassociate_req(struct sk_buff *skb, 416 struct genl_info *info) 417 { 418 struct net_device *dev; 419 struct ieee802154_addr addr; 420 int ret = -EINVAL; 421 422 if ((!info->attrs[IEEE802154_ATTR_DEST_HW_ADDR] && 423 !info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]) || 424 !info->attrs[IEEE802154_ATTR_REASON]) 425 return -EINVAL; 426 427 dev = ieee802154_nl_get_dev(info); 428 if (!dev) 429 return -ENODEV; 430 431 if (info->attrs[IEEE802154_ATTR_DEST_HW_ADDR]) { 432 addr.addr_type = IEEE802154_ADDR_LONG; 433 nla_memcpy(addr.hwaddr, 434 info->attrs[IEEE802154_ATTR_DEST_HW_ADDR], 435 IEEE802154_ADDR_LEN); 436 } else { 437 addr.addr_type = IEEE802154_ADDR_SHORT; 438 addr.short_addr = nla_get_u16( 439 info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]); 440 } 441 addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev); 442 443 ret = ieee802154_mlme_ops(dev)->disassoc_req(dev, &addr, 444 nla_get_u8(info->attrs[IEEE802154_ATTR_REASON])); 445 446 dev_put(dev); 447 return ret; 448 } 449 450 /* 451 * PANid, channel, beacon_order = 15, superframe_order = 15, 452 * PAN_coordinator, battery_life_extension = 0, 453 * coord_realignment = 0, security_enable = 0 454 */ 455 static int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info) 456 { 457 struct net_device *dev; 458 struct ieee802154_addr addr; 459 460 u8 channel, bcn_ord, sf_ord; 461 int pan_coord, blx, coord_realign; 462 int ret; 463 464 if (!info->attrs[IEEE802154_ATTR_COORD_PAN_ID] || 465 !info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR] || 466 !info->attrs[IEEE802154_ATTR_CHANNEL] || 467 !info->attrs[IEEE802154_ATTR_BCN_ORD] || 468 !info->attrs[IEEE802154_ATTR_SF_ORD] || 469 !info->attrs[IEEE802154_ATTR_PAN_COORD] || 470 !info->attrs[IEEE802154_ATTR_BAT_EXT] || 471 !info->attrs[IEEE802154_ATTR_COORD_REALIGN] 472 ) 473 return -EINVAL; 474 475 dev = ieee802154_nl_get_dev(info); 476 if (!dev) 477 return -ENODEV; 478 479 addr.addr_type = IEEE802154_ADDR_SHORT; 480 addr.short_addr = nla_get_u16( 481 info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]); 482 addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]); 483 484 channel = nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]); 485 bcn_ord = nla_get_u8(info->attrs[IEEE802154_ATTR_BCN_ORD]); 486 sf_ord = nla_get_u8(info->attrs[IEEE802154_ATTR_SF_ORD]); 487 pan_coord = nla_get_u8(info->attrs[IEEE802154_ATTR_PAN_COORD]); 488 blx = nla_get_u8(info->attrs[IEEE802154_ATTR_BAT_EXT]); 489 coord_realign = nla_get_u8(info->attrs[IEEE802154_ATTR_COORD_REALIGN]); 490 491 if (addr.short_addr == IEEE802154_ADDR_BROADCAST) { 492 ieee802154_nl_start_confirm(dev, IEEE802154_NO_SHORT_ADDRESS); 493 dev_put(dev); 494 return -EINVAL; 495 } 496 497 ret = ieee802154_mlme_ops(dev)->start_req(dev, &addr, channel, 498 bcn_ord, sf_ord, pan_coord, blx, coord_realign); 499 500 dev_put(dev); 501 return ret; 502 } 503 504 static int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info) 505 { 506 struct net_device *dev; 507 int ret; 508 u8 type; 509 u32 channels; 510 u8 duration; 511 512 if (!info->attrs[IEEE802154_ATTR_SCAN_TYPE] || 513 !info->attrs[IEEE802154_ATTR_CHANNELS] || 514 !info->attrs[IEEE802154_ATTR_DURATION]) 515 return -EINVAL; 516 517 dev = ieee802154_nl_get_dev(info); 518 if (!dev) 519 return -ENODEV; 520 521 type = nla_get_u8(info->attrs[IEEE802154_ATTR_SCAN_TYPE]); 522 channels = nla_get_u32(info->attrs[IEEE802154_ATTR_CHANNELS]); 523 duration = nla_get_u8(info->attrs[IEEE802154_ATTR_DURATION]); 524 525 ret = ieee802154_mlme_ops(dev)->scan_req(dev, type, channels, 526 duration); 527 528 dev_put(dev); 529 return ret; 530 } 531 532 static int ieee802154_list_iface(struct sk_buff *skb, 533 struct genl_info *info) 534 { 535 /* Request for interface name, index, type, IEEE address, 536 PAN Id, short address */ 537 struct sk_buff *msg; 538 struct net_device *dev = NULL; 539 int rc = -ENOBUFS; 540 541 pr_debug("%s\n", __func__); 542 543 dev = ieee802154_nl_get_dev(info); 544 if (!dev) 545 return -ENODEV; 546 547 msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); 548 if (!msg) 549 goto out_dev; 550 551 rc = ieee802154_nl_fill_iface(msg, info->snd_pid, info->snd_seq, 552 0, dev); 553 if (rc < 0) 554 goto out_free; 555 556 dev_put(dev); 557 558 return genlmsg_unicast(&init_net, msg, info->snd_pid); 559 out_free: 560 nlmsg_free(msg); 561 out_dev: 562 dev_put(dev); 563 return rc; 564 565 } 566 567 static int ieee802154_dump_iface(struct sk_buff *skb, 568 struct netlink_callback *cb) 569 { 570 struct net *net = sock_net(skb->sk); 571 struct net_device *dev; 572 int idx; 573 int s_idx = cb->args[0]; 574 575 pr_debug("%s\n", __func__); 576 577 idx = 0; 578 for_each_netdev(net, dev) { 579 if (idx < s_idx || (dev->type != ARPHRD_IEEE802154)) 580 goto cont; 581 582 if (ieee802154_nl_fill_iface(skb, NETLINK_CB(cb->skb).pid, 583 cb->nlh->nlmsg_seq, NLM_F_MULTI, dev) < 0) 584 break; 585 cont: 586 idx++; 587 } 588 cb->args[0] = idx; 589 590 return skb->len; 591 } 592 593 #define IEEE802154_OP(_cmd, _func) \ 594 { \ 595 .cmd = _cmd, \ 596 .policy = ieee802154_policy, \ 597 .doit = _func, \ 598 .dumpit = NULL, \ 599 .flags = GENL_ADMIN_PERM, \ 600 } 601 602 #define IEEE802154_DUMP(_cmd, _func, _dump) \ 603 { \ 604 .cmd = _cmd, \ 605 .policy = ieee802154_policy, \ 606 .doit = _func, \ 607 .dumpit = _dump, \ 608 } 609 610 static struct genl_ops ieee802154_coordinator_ops[] = { 611 IEEE802154_OP(IEEE802154_ASSOCIATE_REQ, ieee802154_associate_req), 612 IEEE802154_OP(IEEE802154_ASSOCIATE_RESP, ieee802154_associate_resp), 613 IEEE802154_OP(IEEE802154_DISASSOCIATE_REQ, ieee802154_disassociate_req), 614 IEEE802154_OP(IEEE802154_SCAN_REQ, ieee802154_scan_req), 615 IEEE802154_OP(IEEE802154_START_REQ, ieee802154_start_req), 616 IEEE802154_DUMP(IEEE802154_LIST_IFACE, ieee802154_list_iface, 617 ieee802154_dump_iface), 618 }; 619 620 static int __init ieee802154_nl_init(void) 621 { 622 int rc; 623 int i; 624 625 rc = genl_register_family(&ieee802154_coordinator_family); 626 if (rc) 627 goto fail; 628 629 rc = genl_register_mc_group(&ieee802154_coordinator_family, 630 &ieee802154_coord_mcgrp); 631 if (rc) 632 goto fail; 633 634 rc = genl_register_mc_group(&ieee802154_coordinator_family, 635 &ieee802154_beacon_mcgrp); 636 if (rc) 637 goto fail; 638 639 640 for (i = 0; i < ARRAY_SIZE(ieee802154_coordinator_ops); i++) { 641 rc = genl_register_ops(&ieee802154_coordinator_family, 642 &ieee802154_coordinator_ops[i]); 643 if (rc) 644 goto fail; 645 } 646 647 return 0; 648 649 fail: 650 genl_unregister_family(&ieee802154_coordinator_family); 651 return rc; 652 } 653 module_init(ieee802154_nl_init); 654 655 static void __exit ieee802154_nl_exit(void) 656 { 657 genl_unregister_family(&ieee802154_coordinator_family); 658 } 659 module_exit(ieee802154_nl_exit); 660 661 MODULE_LICENSE("GPL v2"); 662 MODULE_DESCRIPTION("ieee 802.15.4 configuration interface"); 663 664