cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

nl802154.c (70060B)


      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 (wpan_dev->iftype == NL802154_IFTYPE_MONITOR)
    824		goto out;
    825
    826	if (nl802154_get_llsec_params(msg, rdev, wpan_dev) < 0)
    827		goto nla_put_failure;
    828
    829out:
    830#endif /* CONFIG_IEEE802154_NL802154_EXPERIMENTAL */
    831
    832	genlmsg_end(msg, hdr);
    833	return 0;
    834
    835nla_put_failure:
    836	genlmsg_cancel(msg, hdr);
    837	return -EMSGSIZE;
    838}
    839
    840static int
    841nl802154_dump_interface(struct sk_buff *skb, struct netlink_callback *cb)
    842{
    843	int wp_idx = 0;
    844	int if_idx = 0;
    845	int wp_start = cb->args[0];
    846	int if_start = cb->args[1];
    847	struct cfg802154_registered_device *rdev;
    848	struct wpan_dev *wpan_dev;
    849
    850	rtnl_lock();
    851	list_for_each_entry(rdev, &cfg802154_rdev_list, list) {
    852		if (!net_eq(wpan_phy_net(&rdev->wpan_phy), sock_net(skb->sk)))
    853			continue;
    854		if (wp_idx < wp_start) {
    855			wp_idx++;
    856			continue;
    857		}
    858		if_idx = 0;
    859
    860		list_for_each_entry(wpan_dev, &rdev->wpan_dev_list, list) {
    861			if (if_idx < if_start) {
    862				if_idx++;
    863				continue;
    864			}
    865			if (nl802154_send_iface(skb, NETLINK_CB(cb->skb).portid,
    866						cb->nlh->nlmsg_seq, NLM_F_MULTI,
    867						rdev, wpan_dev) < 0) {
    868				goto out;
    869			}
    870			if_idx++;
    871		}
    872
    873		wp_idx++;
    874	}
    875out:
    876	rtnl_unlock();
    877
    878	cb->args[0] = wp_idx;
    879	cb->args[1] = if_idx;
    880
    881	return skb->len;
    882}
    883
    884static int nl802154_get_interface(struct sk_buff *skb, struct genl_info *info)
    885{
    886	struct sk_buff *msg;
    887	struct cfg802154_registered_device *rdev = info->user_ptr[0];
    888	struct wpan_dev *wdev = info->user_ptr[1];
    889
    890	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
    891	if (!msg)
    892		return -ENOMEM;
    893
    894	if (nl802154_send_iface(msg, info->snd_portid, info->snd_seq, 0,
    895				rdev, wdev) < 0) {
    896		nlmsg_free(msg);
    897		return -ENOBUFS;
    898	}
    899
    900	return genlmsg_reply(msg, info);
    901}
    902
    903static int nl802154_new_interface(struct sk_buff *skb, struct genl_info *info)
    904{
    905	struct cfg802154_registered_device *rdev = info->user_ptr[0];
    906	enum nl802154_iftype type = NL802154_IFTYPE_UNSPEC;
    907	__le64 extended_addr = cpu_to_le64(0x0000000000000000ULL);
    908
    909	/* TODO avoid failing a new interface
    910	 * creation due to pending removal?
    911	 */
    912
    913	if (!info->attrs[NL802154_ATTR_IFNAME])
    914		return -EINVAL;
    915
    916	if (info->attrs[NL802154_ATTR_IFTYPE]) {
    917		type = nla_get_u32(info->attrs[NL802154_ATTR_IFTYPE]);
    918		if (type > NL802154_IFTYPE_MAX ||
    919		    !(rdev->wpan_phy.supported.iftypes & BIT(type)))
    920			return -EINVAL;
    921	}
    922
    923	if (info->attrs[NL802154_ATTR_EXTENDED_ADDR])
    924		extended_addr = nla_get_le64(info->attrs[NL802154_ATTR_EXTENDED_ADDR]);
    925
    926	if (!rdev->ops->add_virtual_intf)
    927		return -EOPNOTSUPP;
    928
    929	return rdev_add_virtual_intf(rdev,
    930				     nla_data(info->attrs[NL802154_ATTR_IFNAME]),
    931				     NET_NAME_USER, type, extended_addr);
    932}
    933
    934static int nl802154_del_interface(struct sk_buff *skb, struct genl_info *info)
    935{
    936	struct cfg802154_registered_device *rdev = info->user_ptr[0];
    937	struct wpan_dev *wpan_dev = info->user_ptr[1];
    938
    939	if (!rdev->ops->del_virtual_intf)
    940		return -EOPNOTSUPP;
    941
    942	/* If we remove a wpan device without a netdev then clear
    943	 * user_ptr[1] so that nl802154_post_doit won't dereference it
    944	 * to check if it needs to do dev_put(). Otherwise it crashes
    945	 * since the wpan_dev has been freed, unlike with a netdev where
    946	 * we need the dev_put() for the netdev to really be freed.
    947	 */
    948	if (!wpan_dev->netdev)
    949		info->user_ptr[1] = NULL;
    950
    951	return rdev_del_virtual_intf(rdev, wpan_dev);
    952}
    953
    954static int nl802154_set_channel(struct sk_buff *skb, struct genl_info *info)
    955{
    956	struct cfg802154_registered_device *rdev = info->user_ptr[0];
    957	u8 channel, page;
    958
    959	if (!info->attrs[NL802154_ATTR_PAGE] ||
    960	    !info->attrs[NL802154_ATTR_CHANNEL])
    961		return -EINVAL;
    962
    963	page = nla_get_u8(info->attrs[NL802154_ATTR_PAGE]);
    964	channel = nla_get_u8(info->attrs[NL802154_ATTR_CHANNEL]);
    965
    966	/* check 802.15.4 constraints */
    967	if (page > IEEE802154_MAX_PAGE || channel > IEEE802154_MAX_CHANNEL ||
    968	    !(rdev->wpan_phy.supported.channels[page] & BIT(channel)))
    969		return -EINVAL;
    970
    971	return rdev_set_channel(rdev, page, channel);
    972}
    973
    974static int nl802154_set_cca_mode(struct sk_buff *skb, struct genl_info *info)
    975{
    976	struct cfg802154_registered_device *rdev = info->user_ptr[0];
    977	struct wpan_phy_cca cca;
    978
    979	if (!(rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_MODE))
    980		return -EOPNOTSUPP;
    981
    982	if (!info->attrs[NL802154_ATTR_CCA_MODE])
    983		return -EINVAL;
    984
    985	cca.mode = nla_get_u32(info->attrs[NL802154_ATTR_CCA_MODE]);
    986	/* checking 802.15.4 constraints */
    987	if (cca.mode < NL802154_CCA_ENERGY ||
    988	    cca.mode > NL802154_CCA_ATTR_MAX ||
    989	    !(rdev->wpan_phy.supported.cca_modes & BIT(cca.mode)))
    990		return -EINVAL;
    991
    992	if (cca.mode == NL802154_CCA_ENERGY_CARRIER) {
    993		if (!info->attrs[NL802154_ATTR_CCA_OPT])
    994			return -EINVAL;
    995
    996		cca.opt = nla_get_u32(info->attrs[NL802154_ATTR_CCA_OPT]);
    997		if (cca.opt > NL802154_CCA_OPT_ATTR_MAX ||
    998		    !(rdev->wpan_phy.supported.cca_opts & BIT(cca.opt)))
    999			return -EINVAL;
   1000	}
   1001
   1002	return rdev_set_cca_mode(rdev, &cca);
   1003}
   1004
   1005static int nl802154_set_cca_ed_level(struct sk_buff *skb, struct genl_info *info)
   1006{
   1007	struct cfg802154_registered_device *rdev = info->user_ptr[0];
   1008	s32 ed_level;
   1009	int i;
   1010
   1011	if (!(rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_ED_LEVEL))
   1012		return -EOPNOTSUPP;
   1013
   1014	if (!info->attrs[NL802154_ATTR_CCA_ED_LEVEL])
   1015		return -EINVAL;
   1016
   1017	ed_level = nla_get_s32(info->attrs[NL802154_ATTR_CCA_ED_LEVEL]);
   1018
   1019	for (i = 0; i < rdev->wpan_phy.supported.cca_ed_levels_size; i++) {
   1020		if (ed_level == rdev->wpan_phy.supported.cca_ed_levels[i])
   1021			return rdev_set_cca_ed_level(rdev, ed_level);
   1022	}
   1023
   1024	return -EINVAL;
   1025}
   1026
   1027static int nl802154_set_tx_power(struct sk_buff *skb, struct genl_info *info)
   1028{
   1029	struct cfg802154_registered_device *rdev = info->user_ptr[0];
   1030	s32 power;
   1031	int i;
   1032
   1033	if (!(rdev->wpan_phy.flags & WPAN_PHY_FLAG_TXPOWER))
   1034		return -EOPNOTSUPP;
   1035
   1036	if (!info->attrs[NL802154_ATTR_TX_POWER])
   1037		return -EINVAL;
   1038
   1039	power = nla_get_s32(info->attrs[NL802154_ATTR_TX_POWER]);
   1040
   1041	for (i = 0; i < rdev->wpan_phy.supported.tx_powers_size; i++) {
   1042		if (power == rdev->wpan_phy.supported.tx_powers[i])
   1043			return rdev_set_tx_power(rdev, power);
   1044	}
   1045
   1046	return -EINVAL;
   1047}
   1048
   1049static int nl802154_set_pan_id(struct sk_buff *skb, struct genl_info *info)
   1050{
   1051	struct cfg802154_registered_device *rdev = info->user_ptr[0];
   1052	struct net_device *dev = info->user_ptr[1];
   1053	struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
   1054	__le16 pan_id;
   1055
   1056	/* conflict here while tx/rx calls */
   1057	if (netif_running(dev))
   1058		return -EBUSY;
   1059
   1060	if (wpan_dev->lowpan_dev) {
   1061		if (netif_running(wpan_dev->lowpan_dev))
   1062			return -EBUSY;
   1063	}
   1064
   1065	/* don't change address fields on monitor */
   1066	if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR ||
   1067	    !info->attrs[NL802154_ATTR_PAN_ID])
   1068		return -EINVAL;
   1069
   1070	pan_id = nla_get_le16(info->attrs[NL802154_ATTR_PAN_ID]);
   1071
   1072	/* TODO
   1073	 * I am not sure about to check here on broadcast pan_id.
   1074	 * Broadcast is a valid setting, comment from 802.15.4:
   1075	 * If this value is 0xffff, the device is not associated.
   1076	 *
   1077	 * This could useful to simple deassociate an device.
   1078	 */
   1079	if (pan_id == cpu_to_le16(IEEE802154_PAN_ID_BROADCAST))
   1080		return -EINVAL;
   1081
   1082	return rdev_set_pan_id(rdev, wpan_dev, pan_id);
   1083}
   1084
   1085static int nl802154_set_short_addr(struct sk_buff *skb, struct genl_info *info)
   1086{
   1087	struct cfg802154_registered_device *rdev = info->user_ptr[0];
   1088	struct net_device *dev = info->user_ptr[1];
   1089	struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
   1090	__le16 short_addr;
   1091
   1092	/* conflict here while tx/rx calls */
   1093	if (netif_running(dev))
   1094		return -EBUSY;
   1095
   1096	if (wpan_dev->lowpan_dev) {
   1097		if (netif_running(wpan_dev->lowpan_dev))
   1098			return -EBUSY;
   1099	}
   1100
   1101	/* don't change address fields on monitor */
   1102	if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR ||
   1103	    !info->attrs[NL802154_ATTR_SHORT_ADDR])
   1104		return -EINVAL;
   1105
   1106	short_addr = nla_get_le16(info->attrs[NL802154_ATTR_SHORT_ADDR]);
   1107
   1108	/* TODO
   1109	 * I am not sure about to check here on broadcast short_addr.
   1110	 * Broadcast is a valid setting, comment from 802.15.4:
   1111	 * A value of 0xfffe indicates that the device has
   1112	 * associated but has not been allocated an address. A
   1113	 * value of 0xffff indicates that the device does not
   1114	 * have a short address.
   1115	 *
   1116	 * I think we should allow to set these settings but
   1117	 * don't allow to allow socket communication with it.
   1118	 */
   1119	if (short_addr == cpu_to_le16(IEEE802154_ADDR_SHORT_UNSPEC) ||
   1120	    short_addr == cpu_to_le16(IEEE802154_ADDR_SHORT_BROADCAST))
   1121		return -EINVAL;
   1122
   1123	return rdev_set_short_addr(rdev, wpan_dev, short_addr);
   1124}
   1125
   1126static int
   1127nl802154_set_backoff_exponent(struct sk_buff *skb, struct genl_info *info)
   1128{
   1129	struct cfg802154_registered_device *rdev = info->user_ptr[0];
   1130	struct net_device *dev = info->user_ptr[1];
   1131	struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
   1132	u8 min_be, max_be;
   1133
   1134	/* should be set on netif open inside phy settings */
   1135	if (netif_running(dev))
   1136		return -EBUSY;
   1137
   1138	if (!info->attrs[NL802154_ATTR_MIN_BE] ||
   1139	    !info->attrs[NL802154_ATTR_MAX_BE])
   1140		return -EINVAL;
   1141
   1142	min_be = nla_get_u8(info->attrs[NL802154_ATTR_MIN_BE]);
   1143	max_be = nla_get_u8(info->attrs[NL802154_ATTR_MAX_BE]);
   1144
   1145	/* check 802.15.4 constraints */
   1146	if (min_be < rdev->wpan_phy.supported.min_minbe ||
   1147	    min_be > rdev->wpan_phy.supported.max_minbe ||
   1148	    max_be < rdev->wpan_phy.supported.min_maxbe ||
   1149	    max_be > rdev->wpan_phy.supported.max_maxbe ||
   1150	    min_be > max_be)
   1151		return -EINVAL;
   1152
   1153	return rdev_set_backoff_exponent(rdev, wpan_dev, min_be, max_be);
   1154}
   1155
   1156static int
   1157nl802154_set_max_csma_backoffs(struct sk_buff *skb, struct genl_info *info)
   1158{
   1159	struct cfg802154_registered_device *rdev = info->user_ptr[0];
   1160	struct net_device *dev = info->user_ptr[1];
   1161	struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
   1162	u8 max_csma_backoffs;
   1163
   1164	/* conflict here while other running iface settings */
   1165	if (netif_running(dev))
   1166		return -EBUSY;
   1167
   1168	if (!info->attrs[NL802154_ATTR_MAX_CSMA_BACKOFFS])
   1169		return -EINVAL;
   1170
   1171	max_csma_backoffs = nla_get_u8(
   1172			info->attrs[NL802154_ATTR_MAX_CSMA_BACKOFFS]);
   1173
   1174	/* check 802.15.4 constraints */
   1175	if (max_csma_backoffs < rdev->wpan_phy.supported.min_csma_backoffs ||
   1176	    max_csma_backoffs > rdev->wpan_phy.supported.max_csma_backoffs)
   1177		return -EINVAL;
   1178
   1179	return rdev_set_max_csma_backoffs(rdev, wpan_dev, max_csma_backoffs);
   1180}
   1181
   1182static int
   1183nl802154_set_max_frame_retries(struct sk_buff *skb, struct genl_info *info)
   1184{
   1185	struct cfg802154_registered_device *rdev = info->user_ptr[0];
   1186	struct net_device *dev = info->user_ptr[1];
   1187	struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
   1188	s8 max_frame_retries;
   1189
   1190	if (netif_running(dev))
   1191		return -EBUSY;
   1192
   1193	if (!info->attrs[NL802154_ATTR_MAX_FRAME_RETRIES])
   1194		return -EINVAL;
   1195
   1196	max_frame_retries = nla_get_s8(
   1197			info->attrs[NL802154_ATTR_MAX_FRAME_RETRIES]);
   1198
   1199	/* check 802.15.4 constraints */
   1200	if (max_frame_retries < rdev->wpan_phy.supported.min_frame_retries ||
   1201	    max_frame_retries > rdev->wpan_phy.supported.max_frame_retries)
   1202		return -EINVAL;
   1203
   1204	return rdev_set_max_frame_retries(rdev, wpan_dev, max_frame_retries);
   1205}
   1206
   1207static int nl802154_set_lbt_mode(struct sk_buff *skb, struct genl_info *info)
   1208{
   1209	struct cfg802154_registered_device *rdev = info->user_ptr[0];
   1210	struct net_device *dev = info->user_ptr[1];
   1211	struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
   1212	int mode;
   1213
   1214	if (netif_running(dev))
   1215		return -EBUSY;
   1216
   1217	if (!info->attrs[NL802154_ATTR_LBT_MODE])
   1218		return -EINVAL;
   1219
   1220	mode = nla_get_u8(info->attrs[NL802154_ATTR_LBT_MODE]);
   1221
   1222	if (mode != 0 && mode != 1)
   1223		return -EINVAL;
   1224
   1225	if (!wpan_phy_supported_bool(mode, rdev->wpan_phy.supported.lbt))
   1226		return -EINVAL;
   1227
   1228	return rdev_set_lbt_mode(rdev, wpan_dev, mode);
   1229}
   1230
   1231static int
   1232nl802154_set_ackreq_default(struct sk_buff *skb, struct genl_info *info)
   1233{
   1234	struct cfg802154_registered_device *rdev = info->user_ptr[0];
   1235	struct net_device *dev = info->user_ptr[1];
   1236	struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
   1237	int ackreq;
   1238
   1239	if (netif_running(dev))
   1240		return -EBUSY;
   1241
   1242	if (!info->attrs[NL802154_ATTR_ACKREQ_DEFAULT])
   1243		return -EINVAL;
   1244
   1245	ackreq = nla_get_u8(info->attrs[NL802154_ATTR_ACKREQ_DEFAULT]);
   1246
   1247	if (ackreq != 0 && ackreq != 1)
   1248		return -EINVAL;
   1249
   1250	return rdev_set_ackreq_default(rdev, wpan_dev, ackreq);
   1251}
   1252
   1253static int nl802154_wpan_phy_netns(struct sk_buff *skb, struct genl_info *info)
   1254{
   1255	struct cfg802154_registered_device *rdev = info->user_ptr[0];
   1256	struct net *net;
   1257	int err;
   1258
   1259	if (info->attrs[NL802154_ATTR_PID]) {
   1260		u32 pid = nla_get_u32(info->attrs[NL802154_ATTR_PID]);
   1261
   1262		net = get_net_ns_by_pid(pid);
   1263	} else if (info->attrs[NL802154_ATTR_NETNS_FD]) {
   1264		u32 fd = nla_get_u32(info->attrs[NL802154_ATTR_NETNS_FD]);
   1265
   1266		net = get_net_ns_by_fd(fd);
   1267	} else {
   1268		return -EINVAL;
   1269	}
   1270
   1271	if (IS_ERR(net))
   1272		return PTR_ERR(net);
   1273
   1274	err = 0;
   1275
   1276	/* check if anything to do */
   1277	if (!net_eq(wpan_phy_net(&rdev->wpan_phy), net))
   1278		err = cfg802154_switch_netns(rdev, net);
   1279
   1280	put_net(net);
   1281	return err;
   1282}
   1283
   1284#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
   1285static const struct nla_policy nl802154_dev_addr_policy[NL802154_DEV_ADDR_ATTR_MAX + 1] = {
   1286	[NL802154_DEV_ADDR_ATTR_PAN_ID] = { .type = NLA_U16 },
   1287	[NL802154_DEV_ADDR_ATTR_MODE] = { .type = NLA_U32 },
   1288	[NL802154_DEV_ADDR_ATTR_SHORT] = { .type = NLA_U16 },
   1289	[NL802154_DEV_ADDR_ATTR_EXTENDED] = { .type = NLA_U64 },
   1290};
   1291
   1292static int
   1293ieee802154_llsec_parse_dev_addr(struct nlattr *nla,
   1294				struct ieee802154_addr *addr)
   1295{
   1296	struct nlattr *attrs[NL802154_DEV_ADDR_ATTR_MAX + 1];
   1297
   1298	if (!nla || nla_parse_nested_deprecated(attrs, NL802154_DEV_ADDR_ATTR_MAX, nla, nl802154_dev_addr_policy, NULL))
   1299		return -EINVAL;
   1300
   1301	if (!attrs[NL802154_DEV_ADDR_ATTR_PAN_ID] || !attrs[NL802154_DEV_ADDR_ATTR_MODE])
   1302		return -EINVAL;
   1303
   1304	addr->pan_id = nla_get_le16(attrs[NL802154_DEV_ADDR_ATTR_PAN_ID]);
   1305	addr->mode = nla_get_u32(attrs[NL802154_DEV_ADDR_ATTR_MODE]);
   1306	switch (addr->mode) {
   1307	case NL802154_DEV_ADDR_SHORT:
   1308		if (!attrs[NL802154_DEV_ADDR_ATTR_SHORT])
   1309			return -EINVAL;
   1310		addr->short_addr = nla_get_le16(attrs[NL802154_DEV_ADDR_ATTR_SHORT]);
   1311		break;
   1312	case NL802154_DEV_ADDR_EXTENDED:
   1313		if (!attrs[NL802154_DEV_ADDR_ATTR_EXTENDED])
   1314			return -EINVAL;
   1315		addr->extended_addr = nla_get_le64(attrs[NL802154_DEV_ADDR_ATTR_EXTENDED]);
   1316		break;
   1317	default:
   1318		return -EINVAL;
   1319	}
   1320
   1321	return 0;
   1322}
   1323
   1324static const struct nla_policy nl802154_key_id_policy[NL802154_KEY_ID_ATTR_MAX + 1] = {
   1325	[NL802154_KEY_ID_ATTR_MODE] = { .type = NLA_U32 },
   1326	[NL802154_KEY_ID_ATTR_INDEX] = { .type = NLA_U8 },
   1327	[NL802154_KEY_ID_ATTR_IMPLICIT] = { .type = NLA_NESTED },
   1328	[NL802154_KEY_ID_ATTR_SOURCE_SHORT] = { .type = NLA_U32 },
   1329	[NL802154_KEY_ID_ATTR_SOURCE_EXTENDED] = { .type = NLA_U64 },
   1330};
   1331
   1332static int
   1333ieee802154_llsec_parse_key_id(struct nlattr *nla,
   1334			      struct ieee802154_llsec_key_id *desc)
   1335{
   1336	struct nlattr *attrs[NL802154_KEY_ID_ATTR_MAX + 1];
   1337
   1338	if (!nla || nla_parse_nested_deprecated(attrs, NL802154_KEY_ID_ATTR_MAX, nla, nl802154_key_id_policy, NULL))
   1339		return -EINVAL;
   1340
   1341	if (!attrs[NL802154_KEY_ID_ATTR_MODE])
   1342		return -EINVAL;
   1343
   1344	desc->mode = nla_get_u32(attrs[NL802154_KEY_ID_ATTR_MODE]);
   1345	switch (desc->mode) {
   1346	case NL802154_KEY_ID_MODE_IMPLICIT:
   1347		if (!attrs[NL802154_KEY_ID_ATTR_IMPLICIT])
   1348			return -EINVAL;
   1349
   1350		if (ieee802154_llsec_parse_dev_addr(attrs[NL802154_KEY_ID_ATTR_IMPLICIT],
   1351						    &desc->device_addr) < 0)
   1352			return -EINVAL;
   1353		break;
   1354	case NL802154_KEY_ID_MODE_INDEX:
   1355		break;
   1356	case NL802154_KEY_ID_MODE_INDEX_SHORT:
   1357		if (!attrs[NL802154_KEY_ID_ATTR_SOURCE_SHORT])
   1358			return -EINVAL;
   1359
   1360		desc->short_source = nla_get_le32(attrs[NL802154_KEY_ID_ATTR_SOURCE_SHORT]);
   1361		break;
   1362	case NL802154_KEY_ID_MODE_INDEX_EXTENDED:
   1363		if (!attrs[NL802154_KEY_ID_ATTR_SOURCE_EXTENDED])
   1364			return -EINVAL;
   1365
   1366		desc->extended_source = nla_get_le64(attrs[NL802154_KEY_ID_ATTR_SOURCE_EXTENDED]);
   1367		break;
   1368	default:
   1369		return -EINVAL;
   1370	}
   1371
   1372	if (desc->mode != NL802154_KEY_ID_MODE_IMPLICIT) {
   1373		if (!attrs[NL802154_KEY_ID_ATTR_INDEX])
   1374			return -EINVAL;
   1375
   1376		/* TODO change id to idx */
   1377		desc->id = nla_get_u8(attrs[NL802154_KEY_ID_ATTR_INDEX]);
   1378	}
   1379
   1380	return 0;
   1381}
   1382
   1383static int nl802154_set_llsec_params(struct sk_buff *skb,
   1384				     struct genl_info *info)
   1385{
   1386	struct cfg802154_registered_device *rdev = info->user_ptr[0];
   1387	struct net_device *dev = info->user_ptr[1];
   1388	struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
   1389	struct ieee802154_llsec_params params;
   1390	u32 changed = 0;
   1391	int ret;
   1392
   1393	if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR)
   1394		return -EOPNOTSUPP;
   1395
   1396	if (info->attrs[NL802154_ATTR_SEC_ENABLED]) {
   1397		u8 enabled;
   1398
   1399		enabled = nla_get_u8(info->attrs[NL802154_ATTR_SEC_ENABLED]);
   1400		if (enabled != 0 && enabled != 1)
   1401			return -EINVAL;
   1402
   1403		params.enabled = nla_get_u8(info->attrs[NL802154_ATTR_SEC_ENABLED]);
   1404		changed |= IEEE802154_LLSEC_PARAM_ENABLED;
   1405	}
   1406
   1407	if (info->attrs[NL802154_ATTR_SEC_OUT_KEY_ID]) {
   1408		ret = ieee802154_llsec_parse_key_id(info->attrs[NL802154_ATTR_SEC_OUT_KEY_ID],
   1409						    &params.out_key);
   1410		if (ret < 0)
   1411			return ret;
   1412
   1413		changed |= IEEE802154_LLSEC_PARAM_OUT_KEY;
   1414	}
   1415
   1416	if (info->attrs[NL802154_ATTR_SEC_OUT_LEVEL]) {
   1417		params.out_level = nla_get_u32(info->attrs[NL802154_ATTR_SEC_OUT_LEVEL]);
   1418		if (params.out_level > NL802154_SECLEVEL_MAX)
   1419			return -EINVAL;
   1420
   1421		changed |= IEEE802154_LLSEC_PARAM_OUT_LEVEL;
   1422	}
   1423
   1424	if (info->attrs[NL802154_ATTR_SEC_FRAME_COUNTER]) {
   1425		params.frame_counter = nla_get_be32(info->attrs[NL802154_ATTR_SEC_FRAME_COUNTER]);
   1426		changed |= IEEE802154_LLSEC_PARAM_FRAME_COUNTER;
   1427	}
   1428
   1429	return rdev_set_llsec_params(rdev, wpan_dev, &params, changed);
   1430}
   1431
   1432static int nl802154_send_key(struct sk_buff *msg, u32 cmd, u32 portid,
   1433			     u32 seq, int flags,
   1434			     struct cfg802154_registered_device *rdev,
   1435			     struct net_device *dev,
   1436			     const struct ieee802154_llsec_key_entry *key)
   1437{
   1438	void *hdr;
   1439	u32 commands[NL802154_CMD_FRAME_NR_IDS / 32];
   1440	struct nlattr *nl_key, *nl_key_id;
   1441
   1442	hdr = nl802154hdr_put(msg, portid, seq, flags, cmd);
   1443	if (!hdr)
   1444		return -ENOBUFS;
   1445
   1446	if (nla_put_u32(msg, NL802154_ATTR_IFINDEX, dev->ifindex))
   1447		goto nla_put_failure;
   1448
   1449	nl_key = nla_nest_start_noflag(msg, NL802154_ATTR_SEC_KEY);
   1450	if (!nl_key)
   1451		goto nla_put_failure;
   1452
   1453	nl_key_id = nla_nest_start_noflag(msg, NL802154_KEY_ATTR_ID);
   1454	if (!nl_key_id)
   1455		goto nla_put_failure;
   1456
   1457	if (ieee802154_llsec_send_key_id(msg, &key->id) < 0)
   1458		goto nla_put_failure;
   1459
   1460	nla_nest_end(msg, nl_key_id);
   1461
   1462	if (nla_put_u8(msg, NL802154_KEY_ATTR_USAGE_FRAMES,
   1463		       key->key->frame_types))
   1464		goto nla_put_failure;
   1465
   1466	if (key->key->frame_types & BIT(NL802154_FRAME_CMD)) {
   1467		/* TODO for each nested */
   1468		memset(commands, 0, sizeof(commands));
   1469		commands[7] = key->key->cmd_frame_ids;
   1470		if (nla_put(msg, NL802154_KEY_ATTR_USAGE_CMDS,
   1471			    sizeof(commands), commands))
   1472			goto nla_put_failure;
   1473	}
   1474
   1475	if (nla_put(msg, NL802154_KEY_ATTR_BYTES, NL802154_KEY_SIZE,
   1476		    key->key->key))
   1477		goto nla_put_failure;
   1478
   1479	nla_nest_end(msg, nl_key);
   1480	genlmsg_end(msg, hdr);
   1481
   1482	return 0;
   1483
   1484nla_put_failure:
   1485	genlmsg_cancel(msg, hdr);
   1486	return -EMSGSIZE;
   1487}
   1488
   1489static int
   1490nl802154_dump_llsec_key(struct sk_buff *skb, struct netlink_callback *cb)
   1491{
   1492	struct cfg802154_registered_device *rdev = NULL;
   1493	struct ieee802154_llsec_key_entry *key;
   1494	struct ieee802154_llsec_table *table;
   1495	struct wpan_dev *wpan_dev;
   1496	int err;
   1497
   1498	err = nl802154_prepare_wpan_dev_dump(skb, cb, &rdev, &wpan_dev);
   1499	if (err)
   1500		return err;
   1501
   1502	if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR) {
   1503		err = skb->len;
   1504		goto out_err;
   1505	}
   1506
   1507	if (!wpan_dev->netdev) {
   1508		err = -EINVAL;
   1509		goto out_err;
   1510	}
   1511
   1512	rdev_lock_llsec_table(rdev, wpan_dev);
   1513	rdev_get_llsec_table(rdev, wpan_dev, &table);
   1514
   1515	/* TODO make it like station dump */
   1516	if (cb->args[2])
   1517		goto out;
   1518
   1519	list_for_each_entry(key, &table->keys, list) {
   1520		if (nl802154_send_key(skb, NL802154_CMD_NEW_SEC_KEY,
   1521				      NETLINK_CB(cb->skb).portid,
   1522				      cb->nlh->nlmsg_seq, NLM_F_MULTI,
   1523				      rdev, wpan_dev->netdev, key) < 0) {
   1524			/* TODO */
   1525			err = -EIO;
   1526			rdev_unlock_llsec_table(rdev, wpan_dev);
   1527			goto out_err;
   1528		}
   1529	}
   1530
   1531	cb->args[2] = 1;
   1532
   1533out:
   1534	rdev_unlock_llsec_table(rdev, wpan_dev);
   1535	err = skb->len;
   1536out_err:
   1537	nl802154_finish_wpan_dev_dump(rdev);
   1538
   1539	return err;
   1540}
   1541
   1542static const struct nla_policy nl802154_key_policy[NL802154_KEY_ATTR_MAX + 1] = {
   1543	[NL802154_KEY_ATTR_ID] = { NLA_NESTED },
   1544	/* TODO handle it as for_each_nested and NLA_FLAG? */
   1545	[NL802154_KEY_ATTR_USAGE_FRAMES] = { NLA_U8 },
   1546	/* TODO handle it as for_each_nested, not static array? */
   1547	[NL802154_KEY_ATTR_USAGE_CMDS] = { .len = NL802154_CMD_FRAME_NR_IDS / 8 },
   1548	[NL802154_KEY_ATTR_BYTES] = { .len = NL802154_KEY_SIZE },
   1549};
   1550
   1551static int nl802154_add_llsec_key(struct sk_buff *skb, struct genl_info *info)
   1552{
   1553	struct cfg802154_registered_device *rdev = info->user_ptr[0];
   1554	struct net_device *dev = info->user_ptr[1];
   1555	struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
   1556	struct nlattr *attrs[NL802154_KEY_ATTR_MAX + 1];
   1557	struct ieee802154_llsec_key key = { };
   1558	struct ieee802154_llsec_key_id id = { };
   1559	u32 commands[NL802154_CMD_FRAME_NR_IDS / 32] = { };
   1560
   1561	if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR)
   1562		return -EOPNOTSUPP;
   1563
   1564	if (!info->attrs[NL802154_ATTR_SEC_KEY] ||
   1565	    nla_parse_nested_deprecated(attrs, NL802154_KEY_ATTR_MAX, info->attrs[NL802154_ATTR_SEC_KEY], nl802154_key_policy, info->extack))
   1566		return -EINVAL;
   1567
   1568	if (!attrs[NL802154_KEY_ATTR_USAGE_FRAMES] ||
   1569	    !attrs[NL802154_KEY_ATTR_BYTES])
   1570		return -EINVAL;
   1571
   1572	if (ieee802154_llsec_parse_key_id(attrs[NL802154_KEY_ATTR_ID], &id) < 0)
   1573		return -ENOBUFS;
   1574
   1575	key.frame_types = nla_get_u8(attrs[NL802154_KEY_ATTR_USAGE_FRAMES]);
   1576	if (key.frame_types > BIT(NL802154_FRAME_MAX) ||
   1577	    ((key.frame_types & BIT(NL802154_FRAME_CMD)) &&
   1578	     !attrs[NL802154_KEY_ATTR_USAGE_CMDS]))
   1579		return -EINVAL;
   1580
   1581	if (attrs[NL802154_KEY_ATTR_USAGE_CMDS]) {
   1582		/* TODO for each nested */
   1583		nla_memcpy(commands, attrs[NL802154_KEY_ATTR_USAGE_CMDS],
   1584			   NL802154_CMD_FRAME_NR_IDS / 8);
   1585
   1586		/* TODO understand the -EINVAL logic here? last condition */
   1587		if (commands[0] || commands[1] || commands[2] || commands[3] ||
   1588		    commands[4] || commands[5] || commands[6] ||
   1589		    commands[7] > BIT(NL802154_CMD_FRAME_MAX))
   1590			return -EINVAL;
   1591
   1592		key.cmd_frame_ids = commands[7];
   1593	} else {
   1594		key.cmd_frame_ids = 0;
   1595	}
   1596
   1597	nla_memcpy(key.key, attrs[NL802154_KEY_ATTR_BYTES], NL802154_KEY_SIZE);
   1598
   1599	if (ieee802154_llsec_parse_key_id(attrs[NL802154_KEY_ATTR_ID], &id) < 0)
   1600		return -ENOBUFS;
   1601
   1602	return rdev_add_llsec_key(rdev, wpan_dev, &id, &key);
   1603}
   1604
   1605static int nl802154_del_llsec_key(struct sk_buff *skb, struct genl_info *info)
   1606{
   1607	struct cfg802154_registered_device *rdev = info->user_ptr[0];
   1608	struct net_device *dev = info->user_ptr[1];
   1609	struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
   1610	struct nlattr *attrs[NL802154_KEY_ATTR_MAX + 1];
   1611	struct ieee802154_llsec_key_id id;
   1612
   1613	if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR)
   1614		return -EOPNOTSUPP;
   1615
   1616	if (!info->attrs[NL802154_ATTR_SEC_KEY] ||
   1617	    nla_parse_nested_deprecated(attrs, NL802154_KEY_ATTR_MAX, info->attrs[NL802154_ATTR_SEC_KEY], nl802154_key_policy, info->extack))
   1618		return -EINVAL;
   1619
   1620	if (ieee802154_llsec_parse_key_id(attrs[NL802154_KEY_ATTR_ID], &id) < 0)
   1621		return -ENOBUFS;
   1622
   1623	return rdev_del_llsec_key(rdev, wpan_dev, &id);
   1624}
   1625
   1626static int nl802154_send_device(struct sk_buff *msg, u32 cmd, u32 portid,
   1627				u32 seq, int flags,
   1628				struct cfg802154_registered_device *rdev,
   1629				struct net_device *dev,
   1630				const struct ieee802154_llsec_device *dev_desc)
   1631{
   1632	void *hdr;
   1633	struct nlattr *nl_device;
   1634
   1635	hdr = nl802154hdr_put(msg, portid, seq, flags, cmd);
   1636	if (!hdr)
   1637		return -ENOBUFS;
   1638
   1639	if (nla_put_u32(msg, NL802154_ATTR_IFINDEX, dev->ifindex))
   1640		goto nla_put_failure;
   1641
   1642	nl_device = nla_nest_start_noflag(msg, NL802154_ATTR_SEC_DEVICE);
   1643	if (!nl_device)
   1644		goto nla_put_failure;
   1645
   1646	if (nla_put_u32(msg, NL802154_DEV_ATTR_FRAME_COUNTER,
   1647			dev_desc->frame_counter) ||
   1648	    nla_put_le16(msg, NL802154_DEV_ATTR_PAN_ID, dev_desc->pan_id) ||
   1649	    nla_put_le16(msg, NL802154_DEV_ATTR_SHORT_ADDR,
   1650			 dev_desc->short_addr) ||
   1651	    nla_put_le64(msg, NL802154_DEV_ATTR_EXTENDED_ADDR,
   1652			 dev_desc->hwaddr, NL802154_DEV_ATTR_PAD) ||
   1653	    nla_put_u8(msg, NL802154_DEV_ATTR_SECLEVEL_EXEMPT,
   1654		       dev_desc->seclevel_exempt) ||
   1655	    nla_put_u32(msg, NL802154_DEV_ATTR_KEY_MODE, dev_desc->key_mode))
   1656		goto nla_put_failure;
   1657
   1658	nla_nest_end(msg, nl_device);
   1659	genlmsg_end(msg, hdr);
   1660
   1661	return 0;
   1662
   1663nla_put_failure:
   1664	genlmsg_cancel(msg, hdr);
   1665	return -EMSGSIZE;
   1666}
   1667
   1668static int
   1669nl802154_dump_llsec_dev(struct sk_buff *skb, struct netlink_callback *cb)
   1670{
   1671	struct cfg802154_registered_device *rdev = NULL;
   1672	struct ieee802154_llsec_device *dev;
   1673	struct ieee802154_llsec_table *table;
   1674	struct wpan_dev *wpan_dev;
   1675	int err;
   1676
   1677	err = nl802154_prepare_wpan_dev_dump(skb, cb, &rdev, &wpan_dev);
   1678	if (err)
   1679		return err;
   1680
   1681	if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR) {
   1682		err = skb->len;
   1683		goto out_err;
   1684	}
   1685
   1686	if (!wpan_dev->netdev) {
   1687		err = -EINVAL;
   1688		goto out_err;
   1689	}
   1690
   1691	rdev_lock_llsec_table(rdev, wpan_dev);
   1692	rdev_get_llsec_table(rdev, wpan_dev, &table);
   1693
   1694	/* TODO make it like station dump */
   1695	if (cb->args[2])
   1696		goto out;
   1697
   1698	list_for_each_entry(dev, &table->devices, list) {
   1699		if (nl802154_send_device(skb, NL802154_CMD_NEW_SEC_LEVEL,
   1700					 NETLINK_CB(cb->skb).portid,
   1701					 cb->nlh->nlmsg_seq, NLM_F_MULTI,
   1702					 rdev, wpan_dev->netdev, dev) < 0) {
   1703			/* TODO */
   1704			err = -EIO;
   1705			rdev_unlock_llsec_table(rdev, wpan_dev);
   1706			goto out_err;
   1707		}
   1708	}
   1709
   1710	cb->args[2] = 1;
   1711
   1712out:
   1713	rdev_unlock_llsec_table(rdev, wpan_dev);
   1714	err = skb->len;
   1715out_err:
   1716	nl802154_finish_wpan_dev_dump(rdev);
   1717
   1718	return err;
   1719}
   1720
   1721static const struct nla_policy nl802154_dev_policy[NL802154_DEV_ATTR_MAX + 1] = {
   1722	[NL802154_DEV_ATTR_FRAME_COUNTER] = { NLA_U32 },
   1723	[NL802154_DEV_ATTR_PAN_ID] = { .type = NLA_U16 },
   1724	[NL802154_DEV_ATTR_SHORT_ADDR] = { .type = NLA_U16 },
   1725	[NL802154_DEV_ATTR_EXTENDED_ADDR] = { .type = NLA_U64 },
   1726	[NL802154_DEV_ATTR_SECLEVEL_EXEMPT] = { NLA_U8 },
   1727	[NL802154_DEV_ATTR_KEY_MODE] = { NLA_U32 },
   1728};
   1729
   1730static int
   1731ieee802154_llsec_parse_device(struct nlattr *nla,
   1732			      struct ieee802154_llsec_device *dev)
   1733{
   1734	struct nlattr *attrs[NL802154_DEV_ATTR_MAX + 1];
   1735
   1736	if (!nla || nla_parse_nested_deprecated(attrs, NL802154_DEV_ATTR_MAX, nla, nl802154_dev_policy, NULL))
   1737		return -EINVAL;
   1738
   1739	memset(dev, 0, sizeof(*dev));
   1740
   1741	if (!attrs[NL802154_DEV_ATTR_FRAME_COUNTER] ||
   1742	    !attrs[NL802154_DEV_ATTR_PAN_ID] ||
   1743	    !attrs[NL802154_DEV_ATTR_SHORT_ADDR] ||
   1744	    !attrs[NL802154_DEV_ATTR_EXTENDED_ADDR] ||
   1745	    !attrs[NL802154_DEV_ATTR_SECLEVEL_EXEMPT] ||
   1746	    !attrs[NL802154_DEV_ATTR_KEY_MODE])
   1747		return -EINVAL;
   1748
   1749	/* TODO be32 */
   1750	dev->frame_counter = nla_get_u32(attrs[NL802154_DEV_ATTR_FRAME_COUNTER]);
   1751	dev->pan_id = nla_get_le16(attrs[NL802154_DEV_ATTR_PAN_ID]);
   1752	dev->short_addr = nla_get_le16(attrs[NL802154_DEV_ATTR_SHORT_ADDR]);
   1753	/* TODO rename hwaddr to extended_addr */
   1754	dev->hwaddr = nla_get_le64(attrs[NL802154_DEV_ATTR_EXTENDED_ADDR]);
   1755	dev->seclevel_exempt = nla_get_u8(attrs[NL802154_DEV_ATTR_SECLEVEL_EXEMPT]);
   1756	dev->key_mode = nla_get_u32(attrs[NL802154_DEV_ATTR_KEY_MODE]);
   1757
   1758	if (dev->key_mode > NL802154_DEVKEY_MAX ||
   1759	    (dev->seclevel_exempt != 0 && dev->seclevel_exempt != 1))
   1760		return -EINVAL;
   1761
   1762	return 0;
   1763}
   1764
   1765static int nl802154_add_llsec_dev(struct sk_buff *skb, struct genl_info *info)
   1766{
   1767	struct cfg802154_registered_device *rdev = info->user_ptr[0];
   1768	struct net_device *dev = info->user_ptr[1];
   1769	struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
   1770	struct ieee802154_llsec_device dev_desc;
   1771
   1772	if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR)
   1773		return -EOPNOTSUPP;
   1774
   1775	if (ieee802154_llsec_parse_device(info->attrs[NL802154_ATTR_SEC_DEVICE],
   1776					  &dev_desc) < 0)
   1777		return -EINVAL;
   1778
   1779	return rdev_add_device(rdev, wpan_dev, &dev_desc);
   1780}
   1781
   1782static int nl802154_del_llsec_dev(struct sk_buff *skb, struct genl_info *info)
   1783{
   1784	struct cfg802154_registered_device *rdev = info->user_ptr[0];
   1785	struct net_device *dev = info->user_ptr[1];
   1786	struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
   1787	struct nlattr *attrs[NL802154_DEV_ATTR_MAX + 1];
   1788	__le64 extended_addr;
   1789
   1790	if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR)
   1791		return -EOPNOTSUPP;
   1792
   1793	if (!info->attrs[NL802154_ATTR_SEC_DEVICE] ||
   1794	    nla_parse_nested_deprecated(attrs, NL802154_DEV_ATTR_MAX, info->attrs[NL802154_ATTR_SEC_DEVICE], nl802154_dev_policy, info->extack))
   1795		return -EINVAL;
   1796
   1797	if (!attrs[NL802154_DEV_ATTR_EXTENDED_ADDR])
   1798		return -EINVAL;
   1799
   1800	extended_addr = nla_get_le64(attrs[NL802154_DEV_ATTR_EXTENDED_ADDR]);
   1801	return rdev_del_device(rdev, wpan_dev, extended_addr);
   1802}
   1803
   1804static int nl802154_send_devkey(struct sk_buff *msg, u32 cmd, u32 portid,
   1805				u32 seq, int flags,
   1806				struct cfg802154_registered_device *rdev,
   1807				struct net_device *dev, __le64 extended_addr,
   1808				const struct ieee802154_llsec_device_key *devkey)
   1809{
   1810	void *hdr;
   1811	struct nlattr *nl_devkey, *nl_key_id;
   1812
   1813	hdr = nl802154hdr_put(msg, portid, seq, flags, cmd);
   1814	if (!hdr)
   1815		return -ENOBUFS;
   1816
   1817	if (nla_put_u32(msg, NL802154_ATTR_IFINDEX, dev->ifindex))
   1818		goto nla_put_failure;
   1819
   1820	nl_devkey = nla_nest_start_noflag(msg, NL802154_ATTR_SEC_DEVKEY);
   1821	if (!nl_devkey)
   1822		goto nla_put_failure;
   1823
   1824	if (nla_put_le64(msg, NL802154_DEVKEY_ATTR_EXTENDED_ADDR,
   1825			 extended_addr, NL802154_DEVKEY_ATTR_PAD) ||
   1826	    nla_put_u32(msg, NL802154_DEVKEY_ATTR_FRAME_COUNTER,
   1827			devkey->frame_counter))
   1828		goto nla_put_failure;
   1829
   1830	nl_key_id = nla_nest_start_noflag(msg, NL802154_DEVKEY_ATTR_ID);
   1831	if (!nl_key_id)
   1832		goto nla_put_failure;
   1833
   1834	if (ieee802154_llsec_send_key_id(msg, &devkey->key_id) < 0)
   1835		goto nla_put_failure;
   1836
   1837	nla_nest_end(msg, nl_key_id);
   1838	nla_nest_end(msg, nl_devkey);
   1839	genlmsg_end(msg, hdr);
   1840
   1841	return 0;
   1842
   1843nla_put_failure:
   1844	genlmsg_cancel(msg, hdr);
   1845	return -EMSGSIZE;
   1846}
   1847
   1848static int
   1849nl802154_dump_llsec_devkey(struct sk_buff *skb, struct netlink_callback *cb)
   1850{
   1851	struct cfg802154_registered_device *rdev = NULL;
   1852	struct ieee802154_llsec_device_key *kpos;
   1853	struct ieee802154_llsec_device *dpos;
   1854	struct ieee802154_llsec_table *table;
   1855	struct wpan_dev *wpan_dev;
   1856	int err;
   1857
   1858	err = nl802154_prepare_wpan_dev_dump(skb, cb, &rdev, &wpan_dev);
   1859	if (err)
   1860		return err;
   1861
   1862	if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR) {
   1863		err = skb->len;
   1864		goto out_err;
   1865	}
   1866
   1867	if (!wpan_dev->netdev) {
   1868		err = -EINVAL;
   1869		goto out_err;
   1870	}
   1871
   1872	rdev_lock_llsec_table(rdev, wpan_dev);
   1873	rdev_get_llsec_table(rdev, wpan_dev, &table);
   1874
   1875	/* TODO make it like station dump */
   1876	if (cb->args[2])
   1877		goto out;
   1878
   1879	/* TODO look if remove devkey and do some nested attribute */
   1880	list_for_each_entry(dpos, &table->devices, list) {
   1881		list_for_each_entry(kpos, &dpos->keys, list) {
   1882			if (nl802154_send_devkey(skb,
   1883						 NL802154_CMD_NEW_SEC_LEVEL,
   1884						 NETLINK_CB(cb->skb).portid,
   1885						 cb->nlh->nlmsg_seq,
   1886						 NLM_F_MULTI, rdev,
   1887						 wpan_dev->netdev,
   1888						 dpos->hwaddr,
   1889						 kpos) < 0) {
   1890				/* TODO */
   1891				err = -EIO;
   1892				rdev_unlock_llsec_table(rdev, wpan_dev);
   1893				goto out_err;
   1894			}
   1895		}
   1896	}
   1897
   1898	cb->args[2] = 1;
   1899
   1900out:
   1901	rdev_unlock_llsec_table(rdev, wpan_dev);
   1902	err = skb->len;
   1903out_err:
   1904	nl802154_finish_wpan_dev_dump(rdev);
   1905
   1906	return err;
   1907}
   1908
   1909static const struct nla_policy nl802154_devkey_policy[NL802154_DEVKEY_ATTR_MAX + 1] = {
   1910	[NL802154_DEVKEY_ATTR_FRAME_COUNTER] = { NLA_U32 },
   1911	[NL802154_DEVKEY_ATTR_EXTENDED_ADDR] = { NLA_U64 },
   1912	[NL802154_DEVKEY_ATTR_ID] = { NLA_NESTED },
   1913};
   1914
   1915static int nl802154_add_llsec_devkey(struct sk_buff *skb, struct genl_info *info)
   1916{
   1917	struct cfg802154_registered_device *rdev = info->user_ptr[0];
   1918	struct net_device *dev = info->user_ptr[1];
   1919	struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
   1920	struct nlattr *attrs[NL802154_DEVKEY_ATTR_MAX + 1];
   1921	struct ieee802154_llsec_device_key key;
   1922	__le64 extended_addr;
   1923
   1924	if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR)
   1925		return -EOPNOTSUPP;
   1926
   1927	if (!info->attrs[NL802154_ATTR_SEC_DEVKEY] ||
   1928	    nla_parse_nested_deprecated(attrs, NL802154_DEVKEY_ATTR_MAX, info->attrs[NL802154_ATTR_SEC_DEVKEY], nl802154_devkey_policy, info->extack) < 0)
   1929		return -EINVAL;
   1930
   1931	if (!attrs[NL802154_DEVKEY_ATTR_FRAME_COUNTER] ||
   1932	    !attrs[NL802154_DEVKEY_ATTR_EXTENDED_ADDR])
   1933		return -EINVAL;
   1934
   1935	/* TODO change key.id ? */
   1936	if (ieee802154_llsec_parse_key_id(attrs[NL802154_DEVKEY_ATTR_ID],
   1937					  &key.key_id) < 0)
   1938		return -ENOBUFS;
   1939
   1940	/* TODO be32 */
   1941	key.frame_counter = nla_get_u32(attrs[NL802154_DEVKEY_ATTR_FRAME_COUNTER]);
   1942	/* TODO change naming hwaddr -> extended_addr
   1943	 * check unique identifier short+pan OR extended_addr
   1944	 */
   1945	extended_addr = nla_get_le64(attrs[NL802154_DEVKEY_ATTR_EXTENDED_ADDR]);
   1946	return rdev_add_devkey(rdev, wpan_dev, extended_addr, &key);
   1947}
   1948
   1949static int nl802154_del_llsec_devkey(struct sk_buff *skb, struct genl_info *info)
   1950{
   1951	struct cfg802154_registered_device *rdev = info->user_ptr[0];
   1952	struct net_device *dev = info->user_ptr[1];
   1953	struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
   1954	struct nlattr *attrs[NL802154_DEVKEY_ATTR_MAX + 1];
   1955	struct ieee802154_llsec_device_key key;
   1956	__le64 extended_addr;
   1957
   1958	if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR)
   1959		return -EOPNOTSUPP;
   1960
   1961	if (!info->attrs[NL802154_ATTR_SEC_DEVKEY] ||
   1962	    nla_parse_nested_deprecated(attrs, NL802154_DEVKEY_ATTR_MAX, info->attrs[NL802154_ATTR_SEC_DEVKEY], nl802154_devkey_policy, info->extack))
   1963		return -EINVAL;
   1964
   1965	if (!attrs[NL802154_DEVKEY_ATTR_EXTENDED_ADDR])
   1966		return -EINVAL;
   1967
   1968	/* TODO change key.id ? */
   1969	if (ieee802154_llsec_parse_key_id(attrs[NL802154_DEVKEY_ATTR_ID],
   1970					  &key.key_id) < 0)
   1971		return -ENOBUFS;
   1972
   1973	/* TODO change naming hwaddr -> extended_addr
   1974	 * check unique identifier short+pan OR extended_addr
   1975	 */
   1976	extended_addr = nla_get_le64(attrs[NL802154_DEVKEY_ATTR_EXTENDED_ADDR]);
   1977	return rdev_del_devkey(rdev, wpan_dev, extended_addr, &key);
   1978}
   1979
   1980static int nl802154_send_seclevel(struct sk_buff *msg, u32 cmd, u32 portid,
   1981				  u32 seq, int flags,
   1982				  struct cfg802154_registered_device *rdev,
   1983				  struct net_device *dev,
   1984				  const struct ieee802154_llsec_seclevel *sl)
   1985{
   1986	void *hdr;
   1987	struct nlattr *nl_seclevel;
   1988
   1989	hdr = nl802154hdr_put(msg, portid, seq, flags, cmd);
   1990	if (!hdr)
   1991		return -ENOBUFS;
   1992
   1993	if (nla_put_u32(msg, NL802154_ATTR_IFINDEX, dev->ifindex))
   1994		goto nla_put_failure;
   1995
   1996	nl_seclevel = nla_nest_start_noflag(msg, NL802154_ATTR_SEC_LEVEL);
   1997	if (!nl_seclevel)
   1998		goto nla_put_failure;
   1999
   2000	if (nla_put_u32(msg, NL802154_SECLEVEL_ATTR_FRAME, sl->frame_type) ||
   2001	    nla_put_u32(msg, NL802154_SECLEVEL_ATTR_LEVELS, sl->sec_levels) ||
   2002	    nla_put_u8(msg, NL802154_SECLEVEL_ATTR_DEV_OVERRIDE,
   2003		       sl->device_override))
   2004		goto nla_put_failure;
   2005
   2006	if (sl->frame_type == NL802154_FRAME_CMD) {
   2007		if (nla_put_u32(msg, NL802154_SECLEVEL_ATTR_CMD_FRAME,
   2008				sl->cmd_frame_id))
   2009			goto nla_put_failure;
   2010	}
   2011
   2012	nla_nest_end(msg, nl_seclevel);
   2013	genlmsg_end(msg, hdr);
   2014
   2015	return 0;
   2016
   2017nla_put_failure:
   2018	genlmsg_cancel(msg, hdr);
   2019	return -EMSGSIZE;
   2020}
   2021
   2022static int
   2023nl802154_dump_llsec_seclevel(struct sk_buff *skb, struct netlink_callback *cb)
   2024{
   2025	struct cfg802154_registered_device *rdev = NULL;
   2026	struct ieee802154_llsec_seclevel *sl;
   2027	struct ieee802154_llsec_table *table;
   2028	struct wpan_dev *wpan_dev;
   2029	int err;
   2030
   2031	err = nl802154_prepare_wpan_dev_dump(skb, cb, &rdev, &wpan_dev);
   2032	if (err)
   2033		return err;
   2034
   2035	if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR) {
   2036		err = skb->len;
   2037		goto out_err;
   2038	}
   2039
   2040	if (!wpan_dev->netdev) {
   2041		err = -EINVAL;
   2042		goto out_err;
   2043	}
   2044
   2045	rdev_lock_llsec_table(rdev, wpan_dev);
   2046	rdev_get_llsec_table(rdev, wpan_dev, &table);
   2047
   2048	/* TODO make it like station dump */
   2049	if (cb->args[2])
   2050		goto out;
   2051
   2052	list_for_each_entry(sl, &table->security_levels, list) {
   2053		if (nl802154_send_seclevel(skb, NL802154_CMD_NEW_SEC_LEVEL,
   2054					   NETLINK_CB(cb->skb).portid,
   2055					   cb->nlh->nlmsg_seq, NLM_F_MULTI,
   2056					   rdev, wpan_dev->netdev, sl) < 0) {
   2057			/* TODO */
   2058			err = -EIO;
   2059			rdev_unlock_llsec_table(rdev, wpan_dev);
   2060			goto out_err;
   2061		}
   2062	}
   2063
   2064	cb->args[2] = 1;
   2065
   2066out:
   2067	rdev_unlock_llsec_table(rdev, wpan_dev);
   2068	err = skb->len;
   2069out_err:
   2070	nl802154_finish_wpan_dev_dump(rdev);
   2071
   2072	return err;
   2073}
   2074
   2075static const struct nla_policy nl802154_seclevel_policy[NL802154_SECLEVEL_ATTR_MAX + 1] = {
   2076	[NL802154_SECLEVEL_ATTR_LEVELS] = { .type = NLA_U8 },
   2077	[NL802154_SECLEVEL_ATTR_FRAME] = { .type = NLA_U32 },
   2078	[NL802154_SECLEVEL_ATTR_CMD_FRAME] = { .type = NLA_U32 },
   2079	[NL802154_SECLEVEL_ATTR_DEV_OVERRIDE] = { .type = NLA_U8 },
   2080};
   2081
   2082static int
   2083llsec_parse_seclevel(struct nlattr *nla, struct ieee802154_llsec_seclevel *sl)
   2084{
   2085	struct nlattr *attrs[NL802154_SECLEVEL_ATTR_MAX + 1];
   2086
   2087	if (!nla || nla_parse_nested_deprecated(attrs, NL802154_SECLEVEL_ATTR_MAX, nla, nl802154_seclevel_policy, NULL))
   2088		return -EINVAL;
   2089
   2090	memset(sl, 0, sizeof(*sl));
   2091
   2092	if (!attrs[NL802154_SECLEVEL_ATTR_LEVELS] ||
   2093	    !attrs[NL802154_SECLEVEL_ATTR_FRAME] ||
   2094	    !attrs[NL802154_SECLEVEL_ATTR_DEV_OVERRIDE])
   2095		return -EINVAL;
   2096
   2097	sl->sec_levels = nla_get_u8(attrs[NL802154_SECLEVEL_ATTR_LEVELS]);
   2098	sl->frame_type = nla_get_u32(attrs[NL802154_SECLEVEL_ATTR_FRAME]);
   2099	sl->device_override = nla_get_u8(attrs[NL802154_SECLEVEL_ATTR_DEV_OVERRIDE]);
   2100	if (sl->frame_type > NL802154_FRAME_MAX ||
   2101	    (sl->device_override != 0 && sl->device_override != 1))
   2102		return -EINVAL;
   2103
   2104	if (sl->frame_type == NL802154_FRAME_CMD) {
   2105		if (!attrs[NL802154_SECLEVEL_ATTR_CMD_FRAME])
   2106			return -EINVAL;
   2107
   2108		sl->cmd_frame_id = nla_get_u32(attrs[NL802154_SECLEVEL_ATTR_CMD_FRAME]);
   2109		if (sl->cmd_frame_id > NL802154_CMD_FRAME_MAX)
   2110			return -EINVAL;
   2111	}
   2112
   2113	return 0;
   2114}
   2115
   2116static int nl802154_add_llsec_seclevel(struct sk_buff *skb,
   2117				       struct genl_info *info)
   2118{
   2119	struct cfg802154_registered_device *rdev = info->user_ptr[0];
   2120	struct net_device *dev = info->user_ptr[1];
   2121	struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
   2122	struct ieee802154_llsec_seclevel sl;
   2123
   2124	if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR)
   2125		return -EOPNOTSUPP;
   2126
   2127	if (llsec_parse_seclevel(info->attrs[NL802154_ATTR_SEC_LEVEL],
   2128				 &sl) < 0)
   2129		return -EINVAL;
   2130
   2131	return rdev_add_seclevel(rdev, wpan_dev, &sl);
   2132}
   2133
   2134static int nl802154_del_llsec_seclevel(struct sk_buff *skb,
   2135				       struct genl_info *info)
   2136{
   2137	struct cfg802154_registered_device *rdev = info->user_ptr[0];
   2138	struct net_device *dev = info->user_ptr[1];
   2139	struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
   2140	struct ieee802154_llsec_seclevel sl;
   2141
   2142	if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR)
   2143		return -EOPNOTSUPP;
   2144
   2145	if (!info->attrs[NL802154_ATTR_SEC_LEVEL] ||
   2146	    llsec_parse_seclevel(info->attrs[NL802154_ATTR_SEC_LEVEL],
   2147				 &sl) < 0)
   2148		return -EINVAL;
   2149
   2150	return rdev_del_seclevel(rdev, wpan_dev, &sl);
   2151}
   2152#endif /* CONFIG_IEEE802154_NL802154_EXPERIMENTAL */
   2153
   2154#define NL802154_FLAG_NEED_WPAN_PHY	0x01
   2155#define NL802154_FLAG_NEED_NETDEV	0x02
   2156#define NL802154_FLAG_NEED_RTNL		0x04
   2157#define NL802154_FLAG_CHECK_NETDEV_UP	0x08
   2158#define NL802154_FLAG_NEED_WPAN_DEV	0x10
   2159
   2160static int nl802154_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
   2161			     struct genl_info *info)
   2162{
   2163	struct cfg802154_registered_device *rdev;
   2164	struct wpan_dev *wpan_dev;
   2165	struct net_device *dev;
   2166	bool rtnl = ops->internal_flags & NL802154_FLAG_NEED_RTNL;
   2167
   2168	if (rtnl)
   2169		rtnl_lock();
   2170
   2171	if (ops->internal_flags & NL802154_FLAG_NEED_WPAN_PHY) {
   2172		rdev = cfg802154_get_dev_from_info(genl_info_net(info), info);
   2173		if (IS_ERR(rdev)) {
   2174			if (rtnl)
   2175				rtnl_unlock();
   2176			return PTR_ERR(rdev);
   2177		}
   2178		info->user_ptr[0] = rdev;
   2179	} else if (ops->internal_flags & NL802154_FLAG_NEED_NETDEV ||
   2180		   ops->internal_flags & NL802154_FLAG_NEED_WPAN_DEV) {
   2181		ASSERT_RTNL();
   2182		wpan_dev = __cfg802154_wpan_dev_from_attrs(genl_info_net(info),
   2183							   info->attrs);
   2184		if (IS_ERR(wpan_dev)) {
   2185			if (rtnl)
   2186				rtnl_unlock();
   2187			return PTR_ERR(wpan_dev);
   2188		}
   2189
   2190		dev = wpan_dev->netdev;
   2191		rdev = wpan_phy_to_rdev(wpan_dev->wpan_phy);
   2192
   2193		if (ops->internal_flags & NL802154_FLAG_NEED_NETDEV) {
   2194			if (!dev) {
   2195				if (rtnl)
   2196					rtnl_unlock();
   2197				return -EINVAL;
   2198			}
   2199
   2200			info->user_ptr[1] = dev;
   2201		} else {
   2202			info->user_ptr[1] = wpan_dev;
   2203		}
   2204
   2205		if (dev) {
   2206			if (ops->internal_flags & NL802154_FLAG_CHECK_NETDEV_UP &&
   2207			    !netif_running(dev)) {
   2208				if (rtnl)
   2209					rtnl_unlock();
   2210				return -ENETDOWN;
   2211			}
   2212
   2213			dev_hold(dev);
   2214		}
   2215
   2216		info->user_ptr[0] = rdev;
   2217	}
   2218
   2219	return 0;
   2220}
   2221
   2222static void nl802154_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
   2223			       struct genl_info *info)
   2224{
   2225	if (info->user_ptr[1]) {
   2226		if (ops->internal_flags & NL802154_FLAG_NEED_WPAN_DEV) {
   2227			struct wpan_dev *wpan_dev = info->user_ptr[1];
   2228
   2229			dev_put(wpan_dev->netdev);
   2230		} else {
   2231			dev_put(info->user_ptr[1]);
   2232		}
   2233	}
   2234
   2235	if (ops->internal_flags & NL802154_FLAG_NEED_RTNL)
   2236		rtnl_unlock();
   2237}
   2238
   2239static const struct genl_ops nl802154_ops[] = {
   2240	{
   2241		.cmd = NL802154_CMD_GET_WPAN_PHY,
   2242		.validate = GENL_DONT_VALIDATE_STRICT |
   2243			    GENL_DONT_VALIDATE_DUMP_STRICT,
   2244		.doit = nl802154_get_wpan_phy,
   2245		.dumpit = nl802154_dump_wpan_phy,
   2246		.done = nl802154_dump_wpan_phy_done,
   2247		/* can be retrieved by unprivileged users */
   2248		.internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
   2249				  NL802154_FLAG_NEED_RTNL,
   2250	},
   2251	{
   2252		.cmd = NL802154_CMD_GET_INTERFACE,
   2253		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
   2254		.doit = nl802154_get_interface,
   2255		.dumpit = nl802154_dump_interface,
   2256		/* can be retrieved by unprivileged users */
   2257		.internal_flags = NL802154_FLAG_NEED_WPAN_DEV |
   2258				  NL802154_FLAG_NEED_RTNL,
   2259	},
   2260	{
   2261		.cmd = NL802154_CMD_NEW_INTERFACE,
   2262		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
   2263		.doit = nl802154_new_interface,
   2264		.flags = GENL_ADMIN_PERM,
   2265		.internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
   2266				  NL802154_FLAG_NEED_RTNL,
   2267	},
   2268	{
   2269		.cmd = NL802154_CMD_DEL_INTERFACE,
   2270		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
   2271		.doit = nl802154_del_interface,
   2272		.flags = GENL_ADMIN_PERM,
   2273		.internal_flags = NL802154_FLAG_NEED_WPAN_DEV |
   2274				  NL802154_FLAG_NEED_RTNL,
   2275	},
   2276	{
   2277		.cmd = NL802154_CMD_SET_CHANNEL,
   2278		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
   2279		.doit = nl802154_set_channel,
   2280		.flags = GENL_ADMIN_PERM,
   2281		.internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
   2282				  NL802154_FLAG_NEED_RTNL,
   2283	},
   2284	{
   2285		.cmd = NL802154_CMD_SET_CCA_MODE,
   2286		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
   2287		.doit = nl802154_set_cca_mode,
   2288		.flags = GENL_ADMIN_PERM,
   2289		.internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
   2290				  NL802154_FLAG_NEED_RTNL,
   2291	},
   2292	{
   2293		.cmd = NL802154_CMD_SET_CCA_ED_LEVEL,
   2294		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
   2295		.doit = nl802154_set_cca_ed_level,
   2296		.flags = GENL_ADMIN_PERM,
   2297		.internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
   2298				  NL802154_FLAG_NEED_RTNL,
   2299	},
   2300	{
   2301		.cmd = NL802154_CMD_SET_TX_POWER,
   2302		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
   2303		.doit = nl802154_set_tx_power,
   2304		.flags = GENL_ADMIN_PERM,
   2305		.internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
   2306				  NL802154_FLAG_NEED_RTNL,
   2307	},
   2308	{
   2309		.cmd = NL802154_CMD_SET_WPAN_PHY_NETNS,
   2310		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
   2311		.doit = nl802154_wpan_phy_netns,
   2312		.flags = GENL_ADMIN_PERM,
   2313		.internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
   2314				  NL802154_FLAG_NEED_RTNL,
   2315	},
   2316	{
   2317		.cmd = NL802154_CMD_SET_PAN_ID,
   2318		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
   2319		.doit = nl802154_set_pan_id,
   2320		.flags = GENL_ADMIN_PERM,
   2321		.internal_flags = NL802154_FLAG_NEED_NETDEV |
   2322				  NL802154_FLAG_NEED_RTNL,
   2323	},
   2324	{
   2325		.cmd = NL802154_CMD_SET_SHORT_ADDR,
   2326		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
   2327		.doit = nl802154_set_short_addr,
   2328		.flags = GENL_ADMIN_PERM,
   2329		.internal_flags = NL802154_FLAG_NEED_NETDEV |
   2330				  NL802154_FLAG_NEED_RTNL,
   2331	},
   2332	{
   2333		.cmd = NL802154_CMD_SET_BACKOFF_EXPONENT,
   2334		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
   2335		.doit = nl802154_set_backoff_exponent,
   2336		.flags = GENL_ADMIN_PERM,
   2337		.internal_flags = NL802154_FLAG_NEED_NETDEV |
   2338				  NL802154_FLAG_NEED_RTNL,
   2339	},
   2340	{
   2341		.cmd = NL802154_CMD_SET_MAX_CSMA_BACKOFFS,
   2342		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
   2343		.doit = nl802154_set_max_csma_backoffs,
   2344		.flags = GENL_ADMIN_PERM,
   2345		.internal_flags = NL802154_FLAG_NEED_NETDEV |
   2346				  NL802154_FLAG_NEED_RTNL,
   2347	},
   2348	{
   2349		.cmd = NL802154_CMD_SET_MAX_FRAME_RETRIES,
   2350		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
   2351		.doit = nl802154_set_max_frame_retries,
   2352		.flags = GENL_ADMIN_PERM,
   2353		.internal_flags = NL802154_FLAG_NEED_NETDEV |
   2354				  NL802154_FLAG_NEED_RTNL,
   2355	},
   2356	{
   2357		.cmd = NL802154_CMD_SET_LBT_MODE,
   2358		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
   2359		.doit = nl802154_set_lbt_mode,
   2360		.flags = GENL_ADMIN_PERM,
   2361		.internal_flags = NL802154_FLAG_NEED_NETDEV |
   2362				  NL802154_FLAG_NEED_RTNL,
   2363	},
   2364	{
   2365		.cmd = NL802154_CMD_SET_ACKREQ_DEFAULT,
   2366		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
   2367		.doit = nl802154_set_ackreq_default,
   2368		.flags = GENL_ADMIN_PERM,
   2369		.internal_flags = NL802154_FLAG_NEED_NETDEV |
   2370				  NL802154_FLAG_NEED_RTNL,
   2371	},
   2372#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
   2373	{
   2374		.cmd = NL802154_CMD_SET_SEC_PARAMS,
   2375		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
   2376		.doit = nl802154_set_llsec_params,
   2377		.flags = GENL_ADMIN_PERM,
   2378		.internal_flags = NL802154_FLAG_NEED_NETDEV |
   2379				  NL802154_FLAG_NEED_RTNL,
   2380	},
   2381	{
   2382		.cmd = NL802154_CMD_GET_SEC_KEY,
   2383		.validate = GENL_DONT_VALIDATE_STRICT |
   2384			    GENL_DONT_VALIDATE_DUMP_STRICT,
   2385		/* TODO .doit by matching key id? */
   2386		.dumpit = nl802154_dump_llsec_key,
   2387		.flags = GENL_ADMIN_PERM,
   2388		.internal_flags = NL802154_FLAG_NEED_NETDEV |
   2389				  NL802154_FLAG_NEED_RTNL,
   2390	},
   2391	{
   2392		.cmd = NL802154_CMD_NEW_SEC_KEY,
   2393		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
   2394		.doit = nl802154_add_llsec_key,
   2395		.flags = GENL_ADMIN_PERM,
   2396		.internal_flags = NL802154_FLAG_NEED_NETDEV |
   2397				  NL802154_FLAG_NEED_RTNL,
   2398	},
   2399	{
   2400		.cmd = NL802154_CMD_DEL_SEC_KEY,
   2401		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
   2402		.doit = nl802154_del_llsec_key,
   2403		.flags = GENL_ADMIN_PERM,
   2404		.internal_flags = NL802154_FLAG_NEED_NETDEV |
   2405				  NL802154_FLAG_NEED_RTNL,
   2406	},
   2407	/* TODO unique identifier must short+pan OR extended_addr */
   2408	{
   2409		.cmd = NL802154_CMD_GET_SEC_DEV,
   2410		.validate = GENL_DONT_VALIDATE_STRICT |
   2411			    GENL_DONT_VALIDATE_DUMP_STRICT,
   2412		/* TODO .doit by matching extended_addr? */
   2413		.dumpit = nl802154_dump_llsec_dev,
   2414		.flags = GENL_ADMIN_PERM,
   2415		.internal_flags = NL802154_FLAG_NEED_NETDEV |
   2416				  NL802154_FLAG_NEED_RTNL,
   2417	},
   2418	{
   2419		.cmd = NL802154_CMD_NEW_SEC_DEV,
   2420		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
   2421		.doit = nl802154_add_llsec_dev,
   2422		.flags = GENL_ADMIN_PERM,
   2423		.internal_flags = NL802154_FLAG_NEED_NETDEV |
   2424				  NL802154_FLAG_NEED_RTNL,
   2425	},
   2426	{
   2427		.cmd = NL802154_CMD_DEL_SEC_DEV,
   2428		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
   2429		.doit = nl802154_del_llsec_dev,
   2430		.flags = GENL_ADMIN_PERM,
   2431		.internal_flags = NL802154_FLAG_NEED_NETDEV |
   2432				  NL802154_FLAG_NEED_RTNL,
   2433	},
   2434	/* TODO remove complete devkey, put it as nested? */
   2435	{
   2436		.cmd = NL802154_CMD_GET_SEC_DEVKEY,
   2437		.validate = GENL_DONT_VALIDATE_STRICT |
   2438			    GENL_DONT_VALIDATE_DUMP_STRICT,
   2439		/* TODO doit by matching ??? */
   2440		.dumpit = nl802154_dump_llsec_devkey,
   2441		.flags = GENL_ADMIN_PERM,
   2442		.internal_flags = NL802154_FLAG_NEED_NETDEV |
   2443				  NL802154_FLAG_NEED_RTNL,
   2444	},
   2445	{
   2446		.cmd = NL802154_CMD_NEW_SEC_DEVKEY,
   2447		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
   2448		.doit = nl802154_add_llsec_devkey,
   2449		.flags = GENL_ADMIN_PERM,
   2450		.internal_flags = NL802154_FLAG_NEED_NETDEV |
   2451				  NL802154_FLAG_NEED_RTNL,
   2452	},
   2453	{
   2454		.cmd = NL802154_CMD_DEL_SEC_DEVKEY,
   2455		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
   2456		.doit = nl802154_del_llsec_devkey,
   2457		.flags = GENL_ADMIN_PERM,
   2458		.internal_flags = NL802154_FLAG_NEED_NETDEV |
   2459				  NL802154_FLAG_NEED_RTNL,
   2460	},
   2461	{
   2462		.cmd = NL802154_CMD_GET_SEC_LEVEL,
   2463		.validate = GENL_DONT_VALIDATE_STRICT |
   2464			    GENL_DONT_VALIDATE_DUMP_STRICT,
   2465		/* TODO .doit by matching frame_type? */
   2466		.dumpit = nl802154_dump_llsec_seclevel,
   2467		.flags = GENL_ADMIN_PERM,
   2468		.internal_flags = NL802154_FLAG_NEED_NETDEV |
   2469				  NL802154_FLAG_NEED_RTNL,
   2470	},
   2471	{
   2472		.cmd = NL802154_CMD_NEW_SEC_LEVEL,
   2473		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
   2474		.doit = nl802154_add_llsec_seclevel,
   2475		.flags = GENL_ADMIN_PERM,
   2476		.internal_flags = NL802154_FLAG_NEED_NETDEV |
   2477				  NL802154_FLAG_NEED_RTNL,
   2478	},
   2479	{
   2480		.cmd = NL802154_CMD_DEL_SEC_LEVEL,
   2481		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
   2482		/* TODO match frame_type only? */
   2483		.doit = nl802154_del_llsec_seclevel,
   2484		.flags = GENL_ADMIN_PERM,
   2485		.internal_flags = NL802154_FLAG_NEED_NETDEV |
   2486				  NL802154_FLAG_NEED_RTNL,
   2487	},
   2488#endif /* CONFIG_IEEE802154_NL802154_EXPERIMENTAL */
   2489};
   2490
   2491static struct genl_family nl802154_fam __ro_after_init = {
   2492	.name = NL802154_GENL_NAME,	/* have users key off the name instead */
   2493	.hdrsize = 0,			/* no private header */
   2494	.version = 1,			/* no particular meaning now */
   2495	.maxattr = NL802154_ATTR_MAX,
   2496	.policy = nl802154_policy,
   2497	.netnsok = true,
   2498	.pre_doit = nl802154_pre_doit,
   2499	.post_doit = nl802154_post_doit,
   2500	.module = THIS_MODULE,
   2501	.ops = nl802154_ops,
   2502	.n_ops = ARRAY_SIZE(nl802154_ops),
   2503	.mcgrps = nl802154_mcgrps,
   2504	.n_mcgrps = ARRAY_SIZE(nl802154_mcgrps),
   2505};
   2506
   2507/* initialisation/exit functions */
   2508int __init nl802154_init(void)
   2509{
   2510	return genl_register_family(&nl802154_fam);
   2511}
   2512
   2513void nl802154_exit(void)
   2514{
   2515	genl_unregister_family(&nl802154_fam);
   2516}