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, u8 page, 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 NLA_PUT_U8(msg, IEEE802154_ATTR_PAGE, page); 255 256 if (edl) 257 NLA_PUT(msg, IEEE802154_ATTR_ED_LIST, 27, edl); 258 259 return ieee802154_nl_finish(msg); 260 261 nla_put_failure: 262 nlmsg_free(msg); 263 return -ENOBUFS; 264 } 265 EXPORT_SYMBOL(ieee802154_nl_scan_confirm); 266 267 int ieee802154_nl_start_confirm(struct net_device *dev, u8 status) 268 { 269 struct sk_buff *msg; 270 271 pr_debug("%s\n", __func__); 272 273 msg = ieee802154_nl_create(0, IEEE802154_START_CONF); 274 if (!msg) 275 return -ENOBUFS; 276 277 NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); 278 NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); 279 NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, 280 dev->dev_addr); 281 282 NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status); 283 284 return ieee802154_nl_finish(msg); 285 286 nla_put_failure: 287 nlmsg_free(msg); 288 return -ENOBUFS; 289 } 290 EXPORT_SYMBOL(ieee802154_nl_start_confirm); 291 292 static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 pid, 293 u32 seq, int flags, struct net_device *dev) 294 { 295 void *hdr; 296 297 pr_debug("%s\n", __func__); 298 299 hdr = genlmsg_put(msg, 0, seq, &ieee802154_coordinator_family, flags, 300 IEEE802154_LIST_IFACE); 301 if (!hdr) 302 goto out; 303 304 NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); 305 NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); 306 307 NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, 308 dev->dev_addr); 309 NLA_PUT_U16(msg, IEEE802154_ATTR_SHORT_ADDR, 310 ieee802154_mlme_ops(dev)->get_short_addr(dev)); 311 NLA_PUT_U16(msg, IEEE802154_ATTR_PAN_ID, 312 ieee802154_mlme_ops(dev)->get_pan_id(dev)); 313 return genlmsg_end(msg, hdr); 314 315 nla_put_failure: 316 genlmsg_cancel(msg, hdr); 317 out: 318 return -EMSGSIZE; 319 } 320 321 /* Requests from userspace */ 322 static struct net_device *ieee802154_nl_get_dev(struct genl_info *info) 323 { 324 struct net_device *dev; 325 326 if (info->attrs[IEEE802154_ATTR_DEV_NAME]) { 327 char name[IFNAMSIZ + 1]; 328 nla_strlcpy(name, info->attrs[IEEE802154_ATTR_DEV_NAME], 329 sizeof(name)); 330 dev = dev_get_by_name(&init_net, name); 331 } else if (info->attrs[IEEE802154_ATTR_DEV_INDEX]) 332 dev = dev_get_by_index(&init_net, 333 nla_get_u32(info->attrs[IEEE802154_ATTR_DEV_INDEX])); 334 else 335 return NULL; 336 337 if (!dev) 338 return NULL; 339 340 if (dev->type != ARPHRD_IEEE802154) { 341 dev_put(dev); 342 return NULL; 343 } 344 345 return dev; 346 } 347 348 static int ieee802154_associate_req(struct sk_buff *skb, 349 struct genl_info *info) 350 { 351 struct net_device *dev; 352 struct ieee802154_addr addr; 353 u8 page; 354 int ret = -EINVAL; 355 356 if (!info->attrs[IEEE802154_ATTR_CHANNEL] || 357 !info->attrs[IEEE802154_ATTR_COORD_PAN_ID] || 358 (!info->attrs[IEEE802154_ATTR_COORD_HW_ADDR] && 359 !info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]) || 360 !info->attrs[IEEE802154_ATTR_CAPABILITY]) 361 return -EINVAL; 362 363 dev = ieee802154_nl_get_dev(info); 364 if (!dev) 365 return -ENODEV; 366 367 if (info->attrs[IEEE802154_ATTR_COORD_HW_ADDR]) { 368 addr.addr_type = IEEE802154_ADDR_LONG; 369 nla_memcpy(addr.hwaddr, 370 info->attrs[IEEE802154_ATTR_COORD_HW_ADDR], 371 IEEE802154_ADDR_LEN); 372 } else { 373 addr.addr_type = IEEE802154_ADDR_SHORT; 374 addr.short_addr = nla_get_u16( 375 info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]); 376 } 377 addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]); 378 379 if (info->attrs[IEEE802154_ATTR_PAGE]) 380 page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]); 381 else 382 page = 0; 383 384 ret = ieee802154_mlme_ops(dev)->assoc_req(dev, &addr, 385 nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]), 386 page, 387 nla_get_u8(info->attrs[IEEE802154_ATTR_CAPABILITY])); 388 389 dev_put(dev); 390 return ret; 391 } 392 393 static int ieee802154_associate_resp(struct sk_buff *skb, 394 struct genl_info *info) 395 { 396 struct net_device *dev; 397 struct ieee802154_addr addr; 398 int ret = -EINVAL; 399 400 if (!info->attrs[IEEE802154_ATTR_STATUS] || 401 !info->attrs[IEEE802154_ATTR_DEST_HW_ADDR] || 402 !info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]) 403 return -EINVAL; 404 405 dev = ieee802154_nl_get_dev(info); 406 if (!dev) 407 return -ENODEV; 408 409 addr.addr_type = IEEE802154_ADDR_LONG; 410 nla_memcpy(addr.hwaddr, info->attrs[IEEE802154_ATTR_DEST_HW_ADDR], 411 IEEE802154_ADDR_LEN); 412 addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev); 413 414 415 ret = ieee802154_mlme_ops(dev)->assoc_resp(dev, &addr, 416 nla_get_u16(info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]), 417 nla_get_u8(info->attrs[IEEE802154_ATTR_STATUS])); 418 419 dev_put(dev); 420 return ret; 421 } 422 423 static int ieee802154_disassociate_req(struct sk_buff *skb, 424 struct genl_info *info) 425 { 426 struct net_device *dev; 427 struct ieee802154_addr addr; 428 int ret = -EINVAL; 429 430 if ((!info->attrs[IEEE802154_ATTR_DEST_HW_ADDR] && 431 !info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]) || 432 !info->attrs[IEEE802154_ATTR_REASON]) 433 return -EINVAL; 434 435 dev = ieee802154_nl_get_dev(info); 436 if (!dev) 437 return -ENODEV; 438 439 if (info->attrs[IEEE802154_ATTR_DEST_HW_ADDR]) { 440 addr.addr_type = IEEE802154_ADDR_LONG; 441 nla_memcpy(addr.hwaddr, 442 info->attrs[IEEE802154_ATTR_DEST_HW_ADDR], 443 IEEE802154_ADDR_LEN); 444 } else { 445 addr.addr_type = IEEE802154_ADDR_SHORT; 446 addr.short_addr = nla_get_u16( 447 info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]); 448 } 449 addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev); 450 451 ret = ieee802154_mlme_ops(dev)->disassoc_req(dev, &addr, 452 nla_get_u8(info->attrs[IEEE802154_ATTR_REASON])); 453 454 dev_put(dev); 455 return ret; 456 } 457 458 /* 459 * PANid, channel, beacon_order = 15, superframe_order = 15, 460 * PAN_coordinator, battery_life_extension = 0, 461 * coord_realignment = 0, security_enable = 0 462 */ 463 static int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info) 464 { 465 struct net_device *dev; 466 struct ieee802154_addr addr; 467 468 u8 channel, bcn_ord, sf_ord; 469 u8 page; 470 int pan_coord, blx, coord_realign; 471 int ret; 472 473 if (!info->attrs[IEEE802154_ATTR_COORD_PAN_ID] || 474 !info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR] || 475 !info->attrs[IEEE802154_ATTR_CHANNEL] || 476 !info->attrs[IEEE802154_ATTR_BCN_ORD] || 477 !info->attrs[IEEE802154_ATTR_SF_ORD] || 478 !info->attrs[IEEE802154_ATTR_PAN_COORD] || 479 !info->attrs[IEEE802154_ATTR_BAT_EXT] || 480 !info->attrs[IEEE802154_ATTR_COORD_REALIGN] 481 ) 482 return -EINVAL; 483 484 dev = ieee802154_nl_get_dev(info); 485 if (!dev) 486 return -ENODEV; 487 488 addr.addr_type = IEEE802154_ADDR_SHORT; 489 addr.short_addr = nla_get_u16( 490 info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]); 491 addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]); 492 493 channel = nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]); 494 bcn_ord = nla_get_u8(info->attrs[IEEE802154_ATTR_BCN_ORD]); 495 sf_ord = nla_get_u8(info->attrs[IEEE802154_ATTR_SF_ORD]); 496 pan_coord = nla_get_u8(info->attrs[IEEE802154_ATTR_PAN_COORD]); 497 blx = nla_get_u8(info->attrs[IEEE802154_ATTR_BAT_EXT]); 498 coord_realign = nla_get_u8(info->attrs[IEEE802154_ATTR_COORD_REALIGN]); 499 500 if (info->attrs[IEEE802154_ATTR_PAGE]) 501 page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]); 502 else 503 page = 0; 504 505 506 if (addr.short_addr == IEEE802154_ADDR_BROADCAST) { 507 ieee802154_nl_start_confirm(dev, IEEE802154_NO_SHORT_ADDRESS); 508 dev_put(dev); 509 return -EINVAL; 510 } 511 512 ret = ieee802154_mlme_ops(dev)->start_req(dev, &addr, channel, page, 513 bcn_ord, sf_ord, pan_coord, blx, coord_realign); 514 515 dev_put(dev); 516 return ret; 517 } 518 519 static int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info) 520 { 521 struct net_device *dev; 522 int ret; 523 u8 type; 524 u32 channels; 525 u8 duration; 526 u8 page; 527 528 if (!info->attrs[IEEE802154_ATTR_SCAN_TYPE] || 529 !info->attrs[IEEE802154_ATTR_CHANNELS] || 530 !info->attrs[IEEE802154_ATTR_DURATION]) 531 return -EINVAL; 532 533 dev = ieee802154_nl_get_dev(info); 534 if (!dev) 535 return -ENODEV; 536 537 type = nla_get_u8(info->attrs[IEEE802154_ATTR_SCAN_TYPE]); 538 channels = nla_get_u32(info->attrs[IEEE802154_ATTR_CHANNELS]); 539 duration = nla_get_u8(info->attrs[IEEE802154_ATTR_DURATION]); 540 541 if (info->attrs[IEEE802154_ATTR_PAGE]) 542 page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]); 543 else 544 page = 0; 545 546 547 ret = ieee802154_mlme_ops(dev)->scan_req(dev, type, channels, page, 548 duration); 549 550 dev_put(dev); 551 return ret; 552 } 553 554 static int ieee802154_list_iface(struct sk_buff *skb, 555 struct genl_info *info) 556 { 557 /* Request for interface name, index, type, IEEE address, 558 PAN Id, short address */ 559 struct sk_buff *msg; 560 struct net_device *dev = NULL; 561 int rc = -ENOBUFS; 562 563 pr_debug("%s\n", __func__); 564 565 dev = ieee802154_nl_get_dev(info); 566 if (!dev) 567 return -ENODEV; 568 569 msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); 570 if (!msg) 571 goto out_dev; 572 573 rc = ieee802154_nl_fill_iface(msg, info->snd_pid, info->snd_seq, 574 0, dev); 575 if (rc < 0) 576 goto out_free; 577 578 dev_put(dev); 579 580 return genlmsg_unicast(&init_net, msg, info->snd_pid); 581 out_free: 582 nlmsg_free(msg); 583 out_dev: 584 dev_put(dev); 585 return rc; 586 587 } 588 589 static int ieee802154_dump_iface(struct sk_buff *skb, 590 struct netlink_callback *cb) 591 { 592 struct net *net = sock_net(skb->sk); 593 struct net_device *dev; 594 int idx; 595 int s_idx = cb->args[0]; 596 597 pr_debug("%s\n", __func__); 598 599 idx = 0; 600 for_each_netdev(net, dev) { 601 if (idx < s_idx || (dev->type != ARPHRD_IEEE802154)) 602 goto cont; 603 604 if (ieee802154_nl_fill_iface(skb, NETLINK_CB(cb->skb).pid, 605 cb->nlh->nlmsg_seq, NLM_F_MULTI, dev) < 0) 606 break; 607 cont: 608 idx++; 609 } 610 cb->args[0] = idx; 611 612 return skb->len; 613 } 614 615 #define IEEE802154_OP(_cmd, _func) \ 616 { \ 617 .cmd = _cmd, \ 618 .policy = ieee802154_policy, \ 619 .doit = _func, \ 620 .dumpit = NULL, \ 621 .flags = GENL_ADMIN_PERM, \ 622 } 623 624 #define IEEE802154_DUMP(_cmd, _func, _dump) \ 625 { \ 626 .cmd = _cmd, \ 627 .policy = ieee802154_policy, \ 628 .doit = _func, \ 629 .dumpit = _dump, \ 630 } 631 632 static struct genl_ops ieee802154_coordinator_ops[] = { 633 IEEE802154_OP(IEEE802154_ASSOCIATE_REQ, ieee802154_associate_req), 634 IEEE802154_OP(IEEE802154_ASSOCIATE_RESP, ieee802154_associate_resp), 635 IEEE802154_OP(IEEE802154_DISASSOCIATE_REQ, ieee802154_disassociate_req), 636 IEEE802154_OP(IEEE802154_SCAN_REQ, ieee802154_scan_req), 637 IEEE802154_OP(IEEE802154_START_REQ, ieee802154_start_req), 638 IEEE802154_DUMP(IEEE802154_LIST_IFACE, ieee802154_list_iface, 639 ieee802154_dump_iface), 640 }; 641 642 static int __init ieee802154_nl_init(void) 643 { 644 int rc; 645 int i; 646 647 rc = genl_register_family(&ieee802154_coordinator_family); 648 if (rc) 649 goto fail; 650 651 rc = genl_register_mc_group(&ieee802154_coordinator_family, 652 &ieee802154_coord_mcgrp); 653 if (rc) 654 goto fail; 655 656 rc = genl_register_mc_group(&ieee802154_coordinator_family, 657 &ieee802154_beacon_mcgrp); 658 if (rc) 659 goto fail; 660 661 662 for (i = 0; i < ARRAY_SIZE(ieee802154_coordinator_ops); i++) { 663 rc = genl_register_ops(&ieee802154_coordinator_family, 664 &ieee802154_coordinator_ops[i]); 665 if (rc) 666 goto fail; 667 } 668 669 return 0; 670 671 fail: 672 genl_unregister_family(&ieee802154_coordinator_family); 673 return rc; 674 } 675 module_init(ieee802154_nl_init); 676 677 static void __exit ieee802154_nl_exit(void) 678 { 679 genl_unregister_family(&ieee802154_coordinator_family); 680 } 681 module_exit(ieee802154_nl_exit); 682 683 MODULE_LICENSE("GPL v2"); 684 MODULE_DESCRIPTION("ieee 802.15.4 configuration interface"); 685 686