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