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