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