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#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
 237        [NL802154_ATTR_SEC_ENABLED] = { .type = NLA_U8, },
 238        [NL802154_ATTR_SEC_OUT_LEVEL] = { .type = NLA_U32, },
 239        [NL802154_ATTR_SEC_OUT_KEY_ID] = { .type = NLA_NESTED, },
 240        [NL802154_ATTR_SEC_FRAME_COUNTER] = { .type = NLA_U32 },
 241
 242        [NL802154_ATTR_SEC_LEVEL] = { .type = NLA_NESTED },
 243        [NL802154_ATTR_SEC_DEVICE] = { .type = NLA_NESTED },
 244        [NL802154_ATTR_SEC_DEVKEY] = { .type = NLA_NESTED },
 245        [NL802154_ATTR_SEC_KEY] = { .type = NLA_NESTED },
 246#endif /* CONFIG_IEEE802154_NL802154_EXPERIMENTAL */
 247};
 248
 249#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
 250static int
 251nl802154_prepare_wpan_dev_dump(struct sk_buff *skb,
 252                               struct netlink_callback *cb,
 253                               struct cfg802154_registered_device **rdev,
 254                               struct wpan_dev **wpan_dev)
 255{
 256        int err;
 257
 258        rtnl_lock();
 259
 260        if (!cb->args[0]) {
 261                err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl802154_fam.hdrsize,
 262                                  nl802154_fam.attrbuf, nl802154_fam.maxattr,
 263                                  nl802154_policy);
 264                if (err)
 265                        goto out_unlock;
 266
 267                *wpan_dev = __cfg802154_wpan_dev_from_attrs(sock_net(skb->sk),
 268                                                            nl802154_fam.attrbuf);
 269                if (IS_ERR(*wpan_dev)) {
 270                        err = PTR_ERR(*wpan_dev);
 271                        goto out_unlock;
 272                }
 273                *rdev = wpan_phy_to_rdev((*wpan_dev)->wpan_phy);
 274                /* 0 is the first index - add 1 to parse only once */
 275                cb->args[0] = (*rdev)->wpan_phy_idx + 1;
 276                cb->args[1] = (*wpan_dev)->identifier;
 277        } else {
 278                /* subtract the 1 again here */
 279                struct wpan_phy *wpan_phy = wpan_phy_idx_to_wpan_phy(cb->args[0] - 1);
 280                struct wpan_dev *tmp;
 281
 282                if (!wpan_phy) {
 283                        err = -ENODEV;
 284                        goto out_unlock;
 285                }
 286                *rdev = wpan_phy_to_rdev(wpan_phy);
 287                *wpan_dev = NULL;
 288
 289                list_for_each_entry(tmp, &(*rdev)->wpan_dev_list, list) {
 290                        if (tmp->identifier == cb->args[1]) {
 291                                *wpan_dev = tmp;
 292                                break;
 293                        }
 294                }
 295
 296                if (!*wpan_dev) {
 297                        err = -ENODEV;
 298                        goto out_unlock;
 299                }
 300        }
 301
 302        return 0;
 303 out_unlock:
 304        rtnl_unlock();
 305        return err;
 306}
 307
 308static void
 309nl802154_finish_wpan_dev_dump(struct cfg802154_registered_device *rdev)
 310{
 311        rtnl_unlock();
 312}
 313#endif /* CONFIG_IEEE802154_NL802154_EXPERIMENTAL */
 314
 315/* message building helper */
 316static inline void *nl802154hdr_put(struct sk_buff *skb, u32 portid, u32 seq,
 317                                    int flags, u8 cmd)
 318{
 319        /* since there is no private header just add the generic one */
 320        return genlmsg_put(skb, portid, seq, &nl802154_fam, flags, cmd);
 321}
 322
 323static int
 324nl802154_put_flags(struct sk_buff *msg, int attr, u32 mask)
 325{
 326        struct nlattr *nl_flags = nla_nest_start(msg, attr);
 327        int i;
 328
 329        if (!nl_flags)
 330                return -ENOBUFS;
 331
 332        i = 0;
 333        while (mask) {
 334                if ((mask & 1) && nla_put_flag(msg, i))
 335                        return -ENOBUFS;
 336
 337                mask >>= 1;
 338                i++;
 339        }
 340
 341        nla_nest_end(msg, nl_flags);
 342        return 0;
 343}
 344
 345static int
 346nl802154_send_wpan_phy_channels(struct cfg802154_registered_device *rdev,
 347                                struct sk_buff *msg)
 348{
 349        struct nlattr *nl_page;
 350        unsigned long page;
 351
 352        nl_page = nla_nest_start(msg, NL802154_ATTR_CHANNELS_SUPPORTED);
 353        if (!nl_page)
 354                return -ENOBUFS;
 355
 356        for (page = 0; page <= IEEE802154_MAX_PAGE; page++) {
 357                if (nla_put_u32(msg, NL802154_ATTR_SUPPORTED_CHANNEL,
 358                                rdev->wpan_phy.supported.channels[page]))
 359                        return -ENOBUFS;
 360        }
 361        nla_nest_end(msg, nl_page);
 362
 363        return 0;
 364}
 365
 366static int
 367nl802154_put_capabilities(struct sk_buff *msg,
 368                          struct cfg802154_registered_device *rdev)
 369{
 370        const struct wpan_phy_supported *caps = &rdev->wpan_phy.supported;
 371        struct nlattr *nl_caps, *nl_channels;
 372        int i;
 373
 374        nl_caps = nla_nest_start(msg, NL802154_ATTR_WPAN_PHY_CAPS);
 375        if (!nl_caps)
 376                return -ENOBUFS;
 377
 378        nl_channels = nla_nest_start(msg, NL802154_CAP_ATTR_CHANNELS);
 379        if (!nl_channels)
 380                return -ENOBUFS;
 381
 382        for (i = 0; i <= IEEE802154_MAX_PAGE; i++) {
 383                if (caps->channels[i]) {
 384                        if (nl802154_put_flags(msg, i, caps->channels[i]))
 385                                return -ENOBUFS;
 386                }
 387        }
 388
 389        nla_nest_end(msg, nl_channels);
 390
 391        if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_ED_LEVEL) {
 392                struct nlattr *nl_ed_lvls;
 393
 394                nl_ed_lvls = nla_nest_start(msg,
 395                                            NL802154_CAP_ATTR_CCA_ED_LEVELS);
 396                if (!nl_ed_lvls)
 397                        return -ENOBUFS;
 398
 399                for (i = 0; i < caps->cca_ed_levels_size; i++) {
 400                        if (nla_put_s32(msg, i, caps->cca_ed_levels[i]))
 401                                return -ENOBUFS;
 402                }
 403
 404                nla_nest_end(msg, nl_ed_lvls);
 405        }
 406
 407        if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_TXPOWER) {
 408                struct nlattr *nl_tx_pwrs;
 409
 410                nl_tx_pwrs = nla_nest_start(msg, NL802154_CAP_ATTR_TX_POWERS);
 411                if (!nl_tx_pwrs)
 412                        return -ENOBUFS;
 413
 414                for (i = 0; i < caps->tx_powers_size; i++) {
 415                        if (nla_put_s32(msg, i, caps->tx_powers[i]))
 416                                return -ENOBUFS;
 417                }
 418
 419                nla_nest_end(msg, nl_tx_pwrs);
 420        }
 421
 422        if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_MODE) {
 423                if (nl802154_put_flags(msg, NL802154_CAP_ATTR_CCA_MODES,
 424                                       caps->cca_modes) ||
 425                    nl802154_put_flags(msg, NL802154_CAP_ATTR_CCA_OPTS,
 426                                       caps->cca_opts))
 427                        return -ENOBUFS;
 428        }
 429
 430        if (nla_put_u8(msg, NL802154_CAP_ATTR_MIN_MINBE, caps->min_minbe) ||
 431            nla_put_u8(msg, NL802154_CAP_ATTR_MAX_MINBE, caps->max_minbe) ||
 432            nla_put_u8(msg, NL802154_CAP_ATTR_MIN_MAXBE, caps->min_maxbe) ||
 433            nla_put_u8(msg, NL802154_CAP_ATTR_MAX_MAXBE, caps->max_maxbe) ||
 434            nla_put_u8(msg, NL802154_CAP_ATTR_MIN_CSMA_BACKOFFS,
 435                       caps->min_csma_backoffs) ||
 436            nla_put_u8(msg, NL802154_CAP_ATTR_MAX_CSMA_BACKOFFS,
 437                       caps->max_csma_backoffs) ||
 438            nla_put_s8(msg, NL802154_CAP_ATTR_MIN_FRAME_RETRIES,
 439                       caps->min_frame_retries) ||
 440            nla_put_s8(msg, NL802154_CAP_ATTR_MAX_FRAME_RETRIES,
 441                       caps->max_frame_retries) ||
 442            nl802154_put_flags(msg, NL802154_CAP_ATTR_IFTYPES,
 443                               caps->iftypes) ||
 444            nla_put_u32(msg, NL802154_CAP_ATTR_LBT, caps->lbt))
 445                return -ENOBUFS;
 446
 447        nla_nest_end(msg, nl_caps);
 448
 449        return 0;
 450}
 451
 452static int nl802154_send_wpan_phy(struct cfg802154_registered_device *rdev,
 453                                  enum nl802154_commands cmd,
 454                                  struct sk_buff *msg, u32 portid, u32 seq,
 455                                  int flags)
 456{
 457        struct nlattr *nl_cmds;
 458        void *hdr;
 459        int i;
 460
 461        hdr = nl802154hdr_put(msg, portid, seq, flags, cmd);
 462        if (!hdr)
 463                return -ENOBUFS;
 464
 465        if (nla_put_u32(msg, NL802154_ATTR_WPAN_PHY, rdev->wpan_phy_idx) ||
 466            nla_put_string(msg, NL802154_ATTR_WPAN_PHY_NAME,
 467                           wpan_phy_name(&rdev->wpan_phy)) ||
 468            nla_put_u32(msg, NL802154_ATTR_GENERATION,
 469                        cfg802154_rdev_list_generation))
 470                goto nla_put_failure;
 471
 472        if (cmd != NL802154_CMD_NEW_WPAN_PHY)
 473                goto finish;
 474
 475        /* DUMP PHY PIB */
 476
 477        /* current channel settings */
 478        if (nla_put_u8(msg, NL802154_ATTR_PAGE,
 479                       rdev->wpan_phy.current_page) ||
 480            nla_put_u8(msg, NL802154_ATTR_CHANNEL,
 481                       rdev->wpan_phy.current_channel))
 482                goto nla_put_failure;
 483
 484        /* TODO remove this behaviour, we still keep support it for a while
 485         * so users can change the behaviour to the new one.
 486         */
 487        if (nl802154_send_wpan_phy_channels(rdev, msg))
 488                goto nla_put_failure;
 489
 490        /* cca mode */
 491        if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_MODE) {
 492                if (nla_put_u32(msg, NL802154_ATTR_CCA_MODE,
 493                                rdev->wpan_phy.cca.mode))
 494                        goto nla_put_failure;
 495
 496                if (rdev->wpan_phy.cca.mode == NL802154_CCA_ENERGY_CARRIER) {
 497                        if (nla_put_u32(msg, NL802154_ATTR_CCA_OPT,
 498                                        rdev->wpan_phy.cca.opt))
 499                                goto nla_put_failure;
 500                }
 501        }
 502
 503        if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_TXPOWER) {
 504                if (nla_put_s32(msg, NL802154_ATTR_TX_POWER,
 505                                rdev->wpan_phy.transmit_power))
 506                        goto nla_put_failure;
 507        }
 508
 509        if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_ED_LEVEL) {
 510                if (nla_put_s32(msg, NL802154_ATTR_CCA_ED_LEVEL,
 511                                rdev->wpan_phy.cca_ed_level))
 512                        goto nla_put_failure;
 513        }
 514
 515        if (nl802154_put_capabilities(msg, rdev))
 516                goto nla_put_failure;
 517
 518        nl_cmds = nla_nest_start(msg, NL802154_ATTR_SUPPORTED_COMMANDS);
 519        if (!nl_cmds)
 520                goto nla_put_failure;
 521
 522        i = 0;
 523#define CMD(op, n)                                                      \
 524        do {                                                            \
 525                if (rdev->ops->op) {                                    \
 526                        i++;                                            \
 527                        if (nla_put_u32(msg, i, NL802154_CMD_ ## n))    \
 528                                goto nla_put_failure;                   \
 529                }                                                       \
 530        } while (0)
 531
 532        CMD(add_virtual_intf, NEW_INTERFACE);
 533        CMD(del_virtual_intf, DEL_INTERFACE);
 534        CMD(set_channel, SET_CHANNEL);
 535        CMD(set_pan_id, SET_PAN_ID);
 536        CMD(set_short_addr, SET_SHORT_ADDR);
 537        CMD(set_backoff_exponent, SET_BACKOFF_EXPONENT);
 538        CMD(set_max_csma_backoffs, SET_MAX_CSMA_BACKOFFS);
 539        CMD(set_max_frame_retries, SET_MAX_FRAME_RETRIES);
 540        CMD(set_lbt_mode, SET_LBT_MODE);
 541        CMD(set_ackreq_default, SET_ACKREQ_DEFAULT);
 542
 543        if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_TXPOWER)
 544                CMD(set_tx_power, SET_TX_POWER);
 545
 546        if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_ED_LEVEL)
 547                CMD(set_cca_ed_level, SET_CCA_ED_LEVEL);
 548
 549        if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_MODE)
 550                CMD(set_cca_mode, SET_CCA_MODE);
 551
 552#undef CMD
 553        nla_nest_end(msg, nl_cmds);
 554
 555finish:
 556        genlmsg_end(msg, hdr);
 557        return 0;
 558
 559nla_put_failure:
 560        genlmsg_cancel(msg, hdr);
 561        return -EMSGSIZE;
 562}
 563
 564struct nl802154_dump_wpan_phy_state {
 565        s64 filter_wpan_phy;
 566        long start;
 567
 568};
 569
 570static int nl802154_dump_wpan_phy_parse(struct sk_buff *skb,
 571                                        struct netlink_callback *cb,
 572                                        struct nl802154_dump_wpan_phy_state *state)
 573{
 574        struct nlattr **tb = nl802154_fam.attrbuf;
 575        int ret = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl802154_fam.hdrsize,
 576                              tb, nl802154_fam.maxattr, nl802154_policy);
 577
 578        /* TODO check if we can handle error here,
 579         * we have no backward compatibility
 580         */
 581        if (ret)
 582                return 0;
 583
 584        if (tb[NL802154_ATTR_WPAN_PHY])
 585                state->filter_wpan_phy = nla_get_u32(tb[NL802154_ATTR_WPAN_PHY]);
 586        if (tb[NL802154_ATTR_WPAN_DEV])
 587                state->filter_wpan_phy = nla_get_u64(tb[NL802154_ATTR_WPAN_DEV]) >> 32;
 588        if (tb[NL802154_ATTR_IFINDEX]) {
 589                struct net_device *netdev;
 590                struct cfg802154_registered_device *rdev;
 591                int ifidx = nla_get_u32(tb[NL802154_ATTR_IFINDEX]);
 592
 593                /* TODO netns */
 594                netdev = __dev_get_by_index(&init_net, ifidx);
 595                if (!netdev)
 596                        return -ENODEV;
 597                if (netdev->ieee802154_ptr) {
 598                        rdev = wpan_phy_to_rdev(
 599                                        netdev->ieee802154_ptr->wpan_phy);
 600                        state->filter_wpan_phy = rdev->wpan_phy_idx;
 601                }
 602        }
 603
 604        return 0;
 605}
 606
 607static int
 608nl802154_dump_wpan_phy(struct sk_buff *skb, struct netlink_callback *cb)
 609{
 610        int idx = 0, ret;
 611        struct nl802154_dump_wpan_phy_state *state = (void *)cb->args[0];
 612        struct cfg802154_registered_device *rdev;
 613
 614        rtnl_lock();
 615        if (!state) {
 616                state = kzalloc(sizeof(*state), GFP_KERNEL);
 617                if (!state) {
 618                        rtnl_unlock();
 619                        return -ENOMEM;
 620                }
 621                state->filter_wpan_phy = -1;
 622                ret = nl802154_dump_wpan_phy_parse(skb, cb, state);
 623                if (ret) {
 624                        kfree(state);
 625                        rtnl_unlock();
 626                        return ret;
 627                }
 628                cb->args[0] = (long)state;
 629        }
 630
 631        list_for_each_entry(rdev, &cfg802154_rdev_list, list) {
 632                /* TODO net ns compare */
 633                if (++idx <= state->start)
 634                        continue;
 635                if (state->filter_wpan_phy != -1 &&
 636                    state->filter_wpan_phy != rdev->wpan_phy_idx)
 637                        continue;
 638                /* attempt to fit multiple wpan_phy data chunks into the skb */
 639                ret = nl802154_send_wpan_phy(rdev,
 640                                             NL802154_CMD_NEW_WPAN_PHY,
 641                                             skb,
 642                                             NETLINK_CB(cb->skb).portid,
 643                                             cb->nlh->nlmsg_seq, NLM_F_MULTI);
 644                if (ret < 0) {
 645                        if ((ret == -ENOBUFS || ret == -EMSGSIZE) &&
 646                            !skb->len && cb->min_dump_alloc < 4096) {
 647                                cb->min_dump_alloc = 4096;
 648                                rtnl_unlock();
 649                                return 1;
 650                        }
 651                        idx--;
 652                        break;
 653                }
 654                break;
 655        }
 656        rtnl_unlock();
 657
 658        state->start = idx;
 659
 660        return skb->len;
 661}
 662
 663static int nl802154_dump_wpan_phy_done(struct netlink_callback *cb)
 664{
 665        kfree((void *)cb->args[0]);
 666        return 0;
 667}
 668
 669static int nl802154_get_wpan_phy(struct sk_buff *skb, struct genl_info *info)
 670{
 671        struct sk_buff *msg;
 672        struct cfg802154_registered_device *rdev = info->user_ptr[0];
 673
 674        msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
 675        if (!msg)
 676                return -ENOMEM;
 677
 678        if (nl802154_send_wpan_phy(rdev, NL802154_CMD_NEW_WPAN_PHY, msg,
 679                                   info->snd_portid, info->snd_seq, 0) < 0) {
 680                nlmsg_free(msg);
 681                return -ENOBUFS;
 682        }
 683
 684        return genlmsg_reply(msg, info);
 685}
 686
 687static inline u64 wpan_dev_id(struct wpan_dev *wpan_dev)
 688{
 689        return (u64)wpan_dev->identifier |
 690               ((u64)wpan_phy_to_rdev(wpan_dev->wpan_phy)->wpan_phy_idx << 32);
 691}
 692
 693#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
 694#include <net/ieee802154_netdev.h>
 695
 696static int
 697ieee802154_llsec_send_key_id(struct sk_buff *msg,
 698                             const struct ieee802154_llsec_key_id *desc)
 699{
 700        struct nlattr *nl_dev_addr;
 701
 702        if (nla_put_u32(msg, NL802154_KEY_ID_ATTR_MODE, desc->mode))
 703                return -ENOBUFS;
 704
 705        switch (desc->mode) {
 706        case NL802154_KEY_ID_MODE_IMPLICIT:
 707                nl_dev_addr = nla_nest_start(msg, NL802154_KEY_ID_ATTR_IMPLICIT);
 708                if (!nl_dev_addr)
 709                        return -ENOBUFS;
 710
 711                if (nla_put_le16(msg, NL802154_DEV_ADDR_ATTR_PAN_ID,
 712                                 desc->device_addr.pan_id) ||
 713                    nla_put_u32(msg,  NL802154_DEV_ADDR_ATTR_MODE,
 714                                desc->device_addr.mode))
 715                        return -ENOBUFS;
 716
 717                switch (desc->device_addr.mode) {
 718                case NL802154_DEV_ADDR_SHORT:
 719                        if (nla_put_le16(msg, NL802154_DEV_ADDR_ATTR_SHORT,
 720                                         desc->device_addr.short_addr))
 721                                return -ENOBUFS;
 722                        break;
 723                case NL802154_DEV_ADDR_EXTENDED:
 724                        if (nla_put_le64(msg, NL802154_DEV_ADDR_ATTR_EXTENDED,
 725                                         desc->device_addr.extended_addr))
 726                                return -ENOBUFS;
 727                        break;
 728                default:
 729                        /* userspace should handle unknown */
 730                        break;
 731                }
 732
 733                nla_nest_end(msg, nl_dev_addr);
 734                break;
 735        case NL802154_KEY_ID_MODE_INDEX:
 736                break;
 737        case NL802154_KEY_ID_MODE_INDEX_SHORT:
 738                /* TODO renmae short_source? */
 739                if (nla_put_le32(msg, NL802154_KEY_ID_ATTR_SOURCE_SHORT,
 740                                 desc->short_source))
 741                        return -ENOBUFS;
 742                break;
 743        case NL802154_KEY_ID_MODE_INDEX_EXTENDED:
 744                if (nla_put_le64(msg, NL802154_KEY_ID_ATTR_SOURCE_EXTENDED,
 745                                 desc->extended_source))
 746                        return -ENOBUFS;
 747                break;
 748        default:
 749                /* userspace should handle unknown */
 750                break;
 751        }
 752
 753        /* TODO key_id to key_idx ? Check naming */
 754        if (desc->mode != NL802154_KEY_ID_MODE_IMPLICIT) {
 755                if (nla_put_u8(msg, NL802154_KEY_ID_ATTR_INDEX, desc->id))
 756                        return -ENOBUFS;
 757        }
 758
 759        return 0;
 760}
 761
 762static int nl802154_get_llsec_params(struct sk_buff *msg,
 763                                     struct cfg802154_registered_device *rdev,
 764                                     struct wpan_dev *wpan_dev)
 765{
 766        struct nlattr *nl_key_id;
 767        struct ieee802154_llsec_params params;
 768        int ret;
 769
 770        ret = rdev_get_llsec_params(rdev, wpan_dev, &params);
 771        if (ret < 0)
 772                return ret;
 773
 774        if (nla_put_u8(msg, NL802154_ATTR_SEC_ENABLED, params.enabled) ||
 775            nla_put_u32(msg, NL802154_ATTR_SEC_OUT_LEVEL, params.out_level) ||
 776            nla_put_be32(msg, NL802154_ATTR_SEC_FRAME_COUNTER,
 777                         params.frame_counter))
 778                return -ENOBUFS;
 779
 780        nl_key_id = nla_nest_start(msg, NL802154_ATTR_SEC_OUT_KEY_ID);
 781        if (!nl_key_id)
 782                return -ENOBUFS;
 783
 784        ret = ieee802154_llsec_send_key_id(msg, &params.out_key);
 785        if (ret < 0)
 786                return ret;
 787
 788        nla_nest_end(msg, nl_key_id);
 789
 790        return 0;
 791}
 792#endif /* CONFIG_IEEE802154_NL802154_EXPERIMENTAL */
 793
 794static int
 795nl802154_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flags,
 796                    struct cfg802154_registered_device *rdev,
 797                    struct wpan_dev *wpan_dev)
 798{
 799        struct net_device *dev = wpan_dev->netdev;
 800        void *hdr;
 801
 802        hdr = nl802154hdr_put(msg, portid, seq, flags,
 803                              NL802154_CMD_NEW_INTERFACE);
 804        if (!hdr)
 805                return -1;
 806
 807        if (dev &&
 808            (nla_put_u32(msg, NL802154_ATTR_IFINDEX, dev->ifindex) ||
 809             nla_put_string(msg, NL802154_ATTR_IFNAME, dev->name)))
 810                goto nla_put_failure;
 811
 812        if (nla_put_u32(msg, NL802154_ATTR_WPAN_PHY, rdev->wpan_phy_idx) ||
 813            nla_put_u32(msg, NL802154_ATTR_IFTYPE, wpan_dev->iftype) ||
 814            nla_put_u64(msg, NL802154_ATTR_WPAN_DEV, wpan_dev_id(wpan_dev)) ||
 815            nla_put_u32(msg, NL802154_ATTR_GENERATION,
 816                        rdev->devlist_generation ^
 817                        (cfg802154_rdev_list_generation << 2)))
 818                goto nla_put_failure;
 819
 820        /* address settings */
 821        if (nla_put_le64(msg, NL802154_ATTR_EXTENDED_ADDR,
 822                         wpan_dev->extended_addr) ||
 823            nla_put_le16(msg, NL802154_ATTR_SHORT_ADDR,
 824                         wpan_dev->short_addr) ||
 825            nla_put_le16(msg, NL802154_ATTR_PAN_ID, wpan_dev->pan_id))
 826                goto nla_put_failure;
 827
 828        /* ARET handling */
 829        if (nla_put_s8(msg, NL802154_ATTR_MAX_FRAME_RETRIES,
 830                       wpan_dev->frame_retries) ||
 831            nla_put_u8(msg, NL802154_ATTR_MAX_BE, wpan_dev->max_be) ||
 832            nla_put_u8(msg, NL802154_ATTR_MAX_CSMA_BACKOFFS,
 833                       wpan_dev->csma_retries) ||
 834            nla_put_u8(msg, NL802154_ATTR_MIN_BE, wpan_dev->min_be))
 835                goto nla_put_failure;
 836
 837        /* listen before transmit */
 838        if (nla_put_u8(msg, NL802154_ATTR_LBT_MODE, wpan_dev->lbt))
 839                goto nla_put_failure;
 840
 841        /* ackreq default behaviour */
 842        if (nla_put_u8(msg, NL802154_ATTR_ACKREQ_DEFAULT, wpan_dev->ackreq))
 843                goto nla_put_failure;
 844
 845#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
 846        if (nl802154_get_llsec_params(msg, rdev, wpan_dev) < 0)
 847                goto nla_put_failure;
 848#endif /* CONFIG_IEEE802154_NL802154_EXPERIMENTAL */
 849
 850        genlmsg_end(msg, hdr);
 851        return 0;
 852
 853nla_put_failure:
 854        genlmsg_cancel(msg, hdr);
 855        return -EMSGSIZE;
 856}
 857
 858static int
 859nl802154_dump_interface(struct sk_buff *skb, struct netlink_callback *cb)
 860{
 861        int wp_idx = 0;
 862        int if_idx = 0;
 863        int wp_start = cb->args[0];
 864        int if_start = cb->args[1];
 865        struct cfg802154_registered_device *rdev;
 866        struct wpan_dev *wpan_dev;
 867
 868        rtnl_lock();
 869        list_for_each_entry(rdev, &cfg802154_rdev_list, list) {
 870                /* TODO netns compare */
 871                if (wp_idx < wp_start) {
 872                        wp_idx++;
 873                        continue;
 874                }
 875                if_idx = 0;
 876
 877                list_for_each_entry(wpan_dev, &rdev->wpan_dev_list, list) {
 878                        if (if_idx < if_start) {
 879                                if_idx++;
 880                                continue;
 881                        }
 882                        if (nl802154_send_iface(skb, NETLINK_CB(cb->skb).portid,
 883                                                cb->nlh->nlmsg_seq, NLM_F_MULTI,
 884                                                rdev, wpan_dev) < 0) {
 885                                goto out;
 886                        }
 887                        if_idx++;
 888                }
 889
 890                wp_idx++;
 891        }
 892out:
 893        rtnl_unlock();
 894
 895        cb->args[0] = wp_idx;
 896        cb->args[1] = if_idx;
 897
 898        return skb->len;
 899}
 900
 901static int nl802154_get_interface(struct sk_buff *skb, struct genl_info *info)
 902{
 903        struct sk_buff *msg;
 904        struct cfg802154_registered_device *rdev = info->user_ptr[0];
 905        struct wpan_dev *wdev = info->user_ptr[1];
 906
 907        msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
 908        if (!msg)
 909                return -ENOMEM;
 910
 911        if (nl802154_send_iface(msg, info->snd_portid, info->snd_seq, 0,
 912                                rdev, wdev) < 0) {
 913                nlmsg_free(msg);
 914                return -ENOBUFS;
 915        }
 916
 917        return genlmsg_reply(msg, info);
 918}
 919
 920static int nl802154_new_interface(struct sk_buff *skb, struct genl_info *info)
 921{
 922        struct cfg802154_registered_device *rdev = info->user_ptr[0];
 923        enum nl802154_iftype type = NL802154_IFTYPE_UNSPEC;
 924        __le64 extended_addr = cpu_to_le64(0x0000000000000000ULL);
 925
 926        /* TODO avoid failing a new interface
 927         * creation due to pending removal?
 928         */
 929
 930        if (!info->attrs[NL802154_ATTR_IFNAME])
 931                return -EINVAL;
 932
 933        if (info->attrs[NL802154_ATTR_IFTYPE]) {
 934                type = nla_get_u32(info->attrs[NL802154_ATTR_IFTYPE]);
 935                if (type > NL802154_IFTYPE_MAX ||
 936                    !(rdev->wpan_phy.supported.iftypes & BIT(type)))
 937                        return -EINVAL;
 938        }
 939
 940        if (info->attrs[NL802154_ATTR_EXTENDED_ADDR])
 941                extended_addr = nla_get_le64(info->attrs[NL802154_ATTR_EXTENDED_ADDR]);
 942
 943        if (!rdev->ops->add_virtual_intf)
 944                return -EOPNOTSUPP;
 945
 946        return rdev_add_virtual_intf(rdev,
 947                                     nla_data(info->attrs[NL802154_ATTR_IFNAME]),
 948                                     NET_NAME_USER, type, extended_addr);
 949}
 950
 951static int nl802154_del_interface(struct sk_buff *skb, struct genl_info *info)
 952{
 953        struct cfg802154_registered_device *rdev = info->user_ptr[0];
 954        struct wpan_dev *wpan_dev = info->user_ptr[1];
 955
 956        if (!rdev->ops->del_virtual_intf)
 957                return -EOPNOTSUPP;
 958
 959        /* If we remove a wpan device without a netdev then clear
 960         * user_ptr[1] so that nl802154_post_doit won't dereference it
 961         * to check if it needs to do dev_put(). Otherwise it crashes
 962         * since the wpan_dev has been freed, unlike with a netdev where
 963         * we need the dev_put() for the netdev to really be freed.
 964         */
 965        if (!wpan_dev->netdev)
 966                info->user_ptr[1] = NULL;
 967
 968        return rdev_del_virtual_intf(rdev, wpan_dev);
 969}
 970
 971static int nl802154_set_channel(struct sk_buff *skb, struct genl_info *info)
 972{
 973        struct cfg802154_registered_device *rdev = info->user_ptr[0];
 974        u8 channel, page;
 975
 976        if (!info->attrs[NL802154_ATTR_PAGE] ||
 977            !info->attrs[NL802154_ATTR_CHANNEL])
 978                return -EINVAL;
 979
 980        page = nla_get_u8(info->attrs[NL802154_ATTR_PAGE]);
 981        channel = nla_get_u8(info->attrs[NL802154_ATTR_CHANNEL]);
 982
 983        /* check 802.15.4 constraints */
 984        if (page > IEEE802154_MAX_PAGE || channel > IEEE802154_MAX_CHANNEL ||
 985            !(rdev->wpan_phy.supported.channels[page] & BIT(channel)))
 986                return -EINVAL;
 987
 988        return rdev_set_channel(rdev, page, channel);
 989}
 990
 991static int nl802154_set_cca_mode(struct sk_buff *skb, struct genl_info *info)
 992{
 993        struct cfg802154_registered_device *rdev = info->user_ptr[0];
 994        struct wpan_phy_cca cca;
 995
 996        if (!(rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_MODE))
 997                return -EOPNOTSUPP;
 998
 999        if (!info->attrs[NL802154_ATTR_CCA_MODE])
1000                return -EINVAL;
1001
1002        cca.mode = nla_get_u32(info->attrs[NL802154_ATTR_CCA_MODE]);
1003        /* checking 802.15.4 constraints */
1004        if (cca.mode < NL802154_CCA_ENERGY ||
1005            cca.mode > NL802154_CCA_ATTR_MAX ||
1006            !(rdev->wpan_phy.supported.cca_modes & BIT(cca.mode)))
1007                return -EINVAL;
1008
1009        if (cca.mode == NL802154_CCA_ENERGY_CARRIER) {
1010                if (!info->attrs[NL802154_ATTR_CCA_OPT])
1011                        return -EINVAL;
1012
1013                cca.opt = nla_get_u32(info->attrs[NL802154_ATTR_CCA_OPT]);
1014                if (cca.opt > NL802154_CCA_OPT_ATTR_MAX ||
1015                    !(rdev->wpan_phy.supported.cca_opts & BIT(cca.opt)))
1016                        return -EINVAL;
1017        }
1018
1019        return rdev_set_cca_mode(rdev, &cca);
1020}
1021
1022static int nl802154_set_cca_ed_level(struct sk_buff *skb, struct genl_info *info)
1023{
1024        struct cfg802154_registered_device *rdev = info->user_ptr[0];
1025        s32 ed_level;
1026        int i;
1027
1028        if (!(rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_ED_LEVEL))
1029                return -EOPNOTSUPP;
1030
1031        if (!info->attrs[NL802154_ATTR_CCA_ED_LEVEL])
1032                return -EINVAL;
1033
1034        ed_level = nla_get_s32(info->attrs[NL802154_ATTR_CCA_ED_LEVEL]);
1035
1036        for (i = 0; i < rdev->wpan_phy.supported.cca_ed_levels_size; i++) {
1037                if (ed_level == rdev->wpan_phy.supported.cca_ed_levels[i])
1038                        return rdev_set_cca_ed_level(rdev, ed_level);
1039        }
1040
1041        return -EINVAL;
1042}
1043
1044static int nl802154_set_tx_power(struct sk_buff *skb, struct genl_info *info)
1045{
1046        struct cfg802154_registered_device *rdev = info->user_ptr[0];
1047        s32 power;
1048        int i;
1049
1050        if (!(rdev->wpan_phy.flags & WPAN_PHY_FLAG_TXPOWER))
1051                return -EOPNOTSUPP;
1052
1053        if (!info->attrs[NL802154_ATTR_TX_POWER])
1054                return -EINVAL;
1055
1056        power = nla_get_s32(info->attrs[NL802154_ATTR_TX_POWER]);
1057
1058        for (i = 0; i < rdev->wpan_phy.supported.tx_powers_size; i++) {
1059                if (power == rdev->wpan_phy.supported.tx_powers[i])
1060                        return rdev_set_tx_power(rdev, power);
1061        }
1062
1063        return -EINVAL;
1064}
1065
1066static int nl802154_set_pan_id(struct sk_buff *skb, struct genl_info *info)
1067{
1068        struct cfg802154_registered_device *rdev = info->user_ptr[0];
1069        struct net_device *dev = info->user_ptr[1];
1070        struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
1071        __le16 pan_id;
1072
1073        /* conflict here while tx/rx calls */
1074        if (netif_running(dev))
1075                return -EBUSY;
1076
1077        /* don't change address fields on monitor */
1078        if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR ||
1079            !info->attrs[NL802154_ATTR_PAN_ID])
1080                return -EINVAL;
1081
1082        pan_id = nla_get_le16(info->attrs[NL802154_ATTR_PAN_ID]);
1083
1084        /* TODO
1085         * I am not sure about to check here on broadcast pan_id.
1086         * Broadcast is a valid setting, comment from 802.15.4:
1087         * If this value is 0xffff, the device is not associated.
1088         *
1089         * This could useful to simple deassociate an device.
1090         */
1091        if (pan_id == cpu_to_le16(IEEE802154_PAN_ID_BROADCAST))
1092                return -EINVAL;
1093
1094        return rdev_set_pan_id(rdev, wpan_dev, pan_id);
1095}
1096
1097static int nl802154_set_short_addr(struct sk_buff *skb, struct genl_info *info)
1098{
1099        struct cfg802154_registered_device *rdev = info->user_ptr[0];
1100        struct net_device *dev = info->user_ptr[1];
1101        struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
1102        __le16 short_addr;
1103
1104        /* conflict here while tx/rx calls */
1105        if (netif_running(dev))
1106                return -EBUSY;
1107
1108        /* don't change address fields on monitor */
1109        if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR ||
1110            !info->attrs[NL802154_ATTR_SHORT_ADDR])
1111                return -EINVAL;
1112
1113        short_addr = nla_get_le16(info->attrs[NL802154_ATTR_SHORT_ADDR]);
1114
1115        /* TODO
1116         * I am not sure about to check here on broadcast short_addr.
1117         * Broadcast is a valid setting, comment from 802.15.4:
1118         * A value of 0xfffe indicates that the device has
1119         * associated but has not been allocated an address. A
1120         * value of 0xffff indicates that the device does not
1121         * have a short address.
1122         *
1123         * I think we should allow to set these settings but
1124         * don't allow to allow socket communication with it.
1125         */
1126        if (short_addr == cpu_to_le16(IEEE802154_ADDR_SHORT_UNSPEC) ||
1127            short_addr == cpu_to_le16(IEEE802154_ADDR_SHORT_BROADCAST))
1128                return -EINVAL;
1129
1130        return rdev_set_short_addr(rdev, wpan_dev, short_addr);
1131}
1132
1133static int
1134nl802154_set_backoff_exponent(struct sk_buff *skb, struct genl_info *info)
1135{
1136        struct cfg802154_registered_device *rdev = info->user_ptr[0];
1137        struct net_device *dev = info->user_ptr[1];
1138        struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
1139        u8 min_be, max_be;
1140
1141        /* should be set on netif open inside phy settings */
1142        if (netif_running(dev))
1143                return -EBUSY;
1144
1145        if (!info->attrs[NL802154_ATTR_MIN_BE] ||
1146            !info->attrs[NL802154_ATTR_MAX_BE])
1147                return -EINVAL;
1148
1149        min_be = nla_get_u8(info->attrs[NL802154_ATTR_MIN_BE]);
1150        max_be = nla_get_u8(info->attrs[NL802154_ATTR_MAX_BE]);
1151
1152        /* check 802.15.4 constraints */
1153        if (min_be < rdev->wpan_phy.supported.min_minbe ||
1154            min_be > rdev->wpan_phy.supported.max_minbe ||
1155            max_be < rdev->wpan_phy.supported.min_maxbe ||
1156            max_be > rdev->wpan_phy.supported.max_maxbe ||
1157            min_be > max_be)
1158                return -EINVAL;
1159
1160        return rdev_set_backoff_exponent(rdev, wpan_dev, min_be, max_be);
1161}
1162
1163static int
1164nl802154_set_max_csma_backoffs(struct sk_buff *skb, struct genl_info *info)
1165{
1166        struct cfg802154_registered_device *rdev = info->user_ptr[0];
1167        struct net_device *dev = info->user_ptr[1];
1168        struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
1169        u8 max_csma_backoffs;
1170
1171        /* conflict here while other running iface settings */
1172        if (netif_running(dev))
1173                return -EBUSY;
1174
1175        if (!info->attrs[NL802154_ATTR_MAX_CSMA_BACKOFFS])
1176                return -EINVAL;
1177
1178        max_csma_backoffs = nla_get_u8(
1179                        info->attrs[NL802154_ATTR_MAX_CSMA_BACKOFFS]);
1180
1181        /* check 802.15.4 constraints */
1182        if (max_csma_backoffs < rdev->wpan_phy.supported.min_csma_backoffs ||
1183            max_csma_backoffs > rdev->wpan_phy.supported.max_csma_backoffs)
1184                return -EINVAL;
1185
1186        return rdev_set_max_csma_backoffs(rdev, wpan_dev, max_csma_backoffs);
1187}
1188
1189static int
1190nl802154_set_max_frame_retries(struct sk_buff *skb, struct genl_info *info)
1191{
1192        struct cfg802154_registered_device *rdev = info->user_ptr[0];
1193        struct net_device *dev = info->user_ptr[1];
1194        struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
1195        s8 max_frame_retries;
1196
1197        if (netif_running(dev))
1198                return -EBUSY;
1199
1200        if (!info->attrs[NL802154_ATTR_MAX_FRAME_RETRIES])
1201                return -EINVAL;
1202
1203        max_frame_retries = nla_get_s8(
1204                        info->attrs[NL802154_ATTR_MAX_FRAME_RETRIES]);
1205
1206        /* check 802.15.4 constraints */
1207        if (max_frame_retries < rdev->wpan_phy.supported.min_frame_retries ||
1208            max_frame_retries > rdev->wpan_phy.supported.max_frame_retries)
1209                return -EINVAL;
1210
1211        return rdev_set_max_frame_retries(rdev, wpan_dev, max_frame_retries);
1212}
1213
1214static int nl802154_set_lbt_mode(struct sk_buff *skb, struct genl_info *info)
1215{
1216        struct cfg802154_registered_device *rdev = info->user_ptr[0];
1217        struct net_device *dev = info->user_ptr[1];
1218        struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
1219        int mode;
1220
1221        if (netif_running(dev))
1222                return -EBUSY;
1223
1224        if (!info->attrs[NL802154_ATTR_LBT_MODE])
1225                return -EINVAL;
1226
1227        mode = nla_get_u8(info->attrs[NL802154_ATTR_LBT_MODE]);
1228
1229        if (mode != 0 && mode != 1)
1230                return -EINVAL;
1231
1232        if (!wpan_phy_supported_bool(mode, rdev->wpan_phy.supported.lbt))
1233                return -EINVAL;
1234
1235        return rdev_set_lbt_mode(rdev, wpan_dev, mode);
1236}
1237
1238static int
1239nl802154_set_ackreq_default(struct sk_buff *skb, struct genl_info *info)
1240{
1241        struct cfg802154_registered_device *rdev = info->user_ptr[0];
1242        struct net_device *dev = info->user_ptr[1];
1243        struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
1244        int ackreq;
1245
1246        if (netif_running(dev))
1247                return -EBUSY;
1248
1249        if (!info->attrs[NL802154_ATTR_ACKREQ_DEFAULT])
1250                return -EINVAL;
1251
1252        ackreq = nla_get_u8(info->attrs[NL802154_ATTR_ACKREQ_DEFAULT]);
1253
1254        if (ackreq != 0 && ackreq != 1)
1255                return -EINVAL;
1256
1257        return rdev_set_ackreq_default(rdev, wpan_dev, ackreq);
1258}
1259
1260#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
1261static const struct nla_policy nl802154_dev_addr_policy[NL802154_DEV_ADDR_ATTR_MAX + 1] = {
1262        [NL802154_DEV_ADDR_ATTR_PAN_ID] = { .type = NLA_U16 },
1263        [NL802154_DEV_ADDR_ATTR_MODE] = { .type = NLA_U32 },
1264        [NL802154_DEV_ADDR_ATTR_SHORT] = { .type = NLA_U16 },
1265        [NL802154_DEV_ADDR_ATTR_EXTENDED] = { .type = NLA_U64 },
1266};
1267
1268static int
1269ieee802154_llsec_parse_dev_addr(struct nlattr *nla,
1270                                struct ieee802154_addr *addr)
1271{
1272        struct nlattr *attrs[NL802154_DEV_ADDR_ATTR_MAX + 1];
1273
1274        if (!nla || nla_parse_nested(attrs, NL802154_DEV_ADDR_ATTR_MAX, nla,
1275                                     nl802154_dev_addr_policy))
1276                return -EINVAL;
1277
1278        if (!attrs[NL802154_DEV_ADDR_ATTR_PAN_ID] &&
1279            !attrs[NL802154_DEV_ADDR_ATTR_MODE] &&
1280            !(attrs[NL802154_DEV_ADDR_ATTR_SHORT] ||
1281              attrs[NL802154_DEV_ADDR_ATTR_EXTENDED]))
1282                return -EINVAL;
1283
1284        addr->pan_id = nla_get_le16(attrs[NL802154_DEV_ADDR_ATTR_PAN_ID]);
1285        addr->mode = nla_get_u32(attrs[NL802154_DEV_ADDR_ATTR_MODE]);
1286        switch (addr->mode) {
1287        case NL802154_DEV_ADDR_SHORT:
1288                addr->short_addr = nla_get_le16(attrs[NL802154_DEV_ADDR_ATTR_SHORT]);
1289                break;
1290        case NL802154_DEV_ADDR_EXTENDED:
1291                addr->extended_addr = nla_get_le64(attrs[NL802154_DEV_ADDR_ATTR_EXTENDED]);
1292                break;
1293        default:
1294                return -EINVAL;
1295        }
1296
1297        return 0;
1298}
1299
1300static const struct nla_policy nl802154_key_id_policy[NL802154_KEY_ID_ATTR_MAX + 1] = {
1301        [NL802154_KEY_ID_ATTR_MODE] = { .type = NLA_U32 },
1302        [NL802154_KEY_ID_ATTR_INDEX] = { .type = NLA_U8 },
1303        [NL802154_KEY_ID_ATTR_IMPLICIT] = { .type = NLA_NESTED },
1304        [NL802154_KEY_ID_ATTR_SOURCE_SHORT] = { .type = NLA_U32 },
1305        [NL802154_KEY_ID_ATTR_SOURCE_EXTENDED] = { .type = NLA_U64 },
1306};
1307
1308static int
1309ieee802154_llsec_parse_key_id(struct nlattr *nla,
1310                              struct ieee802154_llsec_key_id *desc)
1311{
1312        struct nlattr *attrs[NL802154_KEY_ID_ATTR_MAX + 1];
1313
1314        if (!nla || nla_parse_nested(attrs, NL802154_KEY_ID_ATTR_MAX, nla,
1315                                     nl802154_key_id_policy))
1316                return -EINVAL;
1317
1318        if (!attrs[NL802154_KEY_ID_ATTR_MODE])
1319                return -EINVAL;
1320
1321        desc->mode = nla_get_u32(attrs[NL802154_KEY_ID_ATTR_MODE]);
1322        switch (desc->mode) {
1323        case NL802154_KEY_ID_MODE_IMPLICIT:
1324                if (!attrs[NL802154_KEY_ID_ATTR_IMPLICIT])
1325                        return -EINVAL;
1326
1327                if (ieee802154_llsec_parse_dev_addr(attrs[NL802154_KEY_ID_ATTR_IMPLICIT],
1328                                                    &desc->device_addr) < 0)
1329                        return -EINVAL;
1330                break;
1331        case NL802154_KEY_ID_MODE_INDEX:
1332                break;
1333        case NL802154_KEY_ID_MODE_INDEX_SHORT:
1334                if (!attrs[NL802154_KEY_ID_ATTR_SOURCE_SHORT])
1335                        return -EINVAL;
1336
1337                desc->short_source = nla_get_le32(attrs[NL802154_KEY_ID_ATTR_SOURCE_SHORT]);
1338                break;
1339        case NL802154_KEY_ID_MODE_INDEX_EXTENDED:
1340                if (!attrs[NL802154_KEY_ID_ATTR_SOURCE_EXTENDED])
1341                        return -EINVAL;
1342
1343                desc->extended_source = nla_get_le64(attrs[NL802154_KEY_ID_ATTR_SOURCE_EXTENDED]);
1344                break;
1345        default:
1346                return -EINVAL;
1347        }
1348
1349        if (desc->mode != NL802154_KEY_ID_MODE_IMPLICIT) {
1350                if (!attrs[NL802154_KEY_ID_ATTR_INDEX])
1351                        return -EINVAL;
1352
1353                /* TODO change id to idx */
1354                desc->id = nla_get_u8(attrs[NL802154_KEY_ID_ATTR_INDEX]);
1355        }
1356
1357        return 0;
1358}
1359
1360static int nl802154_set_llsec_params(struct sk_buff *skb,
1361                                     struct genl_info *info)
1362{
1363        struct cfg802154_registered_device *rdev = info->user_ptr[0];
1364        struct net_device *dev = info->user_ptr[1];
1365        struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
1366        struct ieee802154_llsec_params params;
1367        u32 changed = 0;
1368        int ret;
1369
1370        if (info->attrs[NL802154_ATTR_SEC_ENABLED]) {
1371                u8 enabled;
1372
1373                enabled = nla_get_u8(info->attrs[NL802154_ATTR_SEC_ENABLED]);
1374                if (enabled != 0 && enabled != 1)
1375                        return -EINVAL;
1376
1377                params.enabled = nla_get_u8(info->attrs[NL802154_ATTR_SEC_ENABLED]);
1378                changed |= IEEE802154_LLSEC_PARAM_ENABLED;
1379        }
1380
1381        if (info->attrs[NL802154_ATTR_SEC_OUT_KEY_ID]) {
1382                ret = ieee802154_llsec_parse_key_id(info->attrs[NL802154_ATTR_SEC_OUT_KEY_ID],
1383                                                    &params.out_key);
1384                if (ret < 0)
1385                        return ret;
1386
1387                changed |= IEEE802154_LLSEC_PARAM_OUT_KEY;
1388        }
1389
1390        if (info->attrs[NL802154_ATTR_SEC_OUT_LEVEL]) {
1391                params.out_level = nla_get_u32(info->attrs[NL802154_ATTR_SEC_OUT_LEVEL]);
1392                if (params.out_level > NL802154_SECLEVEL_MAX)
1393                        return -EINVAL;
1394
1395                changed |= IEEE802154_LLSEC_PARAM_OUT_LEVEL;
1396        }
1397
1398        if (info->attrs[NL802154_ATTR_SEC_FRAME_COUNTER]) {
1399                params.frame_counter = nla_get_be32(info->attrs[NL802154_ATTR_SEC_FRAME_COUNTER]);
1400                changed |= IEEE802154_LLSEC_PARAM_FRAME_COUNTER;
1401        }
1402
1403        return rdev_set_llsec_params(rdev, wpan_dev, &params, changed);
1404}
1405
1406static int nl802154_send_key(struct sk_buff *msg, u32 cmd, u32 portid,
1407                             u32 seq, int flags,
1408                             struct cfg802154_registered_device *rdev,
1409                             struct net_device *dev,
1410                             const struct ieee802154_llsec_key_entry *key)
1411{
1412        void *hdr;
1413        u32 commands[NL802154_CMD_FRAME_NR_IDS / 32];
1414        struct nlattr *nl_key, *nl_key_id;
1415
1416        hdr = nl802154hdr_put(msg, portid, seq, flags, cmd);
1417        if (!hdr)
1418                return -1;
1419
1420        if (nla_put_u32(msg, NL802154_ATTR_IFINDEX, dev->ifindex))
1421                goto nla_put_failure;
1422
1423        nl_key = nla_nest_start(msg, NL802154_ATTR_SEC_KEY);
1424        if (!nl_key)
1425                goto nla_put_failure;
1426
1427        nl_key_id = nla_nest_start(msg, NL802154_KEY_ATTR_ID);
1428        if (!nl_key_id)
1429                goto nla_put_failure;
1430
1431        if (ieee802154_llsec_send_key_id(msg, &key->id) < 0)
1432                goto nla_put_failure;
1433
1434        nla_nest_end(msg, nl_key_id);
1435
1436        if (nla_put_u8(msg, NL802154_KEY_ATTR_USAGE_FRAMES,
1437                       key->key->frame_types))
1438                goto nla_put_failure;
1439
1440        if (key->key->frame_types & BIT(NL802154_FRAME_CMD)) {
1441                /* TODO for each nested */
1442                memset(commands, 0, sizeof(commands));
1443                commands[7] = key->key->cmd_frame_ids;
1444                if (nla_put(msg, NL802154_KEY_ATTR_USAGE_CMDS,
1445                            sizeof(commands), commands))
1446                        goto nla_put_failure;
1447        }
1448
1449        if (nla_put(msg, NL802154_KEY_ATTR_BYTES, NL802154_KEY_SIZE,
1450                    key->key->key))
1451                goto nla_put_failure;
1452
1453        nla_nest_end(msg, nl_key);
1454        genlmsg_end(msg, hdr);
1455
1456        return 0;
1457
1458nla_put_failure:
1459        genlmsg_cancel(msg, hdr);
1460        return -EMSGSIZE;
1461}
1462
1463static int
1464nl802154_dump_llsec_key(struct sk_buff *skb, struct netlink_callback *cb)
1465{
1466        struct cfg802154_registered_device *rdev = NULL;
1467        struct ieee802154_llsec_key_entry *key;
1468        struct ieee802154_llsec_table *table;
1469        struct wpan_dev *wpan_dev;
1470        int err;
1471
1472        err = nl802154_prepare_wpan_dev_dump(skb, cb, &rdev, &wpan_dev);
1473        if (err)
1474                return err;
1475
1476        if (!wpan_dev->netdev) {
1477                err = -EINVAL;
1478                goto out_err;
1479        }
1480
1481        rdev_lock_llsec_table(rdev, wpan_dev);
1482        rdev_get_llsec_table(rdev, wpan_dev, &table);
1483
1484        /* TODO make it like station dump */
1485        if (cb->args[2])
1486                goto out;
1487
1488        list_for_each_entry(key, &table->keys, list) {
1489                if (nl802154_send_key(skb, NL802154_CMD_NEW_SEC_KEY,
1490                                      NETLINK_CB(cb->skb).portid,
1491                                      cb->nlh->nlmsg_seq, NLM_F_MULTI,
1492                                      rdev, wpan_dev->netdev, key) < 0) {
1493                        /* TODO */
1494                        err = -EIO;
1495                        rdev_unlock_llsec_table(rdev, wpan_dev);
1496                        goto out_err;
1497                }
1498        }
1499
1500        cb->args[2] = 1;
1501
1502out:
1503        rdev_unlock_llsec_table(rdev, wpan_dev);
1504        err = skb->len;
1505out_err:
1506        nl802154_finish_wpan_dev_dump(rdev);
1507
1508        return err;
1509}
1510
1511static const struct nla_policy nl802154_key_policy[NL802154_KEY_ATTR_MAX + 1] = {
1512        [NL802154_KEY_ATTR_ID] = { NLA_NESTED },
1513        /* TODO handle it as for_each_nested and NLA_FLAG? */
1514        [NL802154_KEY_ATTR_USAGE_FRAMES] = { NLA_U8 },
1515        /* TODO handle it as for_each_nested, not static array? */
1516        [NL802154_KEY_ATTR_USAGE_CMDS] = { .len = NL802154_CMD_FRAME_NR_IDS / 8 },
1517        [NL802154_KEY_ATTR_BYTES] = { .len = NL802154_KEY_SIZE },
1518};
1519
1520static int nl802154_add_llsec_key(struct sk_buff *skb, struct genl_info *info)
1521{
1522        struct cfg802154_registered_device *rdev = info->user_ptr[0];
1523        struct net_device *dev = info->user_ptr[1];
1524        struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
1525        struct nlattr *attrs[NL802154_KEY_ATTR_MAX + 1];
1526        struct ieee802154_llsec_key key = { };
1527        struct ieee802154_llsec_key_id id = { };
1528        u32 commands[NL802154_CMD_FRAME_NR_IDS / 32] = { };
1529
1530        if (nla_parse_nested(attrs, NL802154_KEY_ATTR_MAX,
1531                             info->attrs[NL802154_ATTR_SEC_KEY],
1532                             nl802154_key_policy))
1533                return -EINVAL;
1534
1535        if (!attrs[NL802154_KEY_ATTR_USAGE_FRAMES] ||
1536            !attrs[NL802154_KEY_ATTR_BYTES])
1537                return -EINVAL;
1538
1539        if (ieee802154_llsec_parse_key_id(attrs[NL802154_KEY_ATTR_ID], &id) < 0)
1540                return -ENOBUFS;
1541
1542        key.frame_types = nla_get_u8(attrs[NL802154_KEY_ATTR_USAGE_FRAMES]);
1543        if (key.frame_types > BIT(NL802154_FRAME_MAX) ||
1544            ((key.frame_types & BIT(NL802154_FRAME_CMD)) &&
1545             !attrs[NL802154_KEY_ATTR_USAGE_CMDS]))
1546                return -EINVAL;
1547
1548        if (attrs[NL802154_KEY_ATTR_USAGE_CMDS]) {
1549                /* TODO for each nested */
1550                nla_memcpy(commands, attrs[NL802154_KEY_ATTR_USAGE_CMDS],
1551                           NL802154_CMD_FRAME_NR_IDS / 8);
1552
1553                /* TODO understand the -EINVAL logic here? last condition */
1554                if (commands[0] || commands[1] || commands[2] || commands[3] ||
1555                    commands[4] || commands[5] || commands[6] ||
1556                    commands[7] > BIT(NL802154_CMD_FRAME_MAX))
1557                        return -EINVAL;
1558
1559                key.cmd_frame_ids = commands[7];
1560        } else {
1561                key.cmd_frame_ids = 0;
1562        }
1563
1564        nla_memcpy(key.key, attrs[NL802154_KEY_ATTR_BYTES], NL802154_KEY_SIZE);
1565
1566        if (ieee802154_llsec_parse_key_id(attrs[NL802154_KEY_ATTR_ID], &id) < 0)
1567                return -ENOBUFS;
1568
1569        return rdev_add_llsec_key(rdev, wpan_dev, &id, &key);
1570}
1571
1572static int nl802154_del_llsec_key(struct sk_buff *skb, struct genl_info *info)
1573{
1574        struct cfg802154_registered_device *rdev = info->user_ptr[0];
1575        struct net_device *dev = info->user_ptr[1];
1576        struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
1577        struct nlattr *attrs[NL802154_KEY_ATTR_MAX + 1];
1578        struct ieee802154_llsec_key_id id;
1579
1580        if (nla_parse_nested(attrs, NL802154_KEY_ATTR_MAX,
1581                             info->attrs[NL802154_ATTR_SEC_KEY],
1582                             nl802154_key_policy))
1583                return -EINVAL;
1584
1585        if (ieee802154_llsec_parse_key_id(attrs[NL802154_KEY_ATTR_ID], &id) < 0)
1586                return -ENOBUFS;
1587
1588        return rdev_del_llsec_key(rdev, wpan_dev, &id);
1589}
1590
1591static int nl802154_send_device(struct sk_buff *msg, u32 cmd, u32 portid,
1592                                u32 seq, int flags,
1593                                struct cfg802154_registered_device *rdev,
1594                                struct net_device *dev,
1595                                const struct ieee802154_llsec_device *dev_desc)
1596{
1597        void *hdr;
1598        struct nlattr *nl_device;
1599
1600        hdr = nl802154hdr_put(msg, portid, seq, flags, cmd);
1601        if (!hdr)
1602                return -1;
1603
1604        if (nla_put_u32(msg, NL802154_ATTR_IFINDEX, dev->ifindex))
1605                goto nla_put_failure;
1606
1607        nl_device = nla_nest_start(msg, NL802154_ATTR_SEC_DEVICE);
1608        if (!nl_device)
1609                goto nla_put_failure;
1610
1611        if (nla_put_u32(msg, NL802154_DEV_ATTR_FRAME_COUNTER,
1612                        dev_desc->frame_counter) ||
1613            nla_put_le16(msg, NL802154_DEV_ATTR_PAN_ID, dev_desc->pan_id) ||
1614            nla_put_le16(msg, NL802154_DEV_ATTR_SHORT_ADDR,
1615                         dev_desc->short_addr) ||
1616            nla_put_le64(msg, NL802154_DEV_ATTR_EXTENDED_ADDR,
1617                         dev_desc->hwaddr) ||
1618            nla_put_u8(msg, NL802154_DEV_ATTR_SECLEVEL_EXEMPT,
1619                       dev_desc->seclevel_exempt) ||
1620            nla_put_u32(msg, NL802154_DEV_ATTR_KEY_MODE, dev_desc->key_mode))
1621                goto nla_put_failure;
1622
1623        nla_nest_end(msg, nl_device);
1624        genlmsg_end(msg, hdr);
1625
1626        return 0;
1627
1628nla_put_failure:
1629        genlmsg_cancel(msg, hdr);
1630        return -EMSGSIZE;
1631}
1632
1633static int
1634nl802154_dump_llsec_dev(struct sk_buff *skb, struct netlink_callback *cb)
1635{
1636        struct cfg802154_registered_device *rdev = NULL;
1637        struct ieee802154_llsec_device *dev;
1638        struct ieee802154_llsec_table *table;
1639        struct wpan_dev *wpan_dev;
1640        int err;
1641
1642        err = nl802154_prepare_wpan_dev_dump(skb, cb, &rdev, &wpan_dev);
1643        if (err)
1644                return err;
1645
1646        if (!wpan_dev->netdev) {
1647                err = -EINVAL;
1648                goto out_err;
1649        }
1650
1651        rdev_lock_llsec_table(rdev, wpan_dev);
1652        rdev_get_llsec_table(rdev, wpan_dev, &table);
1653
1654        /* TODO make it like station dump */
1655        if (cb->args[2])
1656                goto out;
1657
1658        list_for_each_entry(dev, &table->devices, list) {
1659                if (nl802154_send_device(skb, NL802154_CMD_NEW_SEC_LEVEL,
1660                                         NETLINK_CB(cb->skb).portid,
1661                                         cb->nlh->nlmsg_seq, NLM_F_MULTI,
1662                                         rdev, wpan_dev->netdev, dev) < 0) {
1663                        /* TODO */
1664                        err = -EIO;
1665                        rdev_unlock_llsec_table(rdev, wpan_dev);
1666                        goto out_err;
1667                }
1668        }
1669
1670        cb->args[2] = 1;
1671
1672out:
1673        rdev_unlock_llsec_table(rdev, wpan_dev);
1674        err = skb->len;
1675out_err:
1676        nl802154_finish_wpan_dev_dump(rdev);
1677
1678        return err;
1679}
1680
1681static const struct nla_policy nl802154_dev_policy[NL802154_DEV_ATTR_MAX + 1] = {
1682        [NL802154_DEV_ATTR_FRAME_COUNTER] = { NLA_U32 },
1683        [NL802154_DEV_ATTR_PAN_ID] = { .type = NLA_U16 },
1684        [NL802154_DEV_ATTR_SHORT_ADDR] = { .type = NLA_U16 },
1685        [NL802154_DEV_ATTR_EXTENDED_ADDR] = { .type = NLA_U64 },
1686        [NL802154_DEV_ATTR_SECLEVEL_EXEMPT] = { NLA_U8 },
1687        [NL802154_DEV_ATTR_KEY_MODE] = { NLA_U32 },
1688};
1689
1690static int
1691ieee802154_llsec_parse_device(struct nlattr *nla,
1692                              struct ieee802154_llsec_device *dev)
1693{
1694        struct nlattr *attrs[NL802154_DEV_ATTR_MAX + 1];
1695
1696        if (!nla || nla_parse_nested(attrs, NL802154_DEV_ATTR_MAX, nla,
1697                                     nl802154_dev_policy))
1698                return -EINVAL;
1699
1700        memset(dev, 0, sizeof(*dev));
1701
1702        if (!attrs[NL802154_DEV_ATTR_FRAME_COUNTER] ||
1703            !attrs[NL802154_DEV_ATTR_PAN_ID] ||
1704            !attrs[NL802154_DEV_ATTR_SHORT_ADDR] ||
1705            !attrs[NL802154_DEV_ATTR_EXTENDED_ADDR] ||
1706            !attrs[NL802154_DEV_ATTR_SECLEVEL_EXEMPT] ||
1707            !attrs[NL802154_DEV_ATTR_KEY_MODE])
1708                return -EINVAL;
1709
1710        /* TODO be32 */
1711        dev->frame_counter = nla_get_u32(attrs[NL802154_DEV_ATTR_FRAME_COUNTER]);
1712        dev->pan_id = nla_get_le16(attrs[NL802154_DEV_ATTR_PAN_ID]);
1713        dev->short_addr = nla_get_le16(attrs[NL802154_DEV_ATTR_SHORT_ADDR]);
1714        /* TODO rename hwaddr to extended_addr */
1715        dev->hwaddr = nla_get_le64(attrs[NL802154_DEV_ATTR_EXTENDED_ADDR]);
1716        dev->seclevel_exempt = nla_get_u8(attrs[NL802154_DEV_ATTR_SECLEVEL_EXEMPT]);
1717        dev->key_mode = nla_get_u32(attrs[NL802154_DEV_ATTR_KEY_MODE]);
1718
1719        if (dev->key_mode > NL802154_DEVKEY_MAX ||
1720            (dev->seclevel_exempt != 0 && dev->seclevel_exempt != 1))
1721                return -EINVAL;
1722
1723        return 0;
1724}
1725
1726static int nl802154_add_llsec_dev(struct sk_buff *skb, struct genl_info *info)
1727{
1728        struct cfg802154_registered_device *rdev = info->user_ptr[0];
1729        struct net_device *dev = info->user_ptr[1];
1730        struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
1731        struct ieee802154_llsec_device dev_desc;
1732
1733        if (ieee802154_llsec_parse_device(info->attrs[NL802154_ATTR_SEC_DEVICE],
1734                                          &dev_desc) < 0)
1735                return -EINVAL;
1736
1737        return rdev_add_device(rdev, wpan_dev, &dev_desc);
1738}
1739
1740static int nl802154_del_llsec_dev(struct sk_buff *skb, struct genl_info *info)
1741{
1742        struct cfg802154_registered_device *rdev = info->user_ptr[0];
1743        struct net_device *dev = info->user_ptr[1];
1744        struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
1745        struct nlattr *attrs[NL802154_DEV_ATTR_MAX + 1];
1746        __le64 extended_addr;
1747
1748        if (nla_parse_nested(attrs, NL802154_DEV_ATTR_MAX,
1749                             info->attrs[NL802154_ATTR_SEC_DEVICE],
1750                             nl802154_dev_policy))
1751                return -EINVAL;
1752
1753        if (!attrs[NL802154_DEV_ATTR_EXTENDED_ADDR])
1754                return -EINVAL;
1755
1756        extended_addr = nla_get_le64(attrs[NL802154_DEV_ATTR_EXTENDED_ADDR]);
1757        return rdev_del_device(rdev, wpan_dev, extended_addr);
1758}
1759
1760static int nl802154_send_devkey(struct sk_buff *msg, u32 cmd, u32 portid,
1761                                u32 seq, int flags,
1762                                struct cfg802154_registered_device *rdev,
1763                                struct net_device *dev, __le64 extended_addr,
1764                                const struct ieee802154_llsec_device_key *devkey)
1765{
1766        void *hdr;
1767        struct nlattr *nl_devkey, *nl_key_id;
1768
1769        hdr = nl802154hdr_put(msg, portid, seq, flags, cmd);
1770        if (!hdr)
1771                return -1;
1772
1773        if (nla_put_u32(msg, NL802154_ATTR_IFINDEX, dev->ifindex))
1774                goto nla_put_failure;
1775
1776        nl_devkey = nla_nest_start(msg, NL802154_ATTR_SEC_DEVKEY);
1777        if (!nl_devkey)
1778                goto nla_put_failure;
1779
1780        if (nla_put_le64(msg, NL802154_DEVKEY_ATTR_EXTENDED_ADDR,
1781                         extended_addr) ||
1782            nla_put_u32(msg, NL802154_DEVKEY_ATTR_FRAME_COUNTER,
1783                        devkey->frame_counter))
1784                goto nla_put_failure;
1785
1786        nl_key_id = nla_nest_start(msg, NL802154_DEVKEY_ATTR_ID);
1787        if (!nl_key_id)
1788                goto nla_put_failure;
1789
1790        if (ieee802154_llsec_send_key_id(msg, &devkey->key_id) < 0)
1791                goto nla_put_failure;
1792
1793        nla_nest_end(msg, nl_key_id);
1794        nla_nest_end(msg, nl_devkey);
1795        genlmsg_end(msg, hdr);
1796
1797        return 0;
1798
1799nla_put_failure:
1800        genlmsg_cancel(msg, hdr);
1801        return -EMSGSIZE;
1802}
1803
1804static int
1805nl802154_dump_llsec_devkey(struct sk_buff *skb, struct netlink_callback *cb)
1806{
1807        struct cfg802154_registered_device *rdev = NULL;
1808        struct ieee802154_llsec_device_key *kpos;
1809        struct ieee802154_llsec_device *dpos;
1810        struct ieee802154_llsec_table *table;
1811        struct wpan_dev *wpan_dev;
1812        int err;
1813
1814        err = nl802154_prepare_wpan_dev_dump(skb, cb, &rdev, &wpan_dev);
1815        if (err)
1816                return err;
1817
1818        if (!wpan_dev->netdev) {
1819                err = -EINVAL;
1820                goto out_err;
1821        }
1822
1823        rdev_lock_llsec_table(rdev, wpan_dev);
1824        rdev_get_llsec_table(rdev, wpan_dev, &table);
1825
1826        /* TODO make it like station dump */
1827        if (cb->args[2])
1828                goto out;
1829
1830        /* TODO look if remove devkey and do some nested attribute */
1831        list_for_each_entry(dpos, &table->devices, list) {
1832                list_for_each_entry(kpos, &dpos->keys, list) {
1833                        if (nl802154_send_devkey(skb,
1834                                                 NL802154_CMD_NEW_SEC_LEVEL,
1835                                                 NETLINK_CB(cb->skb).portid,
1836                                                 cb->nlh->nlmsg_seq,
1837                                                 NLM_F_MULTI, rdev,
1838                                                 wpan_dev->netdev,
1839                                                 dpos->hwaddr,
1840                                                 kpos) < 0) {
1841                                /* TODO */
1842                                err = -EIO;
1843                                rdev_unlock_llsec_table(rdev, wpan_dev);
1844                                goto out_err;
1845                        }
1846                }
1847        }
1848
1849        cb->args[2] = 1;
1850
1851out:
1852        rdev_unlock_llsec_table(rdev, wpan_dev);
1853        err = skb->len;
1854out_err:
1855        nl802154_finish_wpan_dev_dump(rdev);
1856
1857        return err;
1858}
1859
1860static const struct nla_policy nl802154_devkey_policy[NL802154_DEVKEY_ATTR_MAX + 1] = {
1861        [NL802154_DEVKEY_ATTR_FRAME_COUNTER] = { NLA_U32 },
1862        [NL802154_DEVKEY_ATTR_EXTENDED_ADDR] = { NLA_U64 },
1863        [NL802154_DEVKEY_ATTR_ID] = { NLA_NESTED },
1864};
1865
1866static int nl802154_add_llsec_devkey(struct sk_buff *skb, struct genl_info *info)
1867{
1868        struct cfg802154_registered_device *rdev = info->user_ptr[0];
1869        struct net_device *dev = info->user_ptr[1];
1870        struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
1871        struct nlattr *attrs[NL802154_DEVKEY_ATTR_MAX + 1];
1872        struct ieee802154_llsec_device_key key;
1873        __le64 extended_addr;
1874
1875        if (!info->attrs[NL802154_ATTR_SEC_DEVKEY] ||
1876            nla_parse_nested(attrs, NL802154_DEVKEY_ATTR_MAX,
1877                             info->attrs[NL802154_ATTR_SEC_DEVKEY],
1878                             nl802154_devkey_policy) < 0)
1879                return -EINVAL;
1880
1881        if (!attrs[NL802154_DEVKEY_ATTR_FRAME_COUNTER] ||
1882            !attrs[NL802154_DEVKEY_ATTR_EXTENDED_ADDR])
1883                return -EINVAL;
1884
1885        /* TODO change key.id ? */
1886        if (ieee802154_llsec_parse_key_id(attrs[NL802154_DEVKEY_ATTR_ID],
1887                                          &key.key_id) < 0)
1888                return -ENOBUFS;
1889
1890        /* TODO be32 */
1891        key.frame_counter = nla_get_u32(attrs[NL802154_DEVKEY_ATTR_FRAME_COUNTER]);
1892        /* TODO change naming hwaddr -> extended_addr
1893         * check unique identifier short+pan OR extended_addr
1894         */
1895        extended_addr = nla_get_le64(attrs[NL802154_DEVKEY_ATTR_EXTENDED_ADDR]);
1896        return rdev_add_devkey(rdev, wpan_dev, extended_addr, &key);
1897}
1898
1899static int nl802154_del_llsec_devkey(struct sk_buff *skb, struct genl_info *info)
1900{
1901        struct cfg802154_registered_device *rdev = info->user_ptr[0];
1902        struct net_device *dev = info->user_ptr[1];
1903        struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
1904        struct nlattr *attrs[NL802154_DEVKEY_ATTR_MAX + 1];
1905        struct ieee802154_llsec_device_key key;
1906        __le64 extended_addr;
1907
1908        if (nla_parse_nested(attrs, NL802154_DEVKEY_ATTR_MAX,
1909                             info->attrs[NL802154_ATTR_SEC_DEVKEY],
1910                             nl802154_devkey_policy))
1911                return -EINVAL;
1912
1913        if (!attrs[NL802154_DEVKEY_ATTR_EXTENDED_ADDR])
1914                return -EINVAL;
1915
1916        /* TODO change key.id ? */
1917        if (ieee802154_llsec_parse_key_id(attrs[NL802154_DEVKEY_ATTR_ID],
1918                                          &key.key_id) < 0)
1919                return -ENOBUFS;
1920
1921        /* TODO change naming hwaddr -> extended_addr
1922         * check unique identifier short+pan OR extended_addr
1923         */
1924        extended_addr = nla_get_le64(attrs[NL802154_DEVKEY_ATTR_EXTENDED_ADDR]);
1925        return rdev_del_devkey(rdev, wpan_dev, extended_addr, &key);
1926}
1927
1928static int nl802154_send_seclevel(struct sk_buff *msg, u32 cmd, u32 portid,
1929                                  u32 seq, int flags,
1930                                  struct cfg802154_registered_device *rdev,
1931                                  struct net_device *dev,
1932                                  const struct ieee802154_llsec_seclevel *sl)
1933{
1934        void *hdr;
1935        struct nlattr *nl_seclevel;
1936
1937        hdr = nl802154hdr_put(msg, portid, seq, flags, cmd);
1938        if (!hdr)
1939                return -1;
1940
1941        if (nla_put_u32(msg, NL802154_ATTR_IFINDEX, dev->ifindex))
1942                goto nla_put_failure;
1943
1944        nl_seclevel = nla_nest_start(msg, NL802154_ATTR_SEC_LEVEL);
1945        if (!nl_seclevel)
1946                goto nla_put_failure;
1947
1948        if (nla_put_u32(msg, NL802154_SECLEVEL_ATTR_FRAME, sl->frame_type) ||
1949            nla_put_u32(msg, NL802154_SECLEVEL_ATTR_LEVELS, sl->sec_levels) ||
1950            nla_put_u8(msg, NL802154_SECLEVEL_ATTR_DEV_OVERRIDE,
1951                       sl->device_override))
1952                goto nla_put_failure;
1953
1954        if (sl->frame_type == NL802154_FRAME_CMD) {
1955                if (nla_put_u32(msg, NL802154_SECLEVEL_ATTR_CMD_FRAME,
1956                                sl->cmd_frame_id))
1957                        goto nla_put_failure;
1958        }
1959
1960        nla_nest_end(msg, nl_seclevel);
1961        genlmsg_end(msg, hdr);
1962
1963        return 0;
1964
1965nla_put_failure:
1966        genlmsg_cancel(msg, hdr);
1967        return -EMSGSIZE;
1968}
1969
1970static int
1971nl802154_dump_llsec_seclevel(struct sk_buff *skb, struct netlink_callback *cb)
1972{
1973        struct cfg802154_registered_device *rdev = NULL;
1974        struct ieee802154_llsec_seclevel *sl;
1975        struct ieee802154_llsec_table *table;
1976        struct wpan_dev *wpan_dev;
1977        int err;
1978
1979        err = nl802154_prepare_wpan_dev_dump(skb, cb, &rdev, &wpan_dev);
1980        if (err)
1981                return err;
1982
1983        if (!wpan_dev->netdev) {
1984                err = -EINVAL;
1985                goto out_err;
1986        }
1987
1988        rdev_lock_llsec_table(rdev, wpan_dev);
1989        rdev_get_llsec_table(rdev, wpan_dev, &table);
1990
1991        /* TODO make it like station dump */
1992        if (cb->args[2])
1993                goto out;
1994
1995        list_for_each_entry(sl, &table->security_levels, list) {
1996                if (nl802154_send_seclevel(skb, NL802154_CMD_NEW_SEC_LEVEL,
1997                                           NETLINK_CB(cb->skb).portid,
1998                                           cb->nlh->nlmsg_seq, NLM_F_MULTI,
1999                                           rdev, wpan_dev->netdev, sl) < 0) {
2000                        /* TODO */
2001                        err = -EIO;
2002                        rdev_unlock_llsec_table(rdev, wpan_dev);
2003                        goto out_err;
2004                }
2005        }
2006
2007        cb->args[2] = 1;
2008
2009out:
2010        rdev_unlock_llsec_table(rdev, wpan_dev);
2011        err = skb->len;
2012out_err:
2013        nl802154_finish_wpan_dev_dump(rdev);
2014
2015        return err;
2016}
2017
2018static const struct nla_policy nl802154_seclevel_policy[NL802154_SECLEVEL_ATTR_MAX + 1] = {
2019        [NL802154_SECLEVEL_ATTR_LEVELS] = { .type = NLA_U8 },
2020        [NL802154_SECLEVEL_ATTR_FRAME] = { .type = NLA_U32 },
2021        [NL802154_SECLEVEL_ATTR_CMD_FRAME] = { .type = NLA_U32 },
2022        [NL802154_SECLEVEL_ATTR_DEV_OVERRIDE] = { .type = NLA_U8 },
2023};
2024
2025static int
2026llsec_parse_seclevel(struct nlattr *nla, struct ieee802154_llsec_seclevel *sl)
2027{
2028        struct nlattr *attrs[NL802154_SECLEVEL_ATTR_MAX + 1];
2029
2030        if (!nla || nla_parse_nested(attrs, NL802154_SECLEVEL_ATTR_MAX, nla,
2031                                     nl802154_seclevel_policy))
2032                return -EINVAL;
2033
2034        memset(sl, 0, sizeof(*sl));
2035
2036        if (!attrs[NL802154_SECLEVEL_ATTR_LEVELS] ||
2037            !attrs[NL802154_SECLEVEL_ATTR_FRAME] ||
2038            !attrs[NL802154_SECLEVEL_ATTR_DEV_OVERRIDE])
2039                return -EINVAL;
2040
2041        sl->sec_levels = nla_get_u8(attrs[NL802154_SECLEVEL_ATTR_LEVELS]);
2042        sl->frame_type = nla_get_u32(attrs[NL802154_SECLEVEL_ATTR_FRAME]);
2043        sl->device_override = nla_get_u8(attrs[NL802154_SECLEVEL_ATTR_DEV_OVERRIDE]);
2044        if (sl->frame_type > NL802154_FRAME_MAX ||
2045            (sl->device_override != 0 && sl->device_override != 1))
2046                return -EINVAL;
2047
2048        if (sl->frame_type == NL802154_FRAME_CMD) {
2049                if (!attrs[NL802154_SECLEVEL_ATTR_CMD_FRAME])
2050                        return -EINVAL;
2051
2052                sl->cmd_frame_id = nla_get_u32(attrs[NL802154_SECLEVEL_ATTR_CMD_FRAME]);
2053                if (sl->cmd_frame_id > NL802154_CMD_FRAME_MAX)
2054                        return -EINVAL;
2055        }
2056
2057        return 0;
2058}
2059
2060static int nl802154_add_llsec_seclevel(struct sk_buff *skb,
2061                                       struct genl_info *info)
2062{
2063        struct cfg802154_registered_device *rdev = info->user_ptr[0];
2064        struct net_device *dev = info->user_ptr[1];
2065        struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
2066        struct ieee802154_llsec_seclevel sl;
2067
2068        if (llsec_parse_seclevel(info->attrs[NL802154_ATTR_SEC_LEVEL],
2069                                 &sl) < 0)
2070                return -EINVAL;
2071
2072        return rdev_add_seclevel(rdev, wpan_dev, &sl);
2073}
2074
2075static int nl802154_del_llsec_seclevel(struct sk_buff *skb,
2076                                       struct genl_info *info)
2077{
2078        struct cfg802154_registered_device *rdev = info->user_ptr[0];
2079        struct net_device *dev = info->user_ptr[1];
2080        struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
2081        struct ieee802154_llsec_seclevel sl;
2082
2083        if (!info->attrs[NL802154_ATTR_SEC_LEVEL] ||
2084            llsec_parse_seclevel(info->attrs[NL802154_ATTR_SEC_LEVEL],
2085                                 &sl) < 0)
2086                return -EINVAL;
2087
2088        return rdev_del_seclevel(rdev, wpan_dev, &sl);
2089}
2090#endif /* CONFIG_IEEE802154_NL802154_EXPERIMENTAL */
2091
2092#define NL802154_FLAG_NEED_WPAN_PHY     0x01
2093#define NL802154_FLAG_NEED_NETDEV       0x02
2094#define NL802154_FLAG_NEED_RTNL         0x04
2095#define NL802154_FLAG_CHECK_NETDEV_UP   0x08
2096#define NL802154_FLAG_NEED_NETDEV_UP    (NL802154_FLAG_NEED_NETDEV |\
2097                                         NL802154_FLAG_CHECK_NETDEV_UP)
2098#define NL802154_FLAG_NEED_WPAN_DEV     0x10
2099#define NL802154_FLAG_NEED_WPAN_DEV_UP  (NL802154_FLAG_NEED_WPAN_DEV |\
2100                                         NL802154_FLAG_CHECK_NETDEV_UP)
2101
2102static int nl802154_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
2103                             struct genl_info *info)
2104{
2105        struct cfg802154_registered_device *rdev;
2106        struct wpan_dev *wpan_dev;
2107        struct net_device *dev;
2108        bool rtnl = ops->internal_flags & NL802154_FLAG_NEED_RTNL;
2109
2110        if (rtnl)
2111                rtnl_lock();
2112
2113        if (ops->internal_flags & NL802154_FLAG_NEED_WPAN_PHY) {
2114                rdev = cfg802154_get_dev_from_info(genl_info_net(info), info);
2115                if (IS_ERR(rdev)) {
2116                        if (rtnl)
2117                                rtnl_unlock();
2118                        return PTR_ERR(rdev);
2119                }
2120                info->user_ptr[0] = rdev;
2121        } else if (ops->internal_flags & NL802154_FLAG_NEED_NETDEV ||
2122                   ops->internal_flags & NL802154_FLAG_NEED_WPAN_DEV) {
2123                ASSERT_RTNL();
2124                wpan_dev = __cfg802154_wpan_dev_from_attrs(genl_info_net(info),
2125                                                           info->attrs);
2126                if (IS_ERR(wpan_dev)) {
2127                        if (rtnl)
2128                                rtnl_unlock();
2129                        return PTR_ERR(wpan_dev);
2130                }
2131
2132                dev = wpan_dev->netdev;
2133                rdev = wpan_phy_to_rdev(wpan_dev->wpan_phy);
2134
2135                if (ops->internal_flags & NL802154_FLAG_NEED_NETDEV) {
2136                        if (!dev) {
2137                                if (rtnl)
2138                                        rtnl_unlock();
2139                                return -EINVAL;
2140                        }
2141
2142                        info->user_ptr[1] = dev;
2143                } else {
2144                        info->user_ptr[1] = wpan_dev;
2145                }
2146
2147                if (dev) {
2148                        if (ops->internal_flags & NL802154_FLAG_CHECK_NETDEV_UP &&
2149                            !netif_running(dev)) {
2150                                if (rtnl)
2151                                        rtnl_unlock();
2152                                return -ENETDOWN;
2153                        }
2154
2155                        dev_hold(dev);
2156                }
2157
2158                info->user_ptr[0] = rdev;
2159        }
2160
2161        return 0;
2162}
2163
2164static void nl802154_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
2165                               struct genl_info *info)
2166{
2167        if (info->user_ptr[1]) {
2168                if (ops->internal_flags & NL802154_FLAG_NEED_WPAN_DEV) {
2169                        struct wpan_dev *wpan_dev = info->user_ptr[1];
2170
2171                        if (wpan_dev->netdev)
2172                                dev_put(wpan_dev->netdev);
2173                } else {
2174                        dev_put(info->user_ptr[1]);
2175                }
2176        }
2177
2178        if (ops->internal_flags & NL802154_FLAG_NEED_RTNL)
2179                rtnl_unlock();
2180}
2181
2182static const struct genl_ops nl802154_ops[] = {
2183        {
2184                .cmd = NL802154_CMD_GET_WPAN_PHY,
2185                .doit = nl802154_get_wpan_phy,
2186                .dumpit = nl802154_dump_wpan_phy,
2187                .done = nl802154_dump_wpan_phy_done,
2188                .policy = nl802154_policy,
2189                /* can be retrieved by unprivileged users */
2190                .internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
2191                                  NL802154_FLAG_NEED_RTNL,
2192        },
2193        {
2194                .cmd = NL802154_CMD_GET_INTERFACE,
2195                .doit = nl802154_get_interface,
2196                .dumpit = nl802154_dump_interface,
2197                .policy = nl802154_policy,
2198                /* can be retrieved by unprivileged users */
2199                .internal_flags = NL802154_FLAG_NEED_WPAN_DEV |
2200                                  NL802154_FLAG_NEED_RTNL,
2201        },
2202        {
2203                .cmd = NL802154_CMD_NEW_INTERFACE,
2204                .doit = nl802154_new_interface,
2205                .policy = nl802154_policy,
2206                .flags = GENL_ADMIN_PERM,
2207                .internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
2208                                  NL802154_FLAG_NEED_RTNL,
2209        },
2210        {
2211                .cmd = NL802154_CMD_DEL_INTERFACE,
2212                .doit = nl802154_del_interface,
2213                .policy = nl802154_policy,
2214                .flags = GENL_ADMIN_PERM,
2215                .internal_flags = NL802154_FLAG_NEED_WPAN_DEV |
2216                                  NL802154_FLAG_NEED_RTNL,
2217        },
2218        {
2219                .cmd = NL802154_CMD_SET_CHANNEL,
2220                .doit = nl802154_set_channel,
2221                .policy = nl802154_policy,
2222                .flags = GENL_ADMIN_PERM,
2223                .internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
2224                                  NL802154_FLAG_NEED_RTNL,
2225        },
2226        {
2227                .cmd = NL802154_CMD_SET_CCA_MODE,
2228                .doit = nl802154_set_cca_mode,
2229                .policy = nl802154_policy,
2230                .flags = GENL_ADMIN_PERM,
2231                .internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
2232                                  NL802154_FLAG_NEED_RTNL,
2233        },
2234        {
2235                .cmd = NL802154_CMD_SET_CCA_ED_LEVEL,
2236                .doit = nl802154_set_cca_ed_level,
2237                .policy = nl802154_policy,
2238                .flags = GENL_ADMIN_PERM,
2239                .internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
2240                                  NL802154_FLAG_NEED_RTNL,
2241        },
2242        {
2243                .cmd = NL802154_CMD_SET_TX_POWER,
2244                .doit = nl802154_set_tx_power,
2245                .policy = nl802154_policy,
2246                .flags = GENL_ADMIN_PERM,
2247                .internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
2248                                  NL802154_FLAG_NEED_RTNL,
2249        },
2250        {
2251                .cmd = NL802154_CMD_SET_PAN_ID,
2252                .doit = nl802154_set_pan_id,
2253                .policy = nl802154_policy,
2254                .flags = GENL_ADMIN_PERM,
2255                .internal_flags = NL802154_FLAG_NEED_NETDEV |
2256                                  NL802154_FLAG_NEED_RTNL,
2257        },
2258        {
2259                .cmd = NL802154_CMD_SET_SHORT_ADDR,
2260                .doit = nl802154_set_short_addr,
2261                .policy = nl802154_policy,
2262                .flags = GENL_ADMIN_PERM,
2263                .internal_flags = NL802154_FLAG_NEED_NETDEV |
2264                                  NL802154_FLAG_NEED_RTNL,
2265        },
2266        {
2267                .cmd = NL802154_CMD_SET_BACKOFF_EXPONENT,
2268                .doit = nl802154_set_backoff_exponent,
2269                .policy = nl802154_policy,
2270                .flags = GENL_ADMIN_PERM,
2271                .internal_flags = NL802154_FLAG_NEED_NETDEV |
2272                                  NL802154_FLAG_NEED_RTNL,
2273        },
2274        {
2275                .cmd = NL802154_CMD_SET_MAX_CSMA_BACKOFFS,
2276                .doit = nl802154_set_max_csma_backoffs,
2277                .policy = nl802154_policy,
2278                .flags = GENL_ADMIN_PERM,
2279                .internal_flags = NL802154_FLAG_NEED_NETDEV |
2280                                  NL802154_FLAG_NEED_RTNL,
2281        },
2282        {
2283                .cmd = NL802154_CMD_SET_MAX_FRAME_RETRIES,
2284                .doit = nl802154_set_max_frame_retries,
2285                .policy = nl802154_policy,
2286                .flags = GENL_ADMIN_PERM,
2287                .internal_flags = NL802154_FLAG_NEED_NETDEV |
2288                                  NL802154_FLAG_NEED_RTNL,
2289        },
2290        {
2291                .cmd = NL802154_CMD_SET_LBT_MODE,
2292                .doit = nl802154_set_lbt_mode,
2293                .policy = nl802154_policy,
2294                .flags = GENL_ADMIN_PERM,
2295                .internal_flags = NL802154_FLAG_NEED_NETDEV |
2296                                  NL802154_FLAG_NEED_RTNL,
2297        },
2298        {
2299                .cmd = NL802154_CMD_SET_ACKREQ_DEFAULT,
2300                .doit = nl802154_set_ackreq_default,
2301                .policy = nl802154_policy,
2302                .flags = GENL_ADMIN_PERM,
2303                .internal_flags = NL802154_FLAG_NEED_NETDEV |
2304                                  NL802154_FLAG_NEED_RTNL,
2305        },
2306#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
2307        {
2308                .cmd = NL802154_CMD_SET_SEC_PARAMS,
2309                .doit = nl802154_set_llsec_params,
2310                .policy = nl802154_policy,
2311                .flags = GENL_ADMIN_PERM,
2312                .internal_flags = NL802154_FLAG_NEED_NETDEV |
2313                                  NL802154_FLAG_NEED_RTNL,
2314        },
2315        {
2316                .cmd = NL802154_CMD_GET_SEC_KEY,
2317                /* TODO .doit by matching key id? */
2318                .dumpit = nl802154_dump_llsec_key,
2319                .policy = nl802154_policy,
2320                .flags = GENL_ADMIN_PERM,
2321                .internal_flags = NL802154_FLAG_NEED_NETDEV |
2322                                  NL802154_FLAG_NEED_RTNL,
2323        },
2324        {
2325                .cmd = NL802154_CMD_NEW_SEC_KEY,
2326                .doit = nl802154_add_llsec_key,
2327                .policy = nl802154_policy,
2328                .flags = GENL_ADMIN_PERM,
2329                .internal_flags = NL802154_FLAG_NEED_NETDEV |
2330                                  NL802154_FLAG_NEED_RTNL,
2331        },
2332        {
2333                .cmd = NL802154_CMD_DEL_SEC_KEY,
2334                .doit = nl802154_del_llsec_key,
2335                .policy = nl802154_policy,
2336                .flags = GENL_ADMIN_PERM,
2337                .internal_flags = NL802154_FLAG_NEED_NETDEV |
2338                                  NL802154_FLAG_NEED_RTNL,
2339        },
2340        /* TODO unique identifier must short+pan OR extended_addr */
2341        {
2342                .cmd = NL802154_CMD_GET_SEC_DEV,
2343                /* TODO .doit by matching extended_addr? */
2344                .dumpit = nl802154_dump_llsec_dev,
2345                .policy = nl802154_policy,
2346                .flags = GENL_ADMIN_PERM,
2347                .internal_flags = NL802154_FLAG_NEED_NETDEV |
2348                                  NL802154_FLAG_NEED_RTNL,
2349        },
2350        {
2351                .cmd = NL802154_CMD_NEW_SEC_DEV,
2352                .doit = nl802154_add_llsec_dev,
2353                .policy = nl802154_policy,
2354                .flags = GENL_ADMIN_PERM,
2355                .internal_flags = NL802154_FLAG_NEED_NETDEV |
2356                                  NL802154_FLAG_NEED_RTNL,
2357        },
2358        {
2359                .cmd = NL802154_CMD_DEL_SEC_DEV,
2360                .doit = nl802154_del_llsec_dev,
2361                .policy = nl802154_policy,
2362                .flags = GENL_ADMIN_PERM,
2363                .internal_flags = NL802154_FLAG_NEED_NETDEV |
2364                                  NL802154_FLAG_NEED_RTNL,
2365        },
2366        /* TODO remove complete devkey, put it as nested? */
2367        {
2368                .cmd = NL802154_CMD_GET_SEC_DEVKEY,
2369                /* TODO doit by matching ??? */
2370                .dumpit = nl802154_dump_llsec_devkey,
2371                .policy = nl802154_policy,
2372                .flags = GENL_ADMIN_PERM,
2373                .internal_flags = NL802154_FLAG_NEED_NETDEV |
2374                                  NL802154_FLAG_NEED_RTNL,
2375        },
2376        {
2377                .cmd = NL802154_CMD_NEW_SEC_DEVKEY,
2378                .doit = nl802154_add_llsec_devkey,
2379                .policy = nl802154_policy,
2380                .flags = GENL_ADMIN_PERM,
2381                .internal_flags = NL802154_FLAG_NEED_NETDEV |
2382                                  NL802154_FLAG_NEED_RTNL,
2383        },
2384        {
2385                .cmd = NL802154_CMD_DEL_SEC_DEVKEY,
2386                .doit = nl802154_del_llsec_devkey,
2387                .policy = nl802154_policy,
2388                .flags = GENL_ADMIN_PERM,
2389                .internal_flags = NL802154_FLAG_NEED_NETDEV |
2390                                  NL802154_FLAG_NEED_RTNL,
2391        },
2392        {
2393                .cmd = NL802154_CMD_GET_SEC_LEVEL,
2394                /* TODO .doit by matching frame_type? */
2395                .dumpit = nl802154_dump_llsec_seclevel,
2396                .policy = nl802154_policy,
2397                .flags = GENL_ADMIN_PERM,
2398                .internal_flags = NL802154_FLAG_NEED_NETDEV |
2399                                  NL802154_FLAG_NEED_RTNL,
2400        },
2401        {
2402                .cmd = NL802154_CMD_NEW_SEC_LEVEL,
2403                .doit = nl802154_add_llsec_seclevel,
2404                .policy = nl802154_policy,
2405                .flags = GENL_ADMIN_PERM,
2406                .internal_flags = NL802154_FLAG_NEED_NETDEV |
2407                                  NL802154_FLAG_NEED_RTNL,
2408        },
2409        {
2410                .cmd = NL802154_CMD_DEL_SEC_LEVEL,
2411                /* TODO match frame_type only? */
2412                .doit = nl802154_del_llsec_seclevel,
2413                .policy = nl802154_policy,
2414                .flags = GENL_ADMIN_PERM,
2415                .internal_flags = NL802154_FLAG_NEED_NETDEV |
2416                                  NL802154_FLAG_NEED_RTNL,
2417        },
2418#endif /* CONFIG_IEEE802154_NL802154_EXPERIMENTAL */
2419};
2420
2421/* initialisation/exit functions */
2422int nl802154_init(void)
2423{
2424        return genl_register_family_with_ops_groups(&nl802154_fam, nl802154_ops,
2425                                                    nl802154_mcgrps);
2426}
2427
2428void nl802154_exit(void)
2429{
2430        genl_unregister_family(&nl802154_fam);
2431}
2432