linux/net/ieee802154/nl-mac.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/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
  42static struct genl_multicast_group ieee802154_coord_mcgrp = {
  43        .name           = IEEE802154_MCAST_COORD_NAME,
  44};
  45
  46static struct genl_multicast_group ieee802154_beacon_mcgrp = {
  47        .name           = IEEE802154_MCAST_BEACON_NAME,
  48};
  49
  50int ieee802154_nl_assoc_indic(struct net_device *dev,
  51                struct ieee802154_addr *addr, u8 cap)
  52{
  53        struct sk_buff *msg;
  54
  55        pr_debug("%s\n", __func__);
  56
  57        if (addr->addr_type != IEEE802154_ADDR_LONG) {
  58                pr_err("%s: received non-long source address!\n", __func__);
  59                return -EINVAL;
  60        }
  61
  62        msg = ieee802154_nl_create(0, IEEE802154_ASSOCIATE_INDIC);
  63        if (!msg)
  64                return -ENOBUFS;
  65
  66        if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
  67            nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
  68            nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
  69                    dev->dev_addr) ||
  70            nla_put(msg, IEEE802154_ATTR_SRC_HW_ADDR, IEEE802154_ADDR_LEN,
  71                    addr->hwaddr) ||
  72            nla_put_u8(msg, IEEE802154_ATTR_CAPABILITY, cap))
  73                goto nla_put_failure;
  74
  75        return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
  76
  77nla_put_failure:
  78        nlmsg_free(msg);
  79        return -ENOBUFS;
  80}
  81EXPORT_SYMBOL(ieee802154_nl_assoc_indic);
  82
  83int ieee802154_nl_assoc_confirm(struct net_device *dev, u16 short_addr,
  84                u8 status)
  85{
  86        struct sk_buff *msg;
  87
  88        pr_debug("%s\n", __func__);
  89
  90        msg = ieee802154_nl_create(0, IEEE802154_ASSOCIATE_CONF);
  91        if (!msg)
  92                return -ENOBUFS;
  93
  94        if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
  95            nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
  96            nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
  97                    dev->dev_addr) ||
  98            nla_put_u16(msg, IEEE802154_ATTR_SHORT_ADDR, short_addr) ||
  99            nla_put_u8(msg, IEEE802154_ATTR_STATUS, status))
 100                goto nla_put_failure;
 101        return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
 102
 103nla_put_failure:
 104        nlmsg_free(msg);
 105        return -ENOBUFS;
 106}
 107EXPORT_SYMBOL(ieee802154_nl_assoc_confirm);
 108
 109int ieee802154_nl_disassoc_indic(struct net_device *dev,
 110                struct ieee802154_addr *addr, u8 reason)
 111{
 112        struct sk_buff *msg;
 113
 114        pr_debug("%s\n", __func__);
 115
 116        msg = ieee802154_nl_create(0, IEEE802154_DISASSOCIATE_INDIC);
 117        if (!msg)
 118                return -ENOBUFS;
 119
 120        if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
 121            nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
 122            nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
 123                    dev->dev_addr))
 124                goto nla_put_failure;
 125        if (addr->addr_type == IEEE802154_ADDR_LONG) {
 126                if (nla_put(msg, IEEE802154_ATTR_SRC_HW_ADDR, IEEE802154_ADDR_LEN,
 127                            addr->hwaddr))
 128                        goto nla_put_failure;
 129        } else {
 130                if (nla_put_u16(msg, IEEE802154_ATTR_SRC_SHORT_ADDR,
 131                                addr->short_addr))
 132                        goto nla_put_failure;
 133        }
 134        if (nla_put_u8(msg, IEEE802154_ATTR_REASON, reason))
 135                goto nla_put_failure;
 136        return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
 137
 138nla_put_failure:
 139        nlmsg_free(msg);
 140        return -ENOBUFS;
 141}
 142EXPORT_SYMBOL(ieee802154_nl_disassoc_indic);
 143
 144int ieee802154_nl_disassoc_confirm(struct net_device *dev, u8 status)
 145{
 146        struct sk_buff *msg;
 147
 148        pr_debug("%s\n", __func__);
 149
 150        msg = ieee802154_nl_create(0, IEEE802154_DISASSOCIATE_CONF);
 151        if (!msg)
 152                return -ENOBUFS;
 153
 154        if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
 155            nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
 156            nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
 157                    dev->dev_addr) ||
 158            nla_put_u8(msg, IEEE802154_ATTR_STATUS, status))
 159                goto nla_put_failure;
 160        return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
 161
 162nla_put_failure:
 163        nlmsg_free(msg);
 164        return -ENOBUFS;
 165}
 166EXPORT_SYMBOL(ieee802154_nl_disassoc_confirm);
 167
 168int ieee802154_nl_beacon_indic(struct net_device *dev,
 169                u16 panid, u16 coord_addr)
 170{
 171        struct sk_buff *msg;
 172
 173        pr_debug("%s\n", __func__);
 174
 175        msg = ieee802154_nl_create(0, IEEE802154_BEACON_NOTIFY_INDIC);
 176        if (!msg)
 177                return -ENOBUFS;
 178
 179        if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
 180            nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
 181            nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
 182                    dev->dev_addr) ||
 183            nla_put_u16(msg, IEEE802154_ATTR_COORD_SHORT_ADDR, coord_addr) ||
 184            nla_put_u16(msg, IEEE802154_ATTR_COORD_PAN_ID, panid))
 185                goto nla_put_failure;
 186        return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
 187
 188nla_put_failure:
 189        nlmsg_free(msg);
 190        return -ENOBUFS;
 191}
 192EXPORT_SYMBOL(ieee802154_nl_beacon_indic);
 193
 194int ieee802154_nl_scan_confirm(struct net_device *dev,
 195                u8 status, u8 scan_type, u32 unscanned, u8 page,
 196                u8 *edl/* , struct list_head *pan_desc_list */)
 197{
 198        struct sk_buff *msg;
 199
 200        pr_debug("%s\n", __func__);
 201
 202        msg = ieee802154_nl_create(0, IEEE802154_SCAN_CONF);
 203        if (!msg)
 204                return -ENOBUFS;
 205
 206        if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
 207            nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
 208            nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
 209                    dev->dev_addr) ||
 210            nla_put_u8(msg, IEEE802154_ATTR_STATUS, status) ||
 211            nla_put_u8(msg, IEEE802154_ATTR_SCAN_TYPE, scan_type) ||
 212            nla_put_u32(msg, IEEE802154_ATTR_CHANNELS, unscanned) ||
 213            nla_put_u8(msg, IEEE802154_ATTR_PAGE, page) ||
 214            (edl &&
 215             nla_put(msg, IEEE802154_ATTR_ED_LIST, 27, edl)))
 216                goto nla_put_failure;
 217        return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
 218
 219nla_put_failure:
 220        nlmsg_free(msg);
 221        return -ENOBUFS;
 222}
 223EXPORT_SYMBOL(ieee802154_nl_scan_confirm);
 224
 225int ieee802154_nl_start_confirm(struct net_device *dev, u8 status)
 226{
 227        struct sk_buff *msg;
 228
 229        pr_debug("%s\n", __func__);
 230
 231        msg = ieee802154_nl_create(0, IEEE802154_START_CONF);
 232        if (!msg)
 233                return -ENOBUFS;
 234
 235        if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
 236            nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
 237            nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
 238                    dev->dev_addr) ||
 239            nla_put_u8(msg, IEEE802154_ATTR_STATUS, status))
 240                goto nla_put_failure;
 241        return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
 242
 243nla_put_failure:
 244        nlmsg_free(msg);
 245        return -ENOBUFS;
 246}
 247EXPORT_SYMBOL(ieee802154_nl_start_confirm);
 248
 249static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 portid,
 250        u32 seq, int flags, struct net_device *dev)
 251{
 252        void *hdr;
 253        struct wpan_phy *phy;
 254
 255        pr_debug("%s\n", __func__);
 256
 257        hdr = genlmsg_put(msg, 0, seq, &nl802154_family, flags,
 258                IEEE802154_LIST_IFACE);
 259        if (!hdr)
 260                goto out;
 261
 262        phy = ieee802154_mlme_ops(dev)->get_phy(dev);
 263        BUG_ON(!phy);
 264
 265        if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
 266            nla_put_string(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy)) ||
 267            nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
 268            nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
 269                    dev->dev_addr) ||
 270            nla_put_u16(msg, IEEE802154_ATTR_SHORT_ADDR,
 271                        ieee802154_mlme_ops(dev)->get_short_addr(dev)) ||
 272            nla_put_u16(msg, IEEE802154_ATTR_PAN_ID,
 273                        ieee802154_mlme_ops(dev)->get_pan_id(dev)))
 274                goto nla_put_failure;
 275        wpan_phy_put(phy);
 276        return genlmsg_end(msg, hdr);
 277
 278nla_put_failure:
 279        wpan_phy_put(phy);
 280        genlmsg_cancel(msg, hdr);
 281out:
 282        return -EMSGSIZE;
 283}
 284
 285/* Requests from userspace */
 286static struct net_device *ieee802154_nl_get_dev(struct genl_info *info)
 287{
 288        struct net_device *dev;
 289
 290        if (info->attrs[IEEE802154_ATTR_DEV_NAME]) {
 291                char name[IFNAMSIZ + 1];
 292                nla_strlcpy(name, info->attrs[IEEE802154_ATTR_DEV_NAME],
 293                                sizeof(name));
 294                dev = dev_get_by_name(&init_net, name);
 295        } else if (info->attrs[IEEE802154_ATTR_DEV_INDEX])
 296                dev = dev_get_by_index(&init_net,
 297                        nla_get_u32(info->attrs[IEEE802154_ATTR_DEV_INDEX]));
 298        else
 299                return NULL;
 300
 301        if (!dev)
 302                return NULL;
 303
 304        if (dev->type != ARPHRD_IEEE802154) {
 305                dev_put(dev);
 306                return NULL;
 307        }
 308
 309        return dev;
 310}
 311
 312static int ieee802154_associate_req(struct sk_buff *skb,
 313                struct genl_info *info)
 314{
 315        struct net_device *dev;
 316        struct ieee802154_addr addr;
 317        u8 page;
 318        int ret = -EINVAL;
 319
 320        if (!info->attrs[IEEE802154_ATTR_CHANNEL] ||
 321            !info->attrs[IEEE802154_ATTR_COORD_PAN_ID] ||
 322            (!info->attrs[IEEE802154_ATTR_COORD_HW_ADDR] &&
 323                !info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]) ||
 324            !info->attrs[IEEE802154_ATTR_CAPABILITY])
 325                return -EINVAL;
 326
 327        dev = ieee802154_nl_get_dev(info);
 328        if (!dev)
 329                return -ENODEV;
 330
 331        if (info->attrs[IEEE802154_ATTR_COORD_HW_ADDR]) {
 332                addr.addr_type = IEEE802154_ADDR_LONG;
 333                nla_memcpy(addr.hwaddr,
 334                                info->attrs[IEEE802154_ATTR_COORD_HW_ADDR],
 335                                IEEE802154_ADDR_LEN);
 336        } else {
 337                addr.addr_type = IEEE802154_ADDR_SHORT;
 338                addr.short_addr = nla_get_u16(
 339                                info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]);
 340        }
 341        addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]);
 342
 343        if (info->attrs[IEEE802154_ATTR_PAGE])
 344                page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]);
 345        else
 346                page = 0;
 347
 348        ret = ieee802154_mlme_ops(dev)->assoc_req(dev, &addr,
 349                        nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]),
 350                        page,
 351                        nla_get_u8(info->attrs[IEEE802154_ATTR_CAPABILITY]));
 352
 353        dev_put(dev);
 354        return ret;
 355}
 356
 357static int ieee802154_associate_resp(struct sk_buff *skb,
 358                struct genl_info *info)
 359{
 360        struct net_device *dev;
 361        struct ieee802154_addr addr;
 362        int ret = -EINVAL;
 363
 364        if (!info->attrs[IEEE802154_ATTR_STATUS] ||
 365            !info->attrs[IEEE802154_ATTR_DEST_HW_ADDR] ||
 366            !info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR])
 367                return -EINVAL;
 368
 369        dev = ieee802154_nl_get_dev(info);
 370        if (!dev)
 371                return -ENODEV;
 372
 373        addr.addr_type = IEEE802154_ADDR_LONG;
 374        nla_memcpy(addr.hwaddr, info->attrs[IEEE802154_ATTR_DEST_HW_ADDR],
 375                        IEEE802154_ADDR_LEN);
 376        addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
 377
 378
 379        ret = ieee802154_mlme_ops(dev)->assoc_resp(dev, &addr,
 380                nla_get_u16(info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]),
 381                nla_get_u8(info->attrs[IEEE802154_ATTR_STATUS]));
 382
 383        dev_put(dev);
 384        return ret;
 385}
 386
 387static int ieee802154_disassociate_req(struct sk_buff *skb,
 388                struct genl_info *info)
 389{
 390        struct net_device *dev;
 391        struct ieee802154_addr addr;
 392        int ret = -EINVAL;
 393
 394        if ((!info->attrs[IEEE802154_ATTR_DEST_HW_ADDR] &&
 395                !info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]) ||
 396            !info->attrs[IEEE802154_ATTR_REASON])
 397                return -EINVAL;
 398
 399        dev = ieee802154_nl_get_dev(info);
 400        if (!dev)
 401                return -ENODEV;
 402
 403        if (info->attrs[IEEE802154_ATTR_DEST_HW_ADDR]) {
 404                addr.addr_type = IEEE802154_ADDR_LONG;
 405                nla_memcpy(addr.hwaddr,
 406                                info->attrs[IEEE802154_ATTR_DEST_HW_ADDR],
 407                                IEEE802154_ADDR_LEN);
 408        } else {
 409                addr.addr_type = IEEE802154_ADDR_SHORT;
 410                addr.short_addr = nla_get_u16(
 411                                info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]);
 412        }
 413        addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
 414
 415        ret = ieee802154_mlme_ops(dev)->disassoc_req(dev, &addr,
 416                        nla_get_u8(info->attrs[IEEE802154_ATTR_REASON]));
 417
 418        dev_put(dev);
 419        return ret;
 420}
 421
 422/*
 423 * PANid, channel, beacon_order = 15, superframe_order = 15,
 424 * PAN_coordinator, battery_life_extension = 0,
 425 * coord_realignment = 0, security_enable = 0
 426*/
 427static int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info)
 428{
 429        struct net_device *dev;
 430        struct ieee802154_addr addr;
 431
 432        u8 channel, bcn_ord, sf_ord;
 433        u8 page;
 434        int pan_coord, blx, coord_realign;
 435        int ret;
 436
 437        if (!info->attrs[IEEE802154_ATTR_COORD_PAN_ID] ||
 438            !info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR] ||
 439            !info->attrs[IEEE802154_ATTR_CHANNEL] ||
 440            !info->attrs[IEEE802154_ATTR_BCN_ORD] ||
 441            !info->attrs[IEEE802154_ATTR_SF_ORD] ||
 442            !info->attrs[IEEE802154_ATTR_PAN_COORD] ||
 443            !info->attrs[IEEE802154_ATTR_BAT_EXT] ||
 444            !info->attrs[IEEE802154_ATTR_COORD_REALIGN]
 445         )
 446                return -EINVAL;
 447
 448        dev = ieee802154_nl_get_dev(info);
 449        if (!dev)
 450                return -ENODEV;
 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        dev_put(dev);
 480        return ret;
 481}
 482
 483static int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info)
 484{
 485        struct net_device *dev;
 486        int ret;
 487        u8 type;
 488        u32 channels;
 489        u8 duration;
 490        u8 page;
 491
 492        if (!info->attrs[IEEE802154_ATTR_SCAN_TYPE] ||
 493            !info->attrs[IEEE802154_ATTR_CHANNELS] ||
 494            !info->attrs[IEEE802154_ATTR_DURATION])
 495                return -EINVAL;
 496
 497        dev = ieee802154_nl_get_dev(info);
 498        if (!dev)
 499                return -ENODEV;
 500
 501        type = nla_get_u8(info->attrs[IEEE802154_ATTR_SCAN_TYPE]);
 502        channels = nla_get_u32(info->attrs[IEEE802154_ATTR_CHANNELS]);
 503        duration = nla_get_u8(info->attrs[IEEE802154_ATTR_DURATION]);
 504
 505        if (info->attrs[IEEE802154_ATTR_PAGE])
 506                page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]);
 507        else
 508                page = 0;
 509
 510
 511        ret = ieee802154_mlme_ops(dev)->scan_req(dev, type, channels, page,
 512                        duration);
 513
 514        dev_put(dev);
 515        return ret;
 516}
 517
 518static int ieee802154_list_iface(struct sk_buff *skb,
 519        struct genl_info *info)
 520{
 521        /* Request for interface name, index, type, IEEE address,
 522           PAN Id, short address */
 523        struct sk_buff *msg;
 524        struct net_device *dev = NULL;
 525        int rc = -ENOBUFS;
 526
 527        pr_debug("%s\n", __func__);
 528
 529        dev = ieee802154_nl_get_dev(info);
 530        if (!dev)
 531                return -ENODEV;
 532
 533        msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
 534        if (!msg)
 535                goto out_dev;
 536
 537        rc = ieee802154_nl_fill_iface(msg, info->snd_portid, info->snd_seq,
 538                        0, dev);
 539        if (rc < 0)
 540                goto out_free;
 541
 542        dev_put(dev);
 543
 544        return genlmsg_reply(msg, info);
 545out_free:
 546        nlmsg_free(msg);
 547out_dev:
 548        dev_put(dev);
 549        return rc;
 550
 551}
 552
 553static int ieee802154_dump_iface(struct sk_buff *skb,
 554        struct netlink_callback *cb)
 555{
 556        struct net *net = sock_net(skb->sk);
 557        struct net_device *dev;
 558        int idx;
 559        int s_idx = cb->args[0];
 560
 561        pr_debug("%s\n", __func__);
 562
 563        idx = 0;
 564        for_each_netdev(net, dev) {
 565                if (idx < s_idx || (dev->type != ARPHRD_IEEE802154))
 566                        goto cont;
 567
 568                if (ieee802154_nl_fill_iface(skb, NETLINK_CB(cb->skb).portid,
 569                        cb->nlh->nlmsg_seq, NLM_F_MULTI, dev) < 0)
 570                        break;
 571cont:
 572                idx++;
 573        }
 574        cb->args[0] = idx;
 575
 576        return skb->len;
 577}
 578
 579static struct genl_ops ieee802154_coordinator_ops[] = {
 580        IEEE802154_OP(IEEE802154_ASSOCIATE_REQ, ieee802154_associate_req),
 581        IEEE802154_OP(IEEE802154_ASSOCIATE_RESP, ieee802154_associate_resp),
 582        IEEE802154_OP(IEEE802154_DISASSOCIATE_REQ, ieee802154_disassociate_req),
 583        IEEE802154_OP(IEEE802154_SCAN_REQ, ieee802154_scan_req),
 584        IEEE802154_OP(IEEE802154_START_REQ, ieee802154_start_req),
 585        IEEE802154_DUMP(IEEE802154_LIST_IFACE, ieee802154_list_iface,
 586                                                        ieee802154_dump_iface),
 587};
 588
 589/*
 590 * No need to unregister as family unregistration will do it.
 591 */
 592int nl802154_mac_register(void)
 593{
 594        int i;
 595        int rc;
 596
 597        rc = genl_register_mc_group(&nl802154_family,
 598                        &ieee802154_coord_mcgrp);
 599        if (rc)
 600                return rc;
 601
 602        rc = genl_register_mc_group(&nl802154_family,
 603                        &ieee802154_beacon_mcgrp);
 604        if (rc)
 605                return rc;
 606
 607        for (i = 0; i < ARRAY_SIZE(ieee802154_coordinator_ops); i++) {
 608                rc = genl_register_ops(&nl802154_family,
 609                                &ieee802154_coordinator_ops[i]);
 610                if (rc)
 611                        return rc;
 612        }
 613
 614        return 0;
 615}
 616
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.