linux/net/ieee802154/nl802154.c
<<
>>
Prefs
   1/* This program is free software; you can redistribute it and/or modify
   2 * it under the terms of the GNU General Public License version 2
   3 * as published by the Free Software Foundation.
   4 *
   5 * This program is distributed in the hope that it will be useful,
   6 * but WITHOUT ANY WARRANTY; without even the implied warranty of
   7 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   8 * GNU General Public License for more details.
   9 *
  10 * Authors:
  11 * Alexander Aring <aar@pengutronix.de>
  12 *
  13 * Based on: net/wireless/nl80211.c
  14 */
  15
  16#include <linux/rtnetlink.h>
  17
  18#include <net/cfg802154.h>
  19#include <net/genetlink.h>
  20#include <net/mac802154.h>
  21#include <net/netlink.h>
  22#include <net/nl802154.h>
  23#include <net/sock.h>
  24
  25#include "nl802154.h"
  26#include "rdev-ops.h"
  27#include "core.h"
  28
  29static int nl802154_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
  30                             struct genl_info *info);
  31
  32static void nl802154_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
  33                               struct genl_info *info);
  34
  35/* the netlink family */
  36static struct genl_family nl802154_fam = {
  37        .id = GENL_ID_GENERATE,         /* don't bother with a hardcoded ID */
  38        .name = NL802154_GENL_NAME,     /* have users key off the name instead */
  39        .hdrsize = 0,                   /* no private header */
  40        .version = 1,                   /* no particular meaning now */
  41        .maxattr = NL802154_ATTR_MAX,
  42        .netnsok = true,
  43        .pre_doit = nl802154_pre_doit,
  44        .post_doit = nl802154_post_doit,
  45};
  46
  47/* multicast groups */
  48enum nl802154_multicast_groups {
  49        NL802154_MCGRP_CONFIG,
  50};
  51
  52static const struct genl_multicast_group nl802154_mcgrps[] = {
  53        [NL802154_MCGRP_CONFIG] = { .name = "config", },
  54};
  55
  56/* returns ERR_PTR values */
  57static struct wpan_dev *
  58__cfg802154_wpan_dev_from_attrs(struct net *netns, struct nlattr **attrs)
  59{
  60        struct cfg802154_registered_device *rdev;
  61        struct wpan_dev *result = NULL;
  62        bool have_ifidx = attrs[NL802154_ATTR_IFINDEX];
  63        bool have_wpan_dev_id = attrs[NL802154_ATTR_WPAN_DEV];
  64        u64 wpan_dev_id;
  65        int wpan_phy_idx = -1;
  66        int ifidx = -1;
  67
  68        ASSERT_RTNL();
  69
  70        if (!have_ifidx && !have_wpan_dev_id)
  71                return ERR_PTR(-EINVAL);
  72
  73        if (have_ifidx)
  74                ifidx = nla_get_u32(attrs[NL802154_ATTR_IFINDEX]);
  75        if (have_wpan_dev_id) {
  76                wpan_dev_id = nla_get_u64(attrs[NL802154_ATTR_WPAN_DEV]);
  77                wpan_phy_idx = wpan_dev_id >> 32;
  78        }
  79
  80        list_for_each_entry(rdev, &cfg802154_rdev_list, list) {
  81                struct wpan_dev *wpan_dev;
  82
  83                /* TODO netns compare */
  84
  85                if (have_wpan_dev_id && rdev->wpan_phy_idx != wpan_phy_idx)
  86                        continue;
  87
  88                list_for_each_entry(wpan_dev, &rdev->wpan_dev_list, list) {
  89                        if (have_ifidx && wpan_dev->netdev &&
  90                            wpan_dev->netdev->ifindex == ifidx) {
  91                                result = wpan_dev;
  92                                break;
  93                        }
  94                        if (have_wpan_dev_id &&
  95                            wpan_dev->identifier == (u32)wpan_dev_id) {
  96                                result = wpan_dev;
  97                                break;
  98                        }
  99                }
 100
 101                if (result)
 102                        break;
 103        }
 104
 105        if (result)
 106                return result;
 107
 108        return ERR_PTR(-ENODEV);
 109}
 110
 111static struct cfg802154_registered_device *
 112__cfg802154_rdev_from_attrs(struct net *netns, struct nlattr **attrs)
 113{
 114        struct cfg802154_registered_device *rdev = NULL, *tmp;
 115        struct net_device *netdev;
 116
 117        ASSERT_RTNL();
 118
 119        if (!attrs[NL802154_ATTR_WPAN_PHY] &&
 120            !attrs[NL802154_ATTR_IFINDEX] &&
 121            !attrs[NL802154_ATTR_WPAN_DEV])
 122                return ERR_PTR(-EINVAL);
 123
 124        if (attrs[NL802154_ATTR_WPAN_PHY])
 125                rdev = cfg802154_rdev_by_wpan_phy_idx(
 126                                nla_get_u32(attrs[NL802154_ATTR_WPAN_PHY]));
 127
 128        if (attrs[NL802154_ATTR_WPAN_DEV]) {
 129                u64 wpan_dev_id = nla_get_u64(attrs[NL802154_ATTR_WPAN_DEV]);
 130                struct wpan_dev *wpan_dev;
 131                bool found = false;
 132
 133                tmp = cfg802154_rdev_by_wpan_phy_idx(wpan_dev_id >> 32);
 134                if (tmp) {
 135                        /* make sure wpan_dev exists */
 136                        list_for_each_entry(wpan_dev, &tmp->wpan_dev_list, list) {
 137                                if (wpan_dev->identifier != (u32)wpan_dev_id)
 138                                        continue;
 139                                found = true;
 140                                break;
 141                        }
 142
 143                        if (!found)
 144                                tmp = NULL;
 145
 146                        if (rdev && tmp != rdev)
 147                                return ERR_PTR(-EINVAL);
 148                        rdev = tmp;
 149                }
 150        }
 151
 152        if (attrs[NL802154_ATTR_IFINDEX]) {
 153                int ifindex = nla_get_u32(attrs[NL802154_ATTR_IFINDEX]);
 154
 155                netdev = __dev_get_by_index(netns, ifindex);
 156                if (netdev) {
 157                        if (netdev->ieee802154_ptr)
 158                                tmp = wpan_phy_to_rdev(
 159                                                netdev->ieee802154_ptr->wpan_phy);
 160                        else
 161                                tmp = NULL;
 162
 163                        /* not wireless device -- return error */
 164                        if (!tmp)
 165                                return ERR_PTR(-EINVAL);
 166
 167                        /* mismatch -- return error */
 168                        if (rdev && tmp != rdev)
 169                                return ERR_PTR(-EINVAL);
 170
 171                        rdev = tmp;
 172                }
 173        }
 174
 175        if (!rdev)
 176                return ERR_PTR(-ENODEV);
 177
 178        /* TODO netns compare */
 179
 180        return rdev;
 181}
 182
 183/* This function returns a pointer to the driver
 184 * that the genl_info item that is passed refers to.
 185 *
 186 * The result of this can be a PTR_ERR and hence must
 187 * be checked with IS_ERR() for errors.
 188 */
 189static struct cfg802154_registered_device *
 190cfg802154_get_dev_from_info(struct net *netns, struct genl_info *info)
 191{
 192        return __cfg802154_rdev_from_attrs(netns, info->attrs);
 193}
 194
 195/* policy for the attributes */
 196static const struct nla_policy nl802154_policy[NL802154_ATTR_MAX+1] = {
 197        [NL802154_ATTR_WPAN_PHY] = { .type = NLA_U32 },
 198        [NL802154_ATTR_WPAN_PHY_NAME] = { .type = NLA_NUL_STRING,
 199                                          .len = 20-1 },
 200
 201        [NL802154_ATTR_IFINDEX] = { .type = NLA_U32 },
 202        [NL802154_ATTR_IFTYPE] = { .type = NLA_U32 },
 203        [NL802154_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 },
 204
 205        [NL802154_ATTR_WPAN_DEV] = { .type = NLA_U64 },
 206
 207        [NL802154_ATTR_PAGE] = { .type = NLA_U8, },
 208        [NL802154_ATTR_CHANNEL] = { .type = NLA_U8, },
 209
 210        [NL802154_ATTR_TX_POWER] = { .type = NLA_S32, },
 211
 212        [NL802154_ATTR_CCA_MODE] = { .type = NLA_U32, },
 213        [NL802154_ATTR_CCA_OPT] = { .type = NLA_U32, },
 214        [NL802154_ATTR_CCA_ED_LEVEL] = { .type = NLA_S32, },
 215
 216        [NL802154_ATTR_SUPPORTED_CHANNEL] = { .type = NLA_U32, },
 217
 218        [NL802154_ATTR_PAN_ID] = { .type = NLA_U16, },
 219        [NL802154_ATTR_EXTENDED_ADDR] = { .type = NLA_U64 },
 220        [NL802154_ATTR_SHORT_ADDR] = { .type = NLA_U16, },
 221
 222        [NL802154_ATTR_MIN_BE] = { .type = NLA_U8, },
 223        [NL802154_ATTR_MAX_BE] = { .type = NLA_U8, },
 224        [NL802154_ATTR_MAX_CSMA_BACKOFFS] = { .type = NLA_U8, },
 225
 226        [NL802154_ATTR_MAX_FRAME_RETRIES] = { .type = NLA_S8, },
 227
 228        [NL802154_ATTR_LBT_MODE] = { .type = NLA_U8, },
 229
 230        [NL802154_ATTR_WPAN_PHY_CAPS] = { .type = NLA_NESTED },
 231
 232        [NL802154_ATTR_SUPPORTED_COMMANDS] = { .type = NLA_NESTED },
 233
 234        [NL802154_ATTR_ACKREQ_DEFAULT] = { .type = NLA_U8 },
 235};
 236
 237/* message building helper */
 238static inline void *nl802154hdr_put(struct sk_buff *skb, u32 portid, u32 seq,
 239                                    int flags, u8 cmd)
 240{
 241        /* since there is no private header just add the generic one */
 242        return genlmsg_put(skb, portid, seq, &nl802154_fam, flags, cmd);
 243}
 244
 245static int
 246nl802154_put_flags(struct sk_buff *msg, int attr, u32 mask)
 247{
 248        struct nlattr *nl_flags = nla_nest_start(msg, attr);
 249        int i;
 250
 251        if (!nl_flags)
 252                return -ENOBUFS;
 253
 254        i = 0;
 255        while (mask) {
 256                if ((mask & 1) && nla_put_flag(msg, i))
 257                        return -ENOBUFS;
 258
 259                mask >>= 1;
 260                i++;
 261        }
 262
 263        nla_nest_end(msg, nl_flags);
 264        return 0;
 265}
 266
 267static int
 268nl802154_send_wpan_phy_channels(struct cfg802154_registered_device *rdev,
 269                                struct sk_buff *msg)
 270{
 271        struct nlattr *nl_page;
 272        unsigned long page;
 273
 274        nl_page = nla_nest_start(msg, NL802154_ATTR_CHANNELS_SUPPORTED);
 275        if (!nl_page)
 276                return -ENOBUFS;
 277
 278        for (page = 0; page <= IEEE802154_MAX_PAGE; page++) {
 279                if (nla_put_u32(msg, NL802154_ATTR_SUPPORTED_CHANNEL,
 280                                rdev->wpan_phy.supported.channels[page]))
 281                        return -ENOBUFS;
 282        }
 283        nla_nest_end(msg, nl_page);
 284
 285        return 0;
 286}
 287
 288static int
 289nl802154_put_capabilities(struct sk_buff *msg,
 290                          struct cfg802154_registered_device *rdev)
 291{
 292        const struct wpan_phy_supported *caps = &rdev->wpan_phy.supported;
 293        struct nlattr *nl_caps, *nl_channels;
 294        int i;
 295
 296        nl_caps = nla_nest_start(msg, NL802154_ATTR_WPAN_PHY_CAPS);
 297        if (!nl_caps)
 298                return -ENOBUFS;
 299
 300        nl_channels = nla_nest_start(msg, NL802154_CAP_ATTR_CHANNELS);
 301        if (!nl_channels)
 302                return -ENOBUFS;
 303
 304        for (i = 0; i <= IEEE802154_MAX_PAGE; i++) {
 305                if (caps->channels[i]) {
 306                        if (nl802154_put_flags(msg, i, caps->channels[i]))
 307                                return -ENOBUFS;
 308                }
 309        }
 310
 311        nla_nest_end(msg, nl_channels);
 312
 313        if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_ED_LEVEL) {
 314                struct nlattr *nl_ed_lvls;
 315
 316                nl_ed_lvls = nla_nest_start(msg,
 317                                            NL802154_CAP_ATTR_CCA_ED_LEVELS);
 318                if (!nl_ed_lvls)
 319                        return -ENOBUFS;
 320
 321                for (i = 0; i < caps->cca_ed_levels_size; i++) {
 322                        if (nla_put_s32(msg, i, caps->cca_ed_levels[i]))
 323                                return -ENOBUFS;
 324                }
 325
 326                nla_nest_end(msg, nl_ed_lvls);
 327        }
 328
 329        if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_TXPOWER) {
 330                struct nlattr *nl_tx_pwrs;
 331
 332                nl_tx_pwrs = nla_nest_start(msg, NL802154_CAP_ATTR_TX_POWERS);
 333                if (!nl_tx_pwrs)
 334                        return -ENOBUFS;
 335
 336                for (i = 0; i < caps->tx_powers_size; i++) {
 337                        if (nla_put_s32(msg, i, caps->tx_powers[i]))
 338                                return -ENOBUFS;
 339                }
 340
 341                nla_nest_end(msg, nl_tx_pwrs);
 342        }
 343
 344        if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_MODE) {
 345                if (nl802154_put_flags(msg, NL802154_CAP_ATTR_CCA_MODES,
 346                                       caps->cca_modes) ||
 347                    nl802154_put_flags(msg, NL802154_CAP_ATTR_CCA_OPTS,
 348                                       caps->cca_opts))
 349                        return -ENOBUFS;
 350        }
 351
 352        if (nla_put_u8(msg, NL802154_CAP_ATTR_MIN_MINBE, caps->min_minbe) ||
 353            nla_put_u8(msg, NL802154_CAP_ATTR_MAX_MINBE, caps->max_minbe) ||
 354            nla_put_u8(msg, NL802154_CAP_ATTR_MIN_MAXBE, caps->min_maxbe) ||
 355            nla_put_u8(msg, NL802154_CAP_ATTR_MAX_MAXBE, caps->max_maxbe) ||
 356            nla_put_u8(msg, NL802154_CAP_ATTR_MIN_CSMA_BACKOFFS,
 357                       caps->min_csma_backoffs) ||
 358            nla_put_u8(msg, NL802154_CAP_ATTR_MAX_CSMA_BACKOFFS,
 359                       caps->max_csma_backoffs) ||
 360            nla_put_s8(msg, NL802154_CAP_ATTR_MIN_FRAME_RETRIES,
 361                       caps->min_frame_retries) ||
 362            nla_put_s8(msg, NL802154_CAP_ATTR_MAX_FRAME_RETRIES,
 363                       caps->max_frame_retries) ||
 364            nl802154_put_flags(msg, NL802154_CAP_ATTR_IFTYPES,
 365                               caps->iftypes) ||
 366            nla_put_u32(msg, NL802154_CAP_ATTR_LBT, caps->lbt))
 367                return -ENOBUFS;
 368
 369        nla_nest_end(msg, nl_caps);
 370
 371        return 0;
 372}
 373
 374static int nl802154_send_wpan_phy(struct cfg802154_registered_device *rdev,
 375                                  enum nl802154_commands cmd,
 376                                  struct sk_buff *msg, u32 portid, u32 seq,
 377                                  int flags)
 378{
 379        struct nlattr *nl_cmds;
 380        void *hdr;
 381        int i;
 382
 383        hdr = nl802154hdr_put(msg, portid, seq, flags, cmd);
 384        if (!hdr)
 385                return -ENOBUFS;
 386
 387        if (nla_put_u32(msg, NL802154_ATTR_WPAN_PHY, rdev->wpan_phy_idx) ||
 388            nla_put_string(msg, NL802154_ATTR_WPAN_PHY_NAME,
 389                           wpan_phy_name(&rdev->wpan_phy)) ||
 390            nla_put_u32(msg, NL802154_ATTR_GENERATION,
 391                        cfg802154_rdev_list_generation))
 392                goto nla_put_failure;
 393
 394        if (cmd != NL802154_CMD_NEW_WPAN_PHY)
 395                goto finish;
 396
 397        /* DUMP PHY PIB */
 398
 399        /* current channel settings */
 400        if (nla_put_u8(msg, NL802154_ATTR_PAGE,
 401                       rdev->wpan_phy.current_page) ||
 402            nla_put_u8(msg, NL802154_ATTR_CHANNEL,
 403                       rdev->wpan_phy.current_channel))
 404                goto nla_put_failure;
 405
 406        /* TODO remove this behaviour, we still keep support it for a while
 407         * so users can change the behaviour to the new one.
 408         */
 409        if (nl802154_send_wpan_phy_channels(rdev, msg))
 410                goto nla_put_failure;
 411
 412        /* cca mode */
 413        if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_MODE) {
 414                if (nla_put_u32(msg, NL802154_ATTR_CCA_MODE,
 415                                rdev->wpan_phy.cca.mode))
 416                        goto nla_put_failure;
 417
 418                if (rdev->wpan_phy.cca.mode == NL802154_CCA_ENERGY_CARRIER) {
 419                        if (nla_put_u32(msg, NL802154_ATTR_CCA_OPT,
 420                                        rdev->wpan_phy.cca.opt))
 421                                goto nla_put_failure;
 422                }
 423        }
 424
 425        if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_TXPOWER) {
 426                if (nla_put_s32(msg, NL802154_ATTR_TX_POWER,
 427                                rdev->wpan_phy.transmit_power))
 428                        goto nla_put_failure;
 429        }
 430
 431        if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_ED_LEVEL) {
 432                if (nla_put_s32(msg, NL802154_ATTR_CCA_ED_LEVEL,
 433                                rdev->wpan_phy.cca_ed_level))
 434                        goto nla_put_failure;
 435        }
 436
 437        if (nl802154_put_capabilities(msg, rdev))
 438                goto nla_put_failure;
 439
 440        nl_cmds = nla_nest_start(msg, NL802154_ATTR_SUPPORTED_COMMANDS);
 441        if (!nl_cmds)
 442                goto nla_put_failure;
 443
 444        i = 0;
 445#define CMD(op, n)                                                      \
 446        do {                                                            \
 447                if (rdev->ops->op) {                                    \
 448                        i++;                                            \
 449                        if (nla_put_u32(msg, i, NL802154_CMD_ ## n))    \
 450                                goto nla_put_failure;                   \
 451                }                                                       \
 452        } while (0)
 453
 454        CMD(add_virtual_intf, NEW_INTERFACE);
 455        CMD(del_virtual_intf, DEL_INTERFACE);
 456        CMD(set_channel, SET_CHANNEL);
 457        CMD(set_pan_id, SET_PAN_ID);
 458        CMD(set_short_addr, SET_SHORT_ADDR);
 459        CMD(set_backoff_exponent, SET_BACKOFF_EXPONENT);
 460        CMD(set_max_csma_backoffs, SET_MAX_CSMA_BACKOFFS);
 461        CMD(set_max_frame_retries, SET_MAX_FRAME_RETRIES);
 462        CMD(set_lbt_mode, SET_LBT_MODE);
 463        CMD(set_ackreq_default, SET_ACKREQ_DEFAULT);
 464
 465        if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_TXPOWER)
 466                CMD(set_tx_power, SET_TX_POWER);
 467
 468        if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_ED_LEVEL)
 469                CMD(set_cca_ed_level, SET_CCA_ED_LEVEL);
 470
 471        if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_MODE)
 472                CMD(set_cca_mode, SET_CCA_MODE);
 473
 474#undef CMD
 475        nla_nest_end(msg, nl_cmds);
 476
 477finish:
 478        genlmsg_end(msg, hdr);
 479        return 0;
 480
 481nla_put_failure:
 482        genlmsg_cancel(msg, hdr);
 483        return -EMSGSIZE;
 484}
 485
 486struct nl802154_dump_wpan_phy_state {
 487        s64 filter_wpan_phy;
 488        long start;
 489
 490};
 491
 492static int nl802154_dump_wpan_phy_parse(struct sk_buff *skb,
 493                                        struct netlink_callback *cb,
 494                                        struct nl802154_dump_wpan_phy_state *state)
 495{
 496        struct nlattr **tb = nl802154_fam.attrbuf;
 497        int ret = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl802154_fam.hdrsize,
 498                              tb, nl802154_fam.maxattr, nl802154_policy);
 499
 500        /* TODO check if we can handle error here,
 501         * we have no backward compatibility
 502         */
 503        if (ret)
 504                return 0;
 505
 506        if (tb[NL802154_ATTR_WPAN_PHY])
 507                state->filter_wpan_phy = nla_get_u32(tb[NL802154_ATTR_WPAN_PHY]);
 508        if (tb[NL802154_ATTR_WPAN_DEV])
 509                state->filter_wpan_phy = nla_get_u64(tb[NL802154_ATTR_WPAN_DEV]) >> 32;
 510        if (tb[NL802154_ATTR_IFINDEX]) {
 511                struct net_device *netdev;
 512                struct cfg802154_registered_device *rdev;
 513                int ifidx = nla_get_u32(tb[NL802154_ATTR_IFINDEX]);
 514
 515                /* TODO netns */
 516                netdev = __dev_get_by_index(&init_net, ifidx);
 517                if (!netdev)
 518                        return -ENODEV;
 519                if (netdev->ieee802154_ptr) {
 520                        rdev = wpan_phy_to_rdev(
 521                                        netdev->ieee802154_ptr->wpan_phy);
 522                        state->filter_wpan_phy = rdev->wpan_phy_idx;
 523                }
 524        }
 525
 526        return 0;
 527}
 528
 529static int
 530nl802154_dump_wpan_phy(struct sk_buff *skb, struct netlink_callback *cb)
 531{
 532        int idx = 0, ret;
 533        struct nl802154_dump_wpan_phy_state *state = (void *)cb->args[0];
 534        struct cfg802154_registered_device *rdev;
 535
 536        rtnl_lock();
 537        if (!state) {
 538                state = kzalloc(sizeof(*state), GFP_KERNEL);
 539                if (!state) {
 540                        rtnl_unlock();
 541                        return -ENOMEM;
 542                }
 543                state->filter_wpan_phy = -1;
 544                ret = nl802154_dump_wpan_phy_parse(skb, cb, state);
 545                if (ret) {
 546                        kfree(state);
 547                        rtnl_unlock();
 548                        return ret;
 549                }
 550                cb->args[0] = (long)state;
 551        }
 552
 553        list_for_each_entry(rdev, &cfg802154_rdev_list, list) {
 554                /* TODO net ns compare */
 555                if (++idx <= state->start)
 556                        continue;
 557                if (state->filter_wpan_phy != -1 &&
 558                    state->filter_wpan_phy != rdev->wpan_phy_idx)
 559                        continue;
 560                /* attempt to fit multiple wpan_phy data chunks into the skb */
 561                ret = nl802154_send_wpan_phy(rdev,
 562                                             NL802154_CMD_NEW_WPAN_PHY,
 563                                             skb,
 564                                             NETLINK_CB(cb->skb).portid,
 565                                             cb->nlh->nlmsg_seq, NLM_F_MULTI);
 566                if (ret < 0) {
 567                        if ((ret == -ENOBUFS || ret == -EMSGSIZE) &&
 568                            !skb->len && cb->min_dump_alloc < 4096) {
 569                                cb->min_dump_alloc = 4096;
 570                                rtnl_unlock();
 571                                return 1;
 572                        }
 573                        idx--;
 574                        break;
 575                }
 576                break;
 577        }
 578        rtnl_unlock();
 579
 580        state->start = idx;
 581
 582        return skb->len;
 583}
 584
 585static int nl802154_dump_wpan_phy_done(struct netlink_callback *cb)
 586{
 587        kfree((void *)cb->args[0]);
 588        return 0;
 589}
 590
 591static int nl802154_get_wpan_phy(struct sk_buff *skb, struct genl_info *info)
 592{
 593        struct sk_buff *msg;
 594        struct cfg802154_registered_device *rdev = info->user_ptr[0];
 595
 596        msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
 597        if (!msg)
 598                return -ENOMEM;
 599
 600        if (nl802154_send_wpan_phy(rdev, NL802154_CMD_NEW_WPAN_PHY, msg,
 601                                   info->snd_portid, info->snd_seq, 0) < 0) {
 602                nlmsg_free(msg);
 603                return -ENOBUFS;
 604        }
 605
 606        return genlmsg_reply(msg, info);
 607}
 608
 609static inline u64 wpan_dev_id(struct wpan_dev *wpan_dev)
 610{
 611        return (u64)wpan_dev->identifier |
 612               ((u64)wpan_phy_to_rdev(wpan_dev->wpan_phy)->wpan_phy_idx << 32);
 613}
 614
 615static int
 616nl802154_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flags,
 617                    struct cfg802154_registered_device *rdev,
 618                    struct wpan_dev *wpan_dev)
 619{
 620        struct net_device *dev = wpan_dev->netdev;
 621        void *hdr;
 622
 623        hdr = nl802154hdr_put(msg, portid, seq, flags,
 624                              NL802154_CMD_NEW_INTERFACE);
 625        if (!hdr)
 626                return -1;
 627
 628        if (dev &&
 629            (nla_put_u32(msg, NL802154_ATTR_IFINDEX, dev->ifindex) ||
 630             nla_put_string(msg, NL802154_ATTR_IFNAME, dev->name)))
 631                goto nla_put_failure;
 632
 633        if (nla_put_u32(msg, NL802154_ATTR_WPAN_PHY, rdev->wpan_phy_idx) ||
 634            nla_put_u32(msg, NL802154_ATTR_IFTYPE, wpan_dev->iftype) ||
 635            nla_put_u64(msg, NL802154_ATTR_WPAN_DEV, wpan_dev_id(wpan_dev)) ||
 636            nla_put_u32(msg, NL802154_ATTR_GENERATION,
 637                        rdev->devlist_generation ^
 638                        (cfg802154_rdev_list_generation << 2)))
 639                goto nla_put_failure;
 640
 641        /* address settings */
 642        if (nla_put_le64(msg, NL802154_ATTR_EXTENDED_ADDR,
 643                         wpan_dev->extended_addr) ||
 644            nla_put_le16(msg, NL802154_ATTR_SHORT_ADDR,
 645                         wpan_dev->short_addr) ||
 646            nla_put_le16(msg, NL802154_ATTR_PAN_ID, wpan_dev->pan_id))
 647                goto nla_put_failure;
 648
 649        /* ARET handling */
 650        if (nla_put_s8(msg, NL802154_ATTR_MAX_FRAME_RETRIES,
 651                       wpan_dev->frame_retries) ||
 652            nla_put_u8(msg, NL802154_ATTR_MAX_BE, wpan_dev->max_be) ||
 653            nla_put_u8(msg, NL802154_ATTR_MAX_CSMA_BACKOFFS,
 654                       wpan_dev->csma_retries) ||
 655            nla_put_u8(msg, NL802154_ATTR_MIN_BE, wpan_dev->min_be))
 656                goto nla_put_failure;
 657
 658        /* listen before transmit */
 659        if (nla_put_u8(msg, NL802154_ATTR_LBT_MODE, wpan_dev->lbt))
 660                goto nla_put_failure;
 661
 662        /* ackreq default behaviour */
 663        if (nla_put_u8(msg, NL802154_ATTR_ACKREQ_DEFAULT, wpan_dev->ackreq))
 664                goto nla_put_failure;
 665
 666        genlmsg_end(msg, hdr);
 667        return 0;
 668
 669nla_put_failure:
 670        genlmsg_cancel(msg, hdr);
 671        return -EMSGSIZE;
 672}
 673
 674static int
 675nl802154_dump_interface(struct sk_buff *skb, struct netlink_callback *cb)
 676{
 677        int wp_idx = 0;
 678        int if_idx = 0;
 679        int wp_start = cb->args[0];
 680        int if_start = cb->args[1];
 681        struct cfg802154_registered_device *rdev;
 682        struct wpan_dev *wpan_dev;
 683
 684        rtnl_lock();
 685        list_for_each_entry(rdev, &cfg802154_rdev_list, list) {
 686                /* TODO netns compare */
 687                if (wp_idx < wp_start) {
 688                        wp_idx++;
 689                        continue;
 690                }
 691                if_idx = 0;
 692
 693                list_for_each_entry(wpan_dev, &rdev->wpan_dev_list, list) {
 694                        if (if_idx < if_start) {
 695                                if_idx++;
 696                                continue;
 697                        }
 698                        if (nl802154_send_iface(skb, NETLINK_CB(cb->skb).portid,
 699                                                cb->nlh->nlmsg_seq, NLM_F_MULTI,
 700                                                rdev, wpan_dev) < 0) {
 701                                goto out;
 702                        }
 703                        if_idx++;
 704                }
 705
 706                wp_idx++;
 707        }
 708out:
 709        rtnl_unlock();
 710
 711        cb->args[0] = wp_idx;
 712        cb->args[1] = if_idx;
 713
 714        return skb->len;
 715}
 716
 717static int nl802154_get_interface(struct sk_buff *skb, struct genl_info *info)
 718{
 719        struct sk_buff *msg;
 720        struct cfg802154_registered_device *rdev = info->user_ptr[0];
 721        struct wpan_dev *wdev = info->user_ptr[1];
 722
 723        msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
 724        if (!msg)
 725                return -ENOMEM;
 726
 727        if (nl802154_send_iface(msg, info->snd_portid, info->snd_seq, 0,
 728                                rdev, wdev) < 0) {
 729                nlmsg_free(msg);
 730                return -ENOBUFS;
 731        }
 732
 733        return genlmsg_reply(msg, info);
 734}
 735
 736static int nl802154_new_interface(struct sk_buff *skb, struct genl_info *info)
 737{
 738        struct cfg802154_registered_device *rdev = info->user_ptr[0];
 739        enum nl802154_iftype type = NL802154_IFTYPE_UNSPEC;
 740        __le64 extended_addr = cpu_to_le64(0x0000000000000000ULL);
 741
 742        /* TODO avoid failing a new interface
 743         * creation due to pending removal?
 744         */
 745
 746        if (!info->attrs[NL802154_ATTR_IFNAME])
 747                return -EINVAL;
 748
 749        if (info->attrs[NL802154_ATTR_IFTYPE]) {
 750                type = nla_get_u32(info->attrs[NL802154_ATTR_IFTYPE]);
 751                if (type > NL802154_IFTYPE_MAX ||
 752                    !(rdev->wpan_phy.supported.iftypes & BIT(type)))
 753                        return -EINVAL;
 754        }
 755
 756        /* TODO add nla_get_le64 to netlink */
 757        if (info->attrs[NL802154_ATTR_EXTENDED_ADDR])
 758                extended_addr = (__force __le64)nla_get_u64(
 759                                info->attrs[NL802154_ATTR_EXTENDED_ADDR]);
 760
 761        if (!rdev->ops->add_virtual_intf)
 762                return -EOPNOTSUPP;
 763
 764        return rdev_add_virtual_intf(rdev,
 765                                     nla_data(info->attrs[NL802154_ATTR_IFNAME]),
 766                                     NET_NAME_USER, type, extended_addr);
 767}
 768
 769static int nl802154_del_interface(struct sk_buff *skb, struct genl_info *info)
 770{
 771        struct cfg802154_registered_device *rdev = info->user_ptr[0];
 772        struct wpan_dev *wpan_dev = info->user_ptr[1];
 773
 774        if (!rdev->ops->del_virtual_intf)
 775                return -EOPNOTSUPP;
 776
 777        /* If we remove a wpan device without a netdev then clear
 778         * user_ptr[1] so that nl802154_post_doit won't dereference it
 779         * to check if it needs to do dev_put(). Otherwise it crashes
 780         * since the wpan_dev has been freed, unlike with a netdev where
 781         * we need the dev_put() for the netdev to really be freed.
 782         */
 783        if (!wpan_dev->netdev)
 784                info->user_ptr[1] = NULL;
 785
 786        return rdev_del_virtual_intf(rdev, wpan_dev);
 787}
 788
 789static int nl802154_set_channel(struct sk_buff *skb, struct genl_info *info)
 790{
 791        struct cfg802154_registered_device *rdev = info->user_ptr[0];
 792        u8 channel, page;
 793
 794        if (!info->attrs[NL802154_ATTR_PAGE] ||
 795            !info->attrs[NL802154_ATTR_CHANNEL])
 796                return -EINVAL;
 797
 798        page = nla_get_u8(info->attrs[NL802154_ATTR_PAGE]);
 799        channel = nla_get_u8(info->attrs[NL802154_ATTR_CHANNEL]);
 800
 801        /* check 802.15.4 constraints */
 802        if (page > IEEE802154_MAX_PAGE || channel > IEEE802154_MAX_CHANNEL ||
 803            !(rdev->wpan_phy.supported.channels[page] & BIT(channel)))
 804                return -EINVAL;
 805
 806        return rdev_set_channel(rdev, page, channel);
 807}
 808
 809static int nl802154_set_cca_mode(struct sk_buff *skb, struct genl_info *info)
 810{
 811        struct cfg802154_registered_device *rdev = info->user_ptr[0];
 812        struct wpan_phy_cca cca;
 813
 814        if (!(rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_MODE))
 815                return -EOPNOTSUPP;
 816
 817        if (!info->attrs[NL802154_ATTR_CCA_MODE])
 818                return -EINVAL;
 819
 820        cca.mode = nla_get_u32(info->attrs[NL802154_ATTR_CCA_MODE]);
 821        /* checking 802.15.4 constraints */
 822        if (cca.mode < NL802154_CCA_ENERGY ||
 823            cca.mode > NL802154_CCA_ATTR_MAX ||
 824            !(rdev->wpan_phy.supported.cca_modes & BIT(cca.mode)))
 825                return -EINVAL;
 826
 827        if (cca.mode == NL802154_CCA_ENERGY_CARRIER) {
 828                if (!info->attrs[NL802154_ATTR_CCA_OPT])
 829                        return -EINVAL;
 830
 831                cca.opt = nla_get_u32(info->attrs[NL802154_ATTR_CCA_OPT]);
 832                if (cca.opt > NL802154_CCA_OPT_ATTR_MAX ||
 833                    !(rdev->wpan_phy.supported.cca_opts & BIT(cca.opt)))
 834                        return -EINVAL;
 835        }
 836
 837        return rdev_set_cca_mode(rdev, &cca);
 838}
 839
 840static int nl802154_set_cca_ed_level(struct sk_buff *skb, struct genl_info *info)
 841{
 842        struct cfg802154_registered_device *rdev = info->user_ptr[0];
 843        s32 ed_level;
 844        int i;
 845
 846        if (!(rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_ED_LEVEL))
 847                return -EOPNOTSUPP;
 848
 849        if (!info->attrs[NL802154_ATTR_CCA_ED_LEVEL])
 850                return -EINVAL;
 851
 852        ed_level = nla_get_s32(info->attrs[NL802154_ATTR_CCA_ED_LEVEL]);
 853
 854        for (i = 0; i < rdev->wpan_phy.supported.cca_ed_levels_size; i++) {
 855                if (ed_level == rdev->wpan_phy.supported.cca_ed_levels[i])
 856                        return rdev_set_cca_ed_level(rdev, ed_level);
 857        }
 858
 859        return -EINVAL;
 860}
 861
 862static int nl802154_set_tx_power(struct sk_buff *skb, struct genl_info *info)
 863{
 864        struct cfg802154_registered_device *rdev = info->user_ptr[0];
 865        s32 power;
 866        int i;
 867
 868        if (!(rdev->wpan_phy.flags & WPAN_PHY_FLAG_TXPOWER))
 869                return -EOPNOTSUPP;
 870
 871        if (!info->attrs[NL802154_ATTR_TX_POWER])
 872                return -EINVAL;
 873
 874        power = nla_get_s32(info->attrs[NL802154_ATTR_TX_POWER]);
 875
 876        for (i = 0; i < rdev->wpan_phy.supported.tx_powers_size; i++) {
 877                if (power == rdev->wpan_phy.supported.tx_powers[i])
 878                        return rdev_set_tx_power(rdev, power);
 879        }
 880
 881        return -EINVAL;
 882}
 883
 884static int nl802154_set_pan_id(struct sk_buff *skb, struct genl_info *info)
 885{
 886        struct cfg802154_registered_device *rdev = info->user_ptr[0];
 887        struct net_device *dev = info->user_ptr[1];
 888        struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
 889        __le16 pan_id;
 890
 891        /* conflict here while tx/rx calls */
 892        if (netif_running(dev))
 893                return -EBUSY;
 894
 895        /* don't change address fields on monitor */
 896        if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR ||
 897            !info->attrs[NL802154_ATTR_PAN_ID])
 898                return -EINVAL;
 899
 900        pan_id = nla_get_le16(info->attrs[NL802154_ATTR_PAN_ID]);
 901
 902        /* TODO
 903         * I am not sure about to check here on broadcast pan_id.
 904         * Broadcast is a valid setting, comment from 802.15.4:
 905         * If this value is 0xffff, the device is not associated.
 906         *
 907         * This could useful to simple deassociate an device.
 908         */
 909        if (pan_id == cpu_to_le16(IEEE802154_PAN_ID_BROADCAST))
 910                return -EINVAL;
 911
 912        return rdev_set_pan_id(rdev, wpan_dev, pan_id);
 913}
 914
 915static int nl802154_set_short_addr(struct sk_buff *skb, struct genl_info *info)
 916{
 917        struct cfg802154_registered_device *rdev = info->user_ptr[0];
 918        struct net_device *dev = info->user_ptr[1];
 919        struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
 920        __le16 short_addr;
 921
 922        /* conflict here while tx/rx calls */
 923        if (netif_running(dev))
 924                return -EBUSY;
 925
 926        /* don't change address fields on monitor */
 927        if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR ||
 928            !info->attrs[NL802154_ATTR_SHORT_ADDR])
 929                return -EINVAL;
 930
 931        short_addr = nla_get_le16(info->attrs[NL802154_ATTR_SHORT_ADDR]);
 932
 933        /* TODO
 934         * I am not sure about to check here on broadcast short_addr.
 935         * Broadcast is a valid setting, comment from 802.15.4:
 936         * A value of 0xfffe indicates that the device has
 937         * associated but has not been allocated an address. A
 938         * value of 0xffff indicates that the device does not
 939         * have a short address.
 940         *
 941         * I think we should allow to set these settings but
 942         * don't allow to allow socket communication with it.
 943         */
 944        if (short_addr == cpu_to_le16(IEEE802154_ADDR_SHORT_UNSPEC) ||
 945            short_addr == cpu_to_le16(IEEE802154_ADDR_SHORT_BROADCAST))
 946                return -EINVAL;
 947
 948        return rdev_set_short_addr(rdev, wpan_dev, short_addr);
 949}
 950
 951static int
 952nl802154_set_backoff_exponent(struct sk_buff *skb, struct genl_info *info)
 953{
 954        struct cfg802154_registered_device *rdev = info->user_ptr[0];
 955        struct net_device *dev = info->user_ptr[1];
 956        struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
 957        u8 min_be, max_be;
 958
 959        /* should be set on netif open inside phy settings */
 960        if (netif_running(dev))
 961                return -EBUSY;
 962
 963        if (!info->attrs[NL802154_ATTR_MIN_BE] ||
 964            !info->attrs[NL802154_ATTR_MAX_BE])
 965                return -EINVAL;
 966
 967        min_be = nla_get_u8(info->attrs[NL802154_ATTR_MIN_BE]);
 968        max_be = nla_get_u8(info->attrs[NL802154_ATTR_MAX_BE]);
 969
 970        /* check 802.15.4 constraints */
 971        if (min_be < rdev->wpan_phy.supported.min_minbe ||
 972            min_be > rdev->wpan_phy.supported.max_minbe ||
 973            max_be < rdev->wpan_phy.supported.min_maxbe ||
 974            max_be > rdev->wpan_phy.supported.max_maxbe ||
 975            min_be > max_be)
 976                return -EINVAL;
 977
 978        return rdev_set_backoff_exponent(rdev, wpan_dev, min_be, max_be);
 979}
 980
 981static int
 982nl802154_set_max_csma_backoffs(struct sk_buff *skb, struct genl_info *info)
 983{
 984        struct cfg802154_registered_device *rdev = info->user_ptr[0];
 985        struct net_device *dev = info->user_ptr[1];
 986        struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
 987        u8 max_csma_backoffs;
 988
 989        /* conflict here while other running iface settings */
 990        if (netif_running(dev))
 991                return -EBUSY;
 992
 993        if (!info->attrs[NL802154_ATTR_MAX_CSMA_BACKOFFS])
 994                return -EINVAL;
 995
 996        max_csma_backoffs = nla_get_u8(
 997                        info->attrs[NL802154_ATTR_MAX_CSMA_BACKOFFS]);
 998
 999        /* check 802.15.4 constraints */
1000        if (max_csma_backoffs < rdev->wpan_phy.supported.min_csma_backoffs ||
1001            max_csma_backoffs > rdev->wpan_phy.supported.max_csma_backoffs)
1002                return -EINVAL;
1003
1004        return rdev_set_max_csma_backoffs(rdev, wpan_dev, max_csma_backoffs);
1005}
1006
1007static int
1008nl802154_set_max_frame_retries(struct sk_buff *skb, struct genl_info *info)
1009{
1010        struct cfg802154_registered_device *rdev = info->user_ptr[0];
1011        struct net_device *dev = info->user_ptr[1];
1012        struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
1013        s8 max_frame_retries;
1014
1015        if (netif_running(dev))
1016                return -EBUSY;
1017
1018        if (!info->attrs[NL802154_ATTR_MAX_FRAME_RETRIES])
1019                return -EINVAL;
1020
1021        max_frame_retries = nla_get_s8(
1022                        info->attrs[NL802154_ATTR_MAX_FRAME_RETRIES]);
1023
1024        /* check 802.15.4 constraints */
1025        if (max_frame_retries < rdev->wpan_phy.supported.min_frame_retries ||
1026            max_frame_retries > rdev->wpan_phy.supported.max_frame_retries)
1027                return -EINVAL;
1028
1029        return rdev_set_max_frame_retries(rdev, wpan_dev, max_frame_retries);
1030}
1031
1032static int nl802154_set_lbt_mode(struct sk_buff *skb, struct genl_info *info)
1033{
1034        struct cfg802154_registered_device *rdev = info->user_ptr[0];
1035        struct net_device *dev = info->user_ptr[1];
1036        struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
1037        int mode;
1038
1039        if (netif_running(dev))
1040                return -EBUSY;
1041
1042        if (!info->attrs[NL802154_ATTR_LBT_MODE])
1043                return -EINVAL;
1044
1045        mode = nla_get_u8(info->attrs[NL802154_ATTR_LBT_MODE]);
1046
1047        if (mode != 0 && mode != 1)
1048                return -EINVAL;
1049
1050        if (!wpan_phy_supported_bool(mode, rdev->wpan_phy.supported.lbt))
1051                return -EINVAL;
1052
1053        return rdev_set_lbt_mode(rdev, wpan_dev, mode);
1054}
1055
1056static int
1057nl802154_set_ackreq_default(struct sk_buff *skb, struct genl_info *info)
1058{
1059        struct cfg802154_registered_device *rdev = info->user_ptr[0];
1060        struct net_device *dev = info->user_ptr[1];
1061        struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
1062        int ackreq;
1063
1064        if (netif_running(dev))
1065                return -EBUSY;
1066
1067        if (!info->attrs[NL802154_ATTR_ACKREQ_DEFAULT])
1068                return -EINVAL;
1069
1070        ackreq = nla_get_u8(info->attrs[NL802154_ATTR_ACKREQ_DEFAULT]);
1071
1072        if (ackreq != 0 && ackreq != 1)
1073                return -EINVAL;
1074
1075        return rdev_set_ackreq_default(rdev, wpan_dev, ackreq);
1076}
1077
1078#define NL802154_FLAG_NEED_WPAN_PHY     0x01
1079#define NL802154_FLAG_NEED_NETDEV       0x02
1080#define NL802154_FLAG_NEED_RTNL         0x04
1081#define NL802154_FLAG_CHECK_NETDEV_UP   0x08
1082#define NL802154_FLAG_NEED_NETDEV_UP    (NL802154_FLAG_NEED_NETDEV |\
1083                                         NL802154_FLAG_CHECK_NETDEV_UP)
1084#define NL802154_FLAG_NEED_WPAN_DEV     0x10
1085#define NL802154_FLAG_NEED_WPAN_DEV_UP  (NL802154_FLAG_NEED_WPAN_DEV |\
1086                                         NL802154_FLAG_CHECK_NETDEV_UP)
1087
1088static int nl802154_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
1089                             struct genl_info *info)
1090{
1091        struct cfg802154_registered_device *rdev;
1092        struct wpan_dev *wpan_dev;
1093        struct net_device *dev;
1094        bool rtnl = ops->internal_flags & NL802154_FLAG_NEED_RTNL;
1095
1096        if (rtnl)
1097                rtnl_lock();
1098
1099        if (ops->internal_flags & NL802154_FLAG_NEED_WPAN_PHY) {
1100                rdev = cfg802154_get_dev_from_info(genl_info_net(info), info);
1101                if (IS_ERR(rdev)) {
1102                        if (rtnl)
1103                                rtnl_unlock();
1104                        return PTR_ERR(rdev);
1105                }
1106                info->user_ptr[0] = rdev;
1107        } else if (ops->internal_flags & NL802154_FLAG_NEED_NETDEV ||
1108                   ops->internal_flags & NL802154_FLAG_NEED_WPAN_DEV) {
1109                ASSERT_RTNL();
1110                wpan_dev = __cfg802154_wpan_dev_from_attrs(genl_info_net(info),
1111                                                           info->attrs);
1112                if (IS_ERR(wpan_dev)) {
1113                        if (rtnl)
1114                                rtnl_unlock();
1115                        return PTR_ERR(wpan_dev);
1116                }
1117
1118                dev = wpan_dev->netdev;
1119                rdev = wpan_phy_to_rdev(wpan_dev->wpan_phy);
1120
1121                if (ops->internal_flags & NL802154_FLAG_NEED_NETDEV) {
1122                        if (!dev) {
1123                                if (rtnl)
1124                                        rtnl_unlock();
1125                                return -EINVAL;
1126                        }
1127
1128                        info->user_ptr[1] = dev;
1129                } else {
1130                        info->user_ptr[1] = wpan_dev;
1131                }
1132
1133                if (dev) {
1134                        if (ops->internal_flags & NL802154_FLAG_CHECK_NETDEV_UP &&
1135                            !netif_running(dev)) {
1136                                if (rtnl)
1137                                        rtnl_unlock();
1138                                return -ENETDOWN;
1139                        }
1140
1141                        dev_hold(dev);
1142                }
1143
1144                info->user_ptr[0] = rdev;
1145        }
1146
1147        return 0;
1148}
1149
1150static void nl802154_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
1151                               struct genl_info *info)
1152{
1153        if (info->user_ptr[1]) {
1154                if (ops->internal_flags & NL802154_FLAG_NEED_WPAN_DEV) {
1155                        struct wpan_dev *wpan_dev = info->user_ptr[1];
1156
1157                        if (wpan_dev->netdev)
1158                                dev_put(wpan_dev->netdev);
1159                } else {
1160                        dev_put(info->user_ptr[1]);
1161                }
1162        }
1163
1164        if (ops->internal_flags & NL802154_FLAG_NEED_RTNL)
1165                rtnl_unlock();
1166}
1167
1168static const struct genl_ops nl802154_ops[] = {
1169        {
1170                .cmd = NL802154_CMD_GET_WPAN_PHY,
1171                .doit = nl802154_get_wpan_phy,
1172                .dumpit = nl802154_dump_wpan_phy,
1173                .done = nl802154_dump_wpan_phy_done,
1174                .policy = nl802154_policy,
1175                /* can be retrieved by unprivileged users */
1176                .internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
1177                                  NL802154_FLAG_NEED_RTNL,
1178        },
1179        {
1180                .cmd = NL802154_CMD_GET_INTERFACE,
1181                .doit = nl802154_get_interface,
1182                .dumpit = nl802154_dump_interface,
1183                .policy = nl802154_policy,
1184                /* can be retrieved by unprivileged users */
1185                .internal_flags = NL802154_FLAG_NEED_WPAN_DEV |
1186                                  NL802154_FLAG_NEED_RTNL,
1187        },
1188        {
1189                .cmd = NL802154_CMD_NEW_INTERFACE,
1190                .doit = nl802154_new_interface,
1191                .policy = nl802154_policy,
1192                .flags = GENL_ADMIN_PERM,
1193                .internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
1194                                  NL802154_FLAG_NEED_RTNL,
1195        },
1196        {
1197                .cmd = NL802154_CMD_DEL_INTERFACE,
1198                .doit = nl802154_del_interface,
1199                .policy = nl802154_policy,
1200                .flags = GENL_ADMIN_PERM,
1201                .internal_flags = NL802154_FLAG_NEED_WPAN_DEV |
1202                                  NL802154_FLAG_NEED_RTNL,
1203        },
1204        {
1205                .cmd = NL802154_CMD_SET_CHANNEL,
1206                .doit = nl802154_set_channel,
1207                .policy = nl802154_policy,
1208                .flags = GENL_ADMIN_PERM,
1209                .internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
1210                                  NL802154_FLAG_NEED_RTNL,
1211        },
1212        {
1213                .cmd = NL802154_CMD_SET_CCA_MODE,
1214                .doit = nl802154_set_cca_mode,
1215                .policy = nl802154_policy,
1216                .flags = GENL_ADMIN_PERM,
1217                .internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
1218                                  NL802154_FLAG_NEED_RTNL,
1219        },
1220        {
1221                .cmd = NL802154_CMD_SET_CCA_ED_LEVEL,
1222                .doit = nl802154_set_cca_ed_level,
1223                .policy = nl802154_policy,
1224                .flags = GENL_ADMIN_PERM,
1225                .internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
1226                                  NL802154_FLAG_NEED_RTNL,
1227        },
1228        {
1229                .cmd = NL802154_CMD_SET_TX_POWER,
1230                .doit = nl802154_set_tx_power,
1231                .policy = nl802154_policy,
1232                .flags = GENL_ADMIN_PERM,
1233                .internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
1234                                  NL802154_FLAG_NEED_RTNL,
1235        },
1236        {
1237                .cmd = NL802154_CMD_SET_PAN_ID,
1238                .doit = nl802154_set_pan_id,
1239                .policy = nl802154_policy,
1240                .flags = GENL_ADMIN_PERM,
1241                .internal_flags = NL802154_FLAG_NEED_NETDEV |
1242                                  NL802154_FLAG_NEED_RTNL,
1243        },
1244        {
1245                .cmd = NL802154_CMD_SET_SHORT_ADDR,
1246                .doit = nl802154_set_short_addr,
1247                .policy = nl802154_policy,
1248                .flags = GENL_ADMIN_PERM,
1249                .internal_flags = NL802154_FLAG_NEED_NETDEV |
1250                                  NL802154_FLAG_NEED_RTNL,
1251        },
1252        {
1253                .cmd = NL802154_CMD_SET_BACKOFF_EXPONENT,
1254                .doit = nl802154_set_backoff_exponent,
1255                .policy = nl802154_policy,
1256                .flags = GENL_ADMIN_PERM,
1257                .internal_flags = NL802154_FLAG_NEED_NETDEV |
1258                                  NL802154_FLAG_NEED_RTNL,
1259        },
1260        {
1261                .cmd = NL802154_CMD_SET_MAX_CSMA_BACKOFFS,
1262                .doit = nl802154_set_max_csma_backoffs,
1263                .policy = nl802154_policy,
1264                .flags = GENL_ADMIN_PERM,
1265                .internal_flags = NL802154_FLAG_NEED_NETDEV |
1266                                  NL802154_FLAG_NEED_RTNL,
1267        },
1268        {
1269                .cmd = NL802154_CMD_SET_MAX_FRAME_RETRIES,
1270                .doit = nl802154_set_max_frame_retries,
1271                .policy = nl802154_policy,
1272                .flags = GENL_ADMIN_PERM,
1273                .internal_flags = NL802154_FLAG_NEED_NETDEV |
1274                                  NL802154_FLAG_NEED_RTNL,
1275        },
1276        {
1277                .cmd = NL802154_CMD_SET_LBT_MODE,
1278                .doit = nl802154_set_lbt_mode,
1279                .policy = nl802154_policy,
1280                .flags = GENL_ADMIN_PERM,
1281                .internal_flags = NL802154_FLAG_NEED_NETDEV |
1282                                  NL802154_FLAG_NEED_RTNL,
1283        },
1284        {
1285                .cmd = NL802154_CMD_SET_ACKREQ_DEFAULT,
1286                .doit = nl802154_set_ackreq_default,
1287                .policy = nl802154_policy,
1288                .flags = GENL_ADMIN_PERM,
1289                .internal_flags = NL802154_FLAG_NEED_NETDEV |
1290                                  NL802154_FLAG_NEED_RTNL,
1291        },
1292};
1293
1294/* initialisation/exit functions */
1295int nl802154_init(void)
1296{
1297        return genl_register_family_with_ops_groups(&nl802154_fam, nl802154_ops,
1298                                                    nl802154_mcgrps);
1299}
1300
1301void nl802154_exit(void)
1302{
1303        genl_unregister_family(&nl802154_fam);
1304}
1305