mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 03:01:39 -04:00
This time we have too many changes to list, highlights:
* virt_wifi - wireless control simulation on top of
another network interface
* hwsim configurability to test capabilities similar
to real hardware
* various mesh improvements
* various radiotap vendor data fixes in mac80211
* finally the nl_set_extack_cookie_u64() we talked
about previously, used for
* peer measurement APIs, right now only with FTM
(flight time measurement) for location
* made nl80211 radio/interface announcements more complete
* various new HE (802.11ax) things:
updates, TWT support, ...
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEEH1e1rEeCd0AIMq6MB8qZga/fl8QFAlwaCwkACgkQB8qZga/f
l8S7mA/+I1CJmGC7Pvy+SBFkzoY5zEjjzgZYL6sGo16qMs89NPcURSe5j+uCsDP3
nKEjsvhQMYDfGNLTJJfWbDpGwm9LnKp69AFITlvfzmP6Sm36QMZr7oIC4abi8cW4
osaO3qfdaNoZ//x72jgjrFhUAnphvT2BsRVMNEjz7sXcDd7Jm9NnpRhV8zgXFvLF
dS2Ng51LM/BLMz5jQpyJUDZeeL/iBYybCecyckmVqzXPh1icIZETSqZXiN4ngv2A
6p9BSGNtP6wmjnbkvZz5RDq76VhTPZWsTgTpVb45Wf1k2fm1rB96UgpqvfQtjTgB
+7Zx2WRpMXM5OjGkwaEs8nawFmt7MHCGnhLPLWPCbXc685fhp3OFShysMJdYS/GZ
IIRJ7+IchAQX1yluftB+NkQM9sBDjyseMBwxHRYkj/rQVhoLY1sT+ke7lkuV10o6
DQqfpUTZAsIz7zkuscn7hkNdI/Rjub6BZjbrs1Jt9zSt9WQUBao23XudOI0j5JDa
ErnfC5PISXMQWik5B9M1Zhq3H9qCI2Swh19lMmtxtSDQ9yrLrJkEJ5SA+aHoxNHj
wSxBc3XXSW47qPXGX/D5DNnbOcOrE7kVZuD8YqRsy8VedyjIgEw7oQ21flAD4FC4
R4TgbNkqpfZQsU29gaMkDkYXnfQDB/G9FOk6ARGxjBPjT55Hz0E=
=EpyK
-----END PGP SIGNATURE-----
Merge tag 'mac80211-next-for-davem-2018-12-19' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next
Johannes Berg says:
====================
This time we have too many changes to list, highlights:
* virt_wifi - wireless control simulation on top of
another network interface
* hwsim configurability to test capabilities similar
to real hardware
* various mesh improvements
* various radiotap vendor data fixes in mac80211
* finally the nl_set_extack_cookie_u64() we talked
about previously, used for
* peer measurement APIs, right now only with FTM
(flight time measurement) for location
* made nl80211 radio/interface announcements more complete
* various new HE (802.11ax) things:
updates, TWT support, ...
====================
Signed-off-by: David S. Miller <[email protected]>
This commit is contained in:
commit
5a862f86b8
41 changed files with 2934 additions and 252 deletions
|
|
@ -12,6 +12,7 @@ obj-$(CONFIG_WEXT_PRIV) += wext-priv.o
|
|||
|
||||
cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o
|
||||
cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o ap.o trace.o ocb.o
|
||||
cfg80211-y += pmsr.o
|
||||
cfg80211-$(CONFIG_OF) += of.o
|
||||
cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o
|
||||
cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
*
|
||||
* Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
||||
* Copyright 2018 Intel Corporation
|
||||
*/
|
||||
|
||||
#include <linux/export.h>
|
||||
|
|
@ -747,6 +748,7 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy,
|
|||
case NL80211_CHAN_WIDTH_20:
|
||||
if (!ht_cap->ht_supported)
|
||||
return false;
|
||||
/* fall through */
|
||||
case NL80211_CHAN_WIDTH_20_NOHT:
|
||||
prohibited_flags |= IEEE80211_CHAN_NO_20MHZ;
|
||||
width = 20;
|
||||
|
|
@ -769,6 +771,7 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy,
|
|||
cap = vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
|
||||
if (cap != IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)
|
||||
return false;
|
||||
/* fall through */
|
||||
case NL80211_CHAN_WIDTH_80:
|
||||
if (!vht_cap->vht_supported)
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
* Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
||||
* Copyright 2015-2017 Intel Deutschland GmbH
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
|
@ -190,11 +191,25 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev,
|
|||
return err;
|
||||
}
|
||||
|
||||
list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
|
||||
if (!wdev->netdev)
|
||||
continue;
|
||||
nl80211_notify_iface(rdev, wdev, NL80211_CMD_DEL_INTERFACE);
|
||||
}
|
||||
nl80211_notify_wiphy(rdev, NL80211_CMD_DEL_WIPHY);
|
||||
|
||||
wiphy_net_set(&rdev->wiphy, net);
|
||||
|
||||
err = device_rename(&rdev->wiphy.dev, dev_name(&rdev->wiphy.dev));
|
||||
WARN_ON(err);
|
||||
|
||||
nl80211_notify_wiphy(rdev, NL80211_CMD_NEW_WIPHY);
|
||||
list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
|
||||
if (!wdev->netdev)
|
||||
continue;
|
||||
nl80211_notify_iface(rdev, wdev, NL80211_CMD_NEW_INTERFACE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -664,6 +679,34 @@ int wiphy_register(struct wiphy *wiphy)
|
|||
return -EINVAL;
|
||||
#endif
|
||||
|
||||
if (WARN_ON(wiphy->pmsr_capa && !wiphy->pmsr_capa->ftm.supported))
|
||||
return -EINVAL;
|
||||
|
||||
if (wiphy->pmsr_capa && wiphy->pmsr_capa->ftm.supported) {
|
||||
if (WARN_ON(!wiphy->pmsr_capa->ftm.asap &&
|
||||
!wiphy->pmsr_capa->ftm.non_asap))
|
||||
return -EINVAL;
|
||||
if (WARN_ON(!wiphy->pmsr_capa->ftm.preambles ||
|
||||
!wiphy->pmsr_capa->ftm.bandwidths))
|
||||
return -EINVAL;
|
||||
if (WARN_ON(wiphy->pmsr_capa->ftm.preambles &
|
||||
~(BIT(NL80211_PREAMBLE_LEGACY) |
|
||||
BIT(NL80211_PREAMBLE_HT) |
|
||||
BIT(NL80211_PREAMBLE_VHT) |
|
||||
BIT(NL80211_PREAMBLE_DMG))))
|
||||
return -EINVAL;
|
||||
if (WARN_ON(wiphy->pmsr_capa->ftm.bandwidths &
|
||||
~(BIT(NL80211_CHAN_WIDTH_20_NOHT) |
|
||||
BIT(NL80211_CHAN_WIDTH_20) |
|
||||
BIT(NL80211_CHAN_WIDTH_40) |
|
||||
BIT(NL80211_CHAN_WIDTH_80) |
|
||||
BIT(NL80211_CHAN_WIDTH_80P80) |
|
||||
BIT(NL80211_CHAN_WIDTH_160) |
|
||||
BIT(NL80211_CHAN_WIDTH_5) |
|
||||
BIT(NL80211_CHAN_WIDTH_10))))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* if a wiphy has unsupported modes for regulatory channel enforcement,
|
||||
* opt-out of enforcement checking
|
||||
|
|
@ -1087,6 +1130,8 @@ void __cfg80211_leave(struct cfg80211_registered_device *rdev,
|
|||
ASSERT_RTNL();
|
||||
ASSERT_WDEV_LOCK(wdev);
|
||||
|
||||
cfg80211_pmsr_wdev_down(wdev);
|
||||
|
||||
switch (wdev->iftype) {
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
__cfg80211_leave_ibss(rdev, dev, true);
|
||||
|
|
@ -1174,6 +1219,9 @@ void cfg80211_init_wdev(struct cfg80211_registered_device *rdev,
|
|||
spin_lock_init(&wdev->event_lock);
|
||||
INIT_LIST_HEAD(&wdev->mgmt_registrations);
|
||||
spin_lock_init(&wdev->mgmt_registrations_lock);
|
||||
INIT_LIST_HEAD(&wdev->pmsr_list);
|
||||
spin_lock_init(&wdev->pmsr_lock);
|
||||
INIT_WORK(&wdev->pmsr_free_wk, cfg80211_pmsr_free_wk);
|
||||
|
||||
/*
|
||||
* We get here also when the interface changes network namespaces,
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
* Wireless configuration interface internals.
|
||||
*
|
||||
* Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
*/
|
||||
#ifndef __NET_WIRELESS_CORE_H
|
||||
#define __NET_WIRELESS_CORE_H
|
||||
|
|
@ -530,4 +531,8 @@ void cfg80211_stop_nan(struct cfg80211_registered_device *rdev,
|
|||
|
||||
void cfg80211_cqm_config_free(struct wireless_dev *wdev);
|
||||
|
||||
void cfg80211_release_pmsr(struct wireless_dev *wdev, u32 portid);
|
||||
void cfg80211_pmsr_wdev_down(struct wireless_dev *wdev);
|
||||
void cfg80211_pmsr_free_wk(struct work_struct *work);
|
||||
|
||||
#endif /* __NET_WIRELESS_CORE_H */
|
||||
|
|
|
|||
|
|
@ -240,7 +240,63 @@ nl80211_ftm_responder_policy[NL80211_FTM_RESP_ATTR_MAX + 1] = {
|
|||
.len = U8_MAX },
|
||||
};
|
||||
|
||||
static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
|
||||
static const struct nla_policy
|
||||
nl80211_pmsr_ftm_req_attr_policy[NL80211_PMSR_FTM_REQ_ATTR_MAX + 1] = {
|
||||
[NL80211_PMSR_FTM_REQ_ATTR_ASAP] = { .type = NLA_FLAG },
|
||||
[NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE] = { .type = NLA_U32 },
|
||||
[NL80211_PMSR_FTM_REQ_ATTR_NUM_BURSTS_EXP] =
|
||||
NLA_POLICY_MAX(NLA_U8, 15),
|
||||
[NL80211_PMSR_FTM_REQ_ATTR_BURST_PERIOD] = { .type = NLA_U16 },
|
||||
[NL80211_PMSR_FTM_REQ_ATTR_BURST_DURATION] =
|
||||
NLA_POLICY_MAX(NLA_U8, 15),
|
||||
[NL80211_PMSR_FTM_REQ_ATTR_FTMS_PER_BURST] =
|
||||
NLA_POLICY_MAX(NLA_U8, 15),
|
||||
[NL80211_PMSR_FTM_REQ_ATTR_NUM_FTMR_RETRIES] = { .type = NLA_U8 },
|
||||
[NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI] = { .type = NLA_FLAG },
|
||||
[NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC] = { .type = NLA_FLAG },
|
||||
};
|
||||
|
||||
static const struct nla_policy
|
||||
nl80211_pmsr_req_data_policy[NL80211_PMSR_TYPE_MAX + 1] = {
|
||||
[NL80211_PMSR_TYPE_FTM] =
|
||||
NLA_POLICY_NESTED(NL80211_PMSR_FTM_REQ_ATTR_MAX,
|
||||
nl80211_pmsr_ftm_req_attr_policy),
|
||||
};
|
||||
|
||||
static const struct nla_policy
|
||||
nl80211_pmsr_req_attr_policy[NL80211_PMSR_REQ_ATTR_MAX + 1] = {
|
||||
[NL80211_PMSR_REQ_ATTR_DATA] =
|
||||
NLA_POLICY_NESTED(NL80211_PMSR_TYPE_MAX,
|
||||
nl80211_pmsr_req_data_policy),
|
||||
[NL80211_PMSR_REQ_ATTR_GET_AP_TSF] = { .type = NLA_FLAG },
|
||||
};
|
||||
|
||||
static const struct nla_policy
|
||||
nl80211_psmr_peer_attr_policy[NL80211_PMSR_PEER_ATTR_MAX + 1] = {
|
||||
[NL80211_PMSR_PEER_ATTR_ADDR] = NLA_POLICY_ETH_ADDR,
|
||||
/*
|
||||
* we could specify this again to be the top-level policy,
|
||||
* but that would open us up to recursion problems ...
|
||||
*/
|
||||
[NL80211_PMSR_PEER_ATTR_CHAN] = { .type = NLA_NESTED },
|
||||
[NL80211_PMSR_PEER_ATTR_REQ] =
|
||||
NLA_POLICY_NESTED(NL80211_PMSR_REQ_ATTR_MAX,
|
||||
nl80211_pmsr_req_attr_policy),
|
||||
[NL80211_PMSR_PEER_ATTR_RESP] = { .type = NLA_REJECT },
|
||||
};
|
||||
|
||||
static const struct nla_policy
|
||||
nl80211_pmsr_attr_policy[NL80211_PMSR_ATTR_MAX + 1] = {
|
||||
[NL80211_PMSR_ATTR_MAX_PEERS] = { .type = NLA_REJECT },
|
||||
[NL80211_PMSR_ATTR_REPORT_AP_TSF] = { .type = NLA_REJECT },
|
||||
[NL80211_PMSR_ATTR_RANDOMIZE_MAC_ADDR] = { .type = NLA_REJECT },
|
||||
[NL80211_PMSR_ATTR_TYPE_CAPA] = { .type = NLA_REJECT },
|
||||
[NL80211_PMSR_ATTR_PEERS] =
|
||||
NLA_POLICY_NESTED_ARRAY(NL80211_PMSR_PEER_ATTR_MAX,
|
||||
nl80211_psmr_peer_attr_policy),
|
||||
};
|
||||
|
||||
const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
|
||||
[NL80211_ATTR_WIPHY] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING,
|
||||
.len = 20-1 },
|
||||
|
|
@ -497,6 +553,10 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
|
|||
.type = NLA_NESTED,
|
||||
.validation_data = nl80211_ftm_responder_policy,
|
||||
},
|
||||
[NL80211_ATTR_TIMEOUT] = NLA_POLICY_MIN(NLA_U32, 1),
|
||||
[NL80211_ATTR_PEER_MEASUREMENTS] =
|
||||
NLA_POLICY_NESTED(NL80211_PMSR_FTM_REQ_ATTR_MAX,
|
||||
nl80211_pmsr_attr_policy),
|
||||
};
|
||||
|
||||
/* policy for the key attributes */
|
||||
|
|
@ -637,9 +697,9 @@ nl80211_packet_pattern_policy[MAX_NL80211_PKTPAT + 1] = {
|
|||
[NL80211_PKTPAT_OFFSET] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
static int nl80211_prepare_wdev_dump(struct netlink_callback *cb,
|
||||
struct cfg80211_registered_device **rdev,
|
||||
struct wireless_dev **wdev)
|
||||
int nl80211_prepare_wdev_dump(struct netlink_callback *cb,
|
||||
struct cfg80211_registered_device **rdev,
|
||||
struct wireless_dev **wdev)
|
||||
{
|
||||
int err;
|
||||
|
||||
|
|
@ -684,8 +744,8 @@ static int nl80211_prepare_wdev_dump(struct netlink_callback *cb,
|
|||
}
|
||||
|
||||
/* message building helper */
|
||||
static inline void *nl80211hdr_put(struct sk_buff *skb, u32 portid, u32 seq,
|
||||
int flags, u8 cmd)
|
||||
void *nl80211hdr_put(struct sk_buff *skb, u32 portid, u32 seq,
|
||||
int flags, u8 cmd)
|
||||
{
|
||||
/* since there is no private header just add the generic one */
|
||||
return genlmsg_put(skb, portid, seq, &nl80211_fam, flags, cmd);
|
||||
|
|
@ -1615,6 +1675,91 @@ static int nl80211_add_commands_unsplit(struct cfg80211_registered_device *rdev,
|
|||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
static int
|
||||
nl80211_send_pmsr_ftm_capa(const struct cfg80211_pmsr_capabilities *cap,
|
||||
struct sk_buff *msg)
|
||||
{
|
||||
struct nlattr *ftm;
|
||||
|
||||
if (!cap->ftm.supported)
|
||||
return 0;
|
||||
|
||||
ftm = nla_nest_start(msg, NL80211_PMSR_TYPE_FTM);
|
||||
if (!ftm)
|
||||
return -ENOBUFS;
|
||||
|
||||
if (cap->ftm.asap && nla_put_flag(msg, NL80211_PMSR_FTM_CAPA_ATTR_ASAP))
|
||||
return -ENOBUFS;
|
||||
if (cap->ftm.non_asap &&
|
||||
nla_put_flag(msg, NL80211_PMSR_FTM_CAPA_ATTR_NON_ASAP))
|
||||
return -ENOBUFS;
|
||||
if (cap->ftm.request_lci &&
|
||||
nla_put_flag(msg, NL80211_PMSR_FTM_CAPA_ATTR_REQ_LCI))
|
||||
return -ENOBUFS;
|
||||
if (cap->ftm.request_civicloc &&
|
||||
nla_put_flag(msg, NL80211_PMSR_FTM_CAPA_ATTR_REQ_CIVICLOC))
|
||||
return -ENOBUFS;
|
||||
if (nla_put_u32(msg, NL80211_PMSR_FTM_CAPA_ATTR_PREAMBLES,
|
||||
cap->ftm.preambles))
|
||||
return -ENOBUFS;
|
||||
if (nla_put_u32(msg, NL80211_PMSR_FTM_CAPA_ATTR_BANDWIDTHS,
|
||||
cap->ftm.bandwidths))
|
||||
return -ENOBUFS;
|
||||
if (cap->ftm.max_bursts_exponent >= 0 &&
|
||||
nla_put_u32(msg, NL80211_PMSR_FTM_CAPA_ATTR_MAX_BURSTS_EXPONENT,
|
||||
cap->ftm.max_bursts_exponent))
|
||||
return -ENOBUFS;
|
||||
if (cap->ftm.max_ftms_per_burst &&
|
||||
nla_put_u32(msg, NL80211_PMSR_FTM_CAPA_ATTR_MAX_FTMS_PER_BURST,
|
||||
cap->ftm.max_ftms_per_burst))
|
||||
return -ENOBUFS;
|
||||
|
||||
nla_nest_end(msg, ftm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nl80211_send_pmsr_capa(struct cfg80211_registered_device *rdev,
|
||||
struct sk_buff *msg)
|
||||
{
|
||||
const struct cfg80211_pmsr_capabilities *cap = rdev->wiphy.pmsr_capa;
|
||||
struct nlattr *pmsr, *caps;
|
||||
|
||||
if (!cap)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* we don't need to clean up anything here since the caller
|
||||
* will genlmsg_cancel() if we fail
|
||||
*/
|
||||
|
||||
pmsr = nla_nest_start(msg, NL80211_ATTR_PEER_MEASUREMENTS);
|
||||
if (!pmsr)
|
||||
return -ENOBUFS;
|
||||
|
||||
if (nla_put_u32(msg, NL80211_PMSR_ATTR_MAX_PEERS, cap->max_peers))
|
||||
return -ENOBUFS;
|
||||
|
||||
if (cap->report_ap_tsf &&
|
||||
nla_put_flag(msg, NL80211_PMSR_ATTR_REPORT_AP_TSF))
|
||||
return -ENOBUFS;
|
||||
|
||||
if (cap->randomize_mac_addr &&
|
||||
nla_put_flag(msg, NL80211_PMSR_ATTR_RANDOMIZE_MAC_ADDR))
|
||||
return -ENOBUFS;
|
||||
|
||||
caps = nla_nest_start(msg, NL80211_PMSR_ATTR_TYPE_CAPA);
|
||||
if (!caps)
|
||||
return -ENOBUFS;
|
||||
|
||||
if (nl80211_send_pmsr_ftm_capa(cap, msg))
|
||||
return -ENOBUFS;
|
||||
|
||||
nla_nest_end(msg, caps);
|
||||
nla_nest_end(msg, pmsr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct nl80211_dump_wiphy_state {
|
||||
s64 filter_wiphy;
|
||||
long start;
|
||||
|
|
@ -1706,6 +1851,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
|
|||
state->split_start++;
|
||||
if (state->split)
|
||||
break;
|
||||
/* fall through */
|
||||
case 1:
|
||||
if (nla_put(msg, NL80211_ATTR_CIPHER_SUITES,
|
||||
sizeof(u32) * rdev->wiphy.n_cipher_suites,
|
||||
|
|
@ -1752,6 +1898,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
|
|||
state->split_start++;
|
||||
if (state->split)
|
||||
break;
|
||||
/* fall through */
|
||||
case 2:
|
||||
if (nl80211_put_iftypes(msg, NL80211_ATTR_SUPPORTED_IFTYPES,
|
||||
rdev->wiphy.interface_modes))
|
||||
|
|
@ -1759,6 +1906,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
|
|||
state->split_start++;
|
||||
if (state->split)
|
||||
break;
|
||||
/* fall through */
|
||||
case 3:
|
||||
nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS);
|
||||
if (!nl_bands)
|
||||
|
|
@ -1784,6 +1932,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
|
|||
state->chan_start++;
|
||||
if (state->split)
|
||||
break;
|
||||
/* fall through */
|
||||
default:
|
||||
/* add frequencies */
|
||||
nl_freqs = nla_nest_start(
|
||||
|
|
@ -1837,6 +1986,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
|
|||
state->split_start++;
|
||||
if (state->split)
|
||||
break;
|
||||
/* fall through */
|
||||
case 4:
|
||||
nl_cmds = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_COMMANDS);
|
||||
if (!nl_cmds)
|
||||
|
|
@ -1863,6 +2013,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
|
|||
state->split_start++;
|
||||
if (state->split)
|
||||
break;
|
||||
/* fall through */
|
||||
case 5:
|
||||
if (rdev->ops->remain_on_channel &&
|
||||
(rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL) &&
|
||||
|
|
@ -1880,6 +2031,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
|
|||
state->split_start++;
|
||||
if (state->split)
|
||||
break;
|
||||
/* fall through */
|
||||
case 6:
|
||||
#ifdef CONFIG_PM
|
||||
if (nl80211_send_wowlan(msg, rdev, state->split))
|
||||
|
|
@ -1890,6 +2042,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
|
|||
#else
|
||||
state->split_start++;
|
||||
#endif
|
||||
/* fall through */
|
||||
case 7:
|
||||
if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES,
|
||||
rdev->wiphy.software_iftypes))
|
||||
|
|
@ -1902,6 +2055,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
|
|||
state->split_start++;
|
||||
if (state->split)
|
||||
break;
|
||||
/* fall through */
|
||||
case 8:
|
||||
if ((rdev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME) &&
|
||||
nla_put_u32(msg, NL80211_ATTR_DEVICE_AP_SME,
|
||||
|
|
@ -2118,6 +2272,12 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
|
|||
goto nla_put_failure;
|
||||
}
|
||||
|
||||
state->split_start++;
|
||||
break;
|
||||
case 14:
|
||||
if (nl80211_send_pmsr_capa(rdev, msg))
|
||||
goto nla_put_failure;
|
||||
|
||||
/* done */
|
||||
state->split_start = 0;
|
||||
break;
|
||||
|
|
@ -2318,9 +2478,9 @@ static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev)
|
|||
wdev->iftype == NL80211_IFTYPE_P2P_GO;
|
||||
}
|
||||
|
||||
static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
|
||||
struct genl_info *info,
|
||||
struct cfg80211_chan_def *chandef)
|
||||
int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
|
||||
struct genl_info *info,
|
||||
struct cfg80211_chan_def *chandef)
|
||||
{
|
||||
struct netlink_ext_ack *extack = info->extack;
|
||||
struct nlattr **attrs = info->attrs;
|
||||
|
|
@ -2794,12 +2954,6 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline u64 wdev_id(struct wireless_dev *wdev)
|
||||
{
|
||||
return (u64)wdev->identifier |
|
||||
((u64)wiphy_to_rdev(wdev->wiphy)->wiphy_idx << 32);
|
||||
}
|
||||
|
||||
static int nl80211_send_chandef(struct sk_buff *msg,
|
||||
const struct cfg80211_chan_def *chandef)
|
||||
{
|
||||
|
|
@ -2832,14 +2986,15 @@ static int nl80211_send_chandef(struct sk_buff *msg,
|
|||
|
||||
static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flags,
|
||||
struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev, bool removal)
|
||||
struct wireless_dev *wdev,
|
||||
enum nl80211_commands cmd)
|
||||
{
|
||||
struct net_device *dev = wdev->netdev;
|
||||
u8 cmd = NL80211_CMD_NEW_INTERFACE;
|
||||
void *hdr;
|
||||
|
||||
if (removal)
|
||||
cmd = NL80211_CMD_DEL_INTERFACE;
|
||||
WARN_ON(cmd != NL80211_CMD_NEW_INTERFACE &&
|
||||
cmd != NL80211_CMD_DEL_INTERFACE &&
|
||||
cmd != NL80211_CMD_SET_INTERFACE);
|
||||
|
||||
hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
|
||||
if (!hdr)
|
||||
|
|
@ -2987,7 +3142,8 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *
|
|||
}
|
||||
if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).portid,
|
||||
cb->nlh->nlmsg_seq, NLM_F_MULTI,
|
||||
rdev, wdev, false) < 0) {
|
||||
rdev, wdev,
|
||||
NL80211_CMD_NEW_INTERFACE) < 0) {
|
||||
goto out;
|
||||
}
|
||||
if_idx++;
|
||||
|
|
@ -3017,7 +3173,7 @@ static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info)
|
|||
return -ENOMEM;
|
||||
|
||||
if (nl80211_send_iface(msg, info->snd_portid, info->snd_seq, 0,
|
||||
rdev, wdev, false) < 0) {
|
||||
rdev, wdev, NL80211_CMD_NEW_INTERFACE) < 0) {
|
||||
nlmsg_free(msg);
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
|
@ -3207,6 +3363,12 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
|
|||
if (!err && params.use_4addr != -1)
|
||||
dev->ieee80211_ptr->use_4addr = params.use_4addr;
|
||||
|
||||
if (change && !err) {
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
|
||||
nl80211_notify_iface(rdev, wdev, NL80211_CMD_SET_INTERFACE);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
@ -3298,7 +3460,7 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
|
|||
}
|
||||
|
||||
if (nl80211_send_iface(msg, info->snd_portid, info->snd_seq, 0,
|
||||
rdev, wdev, false) < 0) {
|
||||
rdev, wdev, NL80211_CMD_NEW_INTERFACE) < 0) {
|
||||
nlmsg_free(msg);
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
|
@ -4521,8 +4683,7 @@ static int parse_station_flags(struct genl_info *info,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info,
|
||||
int attr)
|
||||
bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info, int attr)
|
||||
{
|
||||
struct nlattr *rate;
|
||||
u32 bitrate;
|
||||
|
|
@ -4731,6 +4892,7 @@ static int nl80211_send_station(struct sk_buff *msg, u32 cmd, u32 portid,
|
|||
PUT_SINFO(LOCAL_PM, local_pm, u32);
|
||||
PUT_SINFO(PEER_PM, peer_pm, u32);
|
||||
PUT_SINFO(NONPEER_PM, nonpeer_pm, u32);
|
||||
PUT_SINFO(CONNECTED_TO_GATE, connected_to_gate, u8);
|
||||
|
||||
if (sinfo->filled & BIT_ULL(NL80211_STA_INFO_BSS_PARAM)) {
|
||||
bss_param = nla_nest_start(msg, NL80211_STA_INFO_BSS_PARAM);
|
||||
|
|
@ -6122,7 +6284,9 @@ static int nl80211_get_mesh_config(struct sk_buff *skb,
|
|||
nla_put_u16(msg, NL80211_MESHCONF_AWAKE_WINDOW,
|
||||
cur_params.dot11MeshAwakeWindowDuration) ||
|
||||
nla_put_u32(msg, NL80211_MESHCONF_PLINK_TIMEOUT,
|
||||
cur_params.plink_timeout))
|
||||
cur_params.plink_timeout) ||
|
||||
nla_put_u8(msg, NL80211_MESHCONF_CONNECTED_TO_GATE,
|
||||
cur_params.dot11MeshConnectedToMeshGate))
|
||||
goto nla_put_failure;
|
||||
nla_nest_end(msg, pinfoattr);
|
||||
genlmsg_end(msg, hdr);
|
||||
|
|
@ -6179,6 +6343,7 @@ nl80211_meshconf_params_policy[NL80211_MESHCONF_ATTR_MAX+1] = {
|
|||
NL80211_MESH_POWER_MAX),
|
||||
[NL80211_MESHCONF_AWAKE_WINDOW] = { .type = NLA_U16 },
|
||||
[NL80211_MESHCONF_PLINK_TIMEOUT] = { .type = NLA_U32 },
|
||||
[NL80211_MESHCONF_CONNECTED_TO_GATE] = NLA_POLICY_RANGE(NLA_U8, 0, 1),
|
||||
};
|
||||
|
||||
static const struct nla_policy
|
||||
|
|
@ -6290,6 +6455,9 @@ do { \
|
|||
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, rssi_threshold, mask,
|
||||
NL80211_MESHCONF_RSSI_THRESHOLD,
|
||||
nla_get_s32);
|
||||
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshConnectedToMeshGate, mask,
|
||||
NL80211_MESHCONF_CONNECTED_TO_GATE,
|
||||
nla_get_u8);
|
||||
/*
|
||||
* Check HT operation mode based on
|
||||
* IEEE 802.11-2016 9.4.2.57 HT Operation element.
|
||||
|
|
@ -6855,8 +7023,8 @@ static int parse_bss_select(struct nlattr *nla, struct wiphy *wiphy,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int nl80211_parse_random_mac(struct nlattr **attrs,
|
||||
u8 *mac_addr, u8 *mac_addr_mask)
|
||||
int nl80211_parse_random_mac(struct nlattr **attrs,
|
||||
u8 *mac_addr, u8 *mac_addr_mask)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
|
@ -7822,6 +7990,60 @@ static int nl80211_start_radar_detection(struct sk_buff *skb,
|
|||
return err;
|
||||
}
|
||||
|
||||
static int nl80211_notify_radar_detection(struct sk_buff *skb,
|
||||
struct genl_info *info)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = info->user_ptr[0];
|
||||
struct net_device *dev = info->user_ptr[1];
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct wiphy *wiphy = wdev->wiphy;
|
||||
struct cfg80211_chan_def chandef;
|
||||
enum nl80211_dfs_regions dfs_region;
|
||||
int err;
|
||||
|
||||
dfs_region = reg_get_dfs_region(wiphy);
|
||||
if (dfs_region == NL80211_DFS_UNSET) {
|
||||
GENL_SET_ERR_MSG(info,
|
||||
"DFS Region is not set. Unexpected Radar indication");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = nl80211_parse_chandef(rdev, info, &chandef);
|
||||
if (err) {
|
||||
GENL_SET_ERR_MSG(info, "Unable to extract chandef info");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = cfg80211_chandef_dfs_required(wiphy, &chandef, wdev->iftype);
|
||||
if (err < 0) {
|
||||
GENL_SET_ERR_MSG(info, "chandef is invalid");
|
||||
return err;
|
||||
}
|
||||
|
||||
if (err == 0) {
|
||||
GENL_SET_ERR_MSG(info,
|
||||
"Unexpected Radar indication for chandef/iftype");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Do not process this notification if radar is already detected
|
||||
* by kernel on this channel, and return success.
|
||||
*/
|
||||
if (chandef.chan->dfs_state == NL80211_DFS_UNAVAILABLE)
|
||||
return 0;
|
||||
|
||||
cfg80211_set_dfs_state(wiphy, &chandef, NL80211_DFS_UNAVAILABLE);
|
||||
|
||||
cfg80211_sched_dfs_chan_update(rdev);
|
||||
|
||||
memcpy(&rdev->radar_chandef, &chandef, sizeof(chandef));
|
||||
|
||||
/* Propagate this notification to other radios as well */
|
||||
queue_work(cfg80211_wq, &rdev->propagate_radar_detect_wk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = info->user_ptr[0];
|
||||
|
|
@ -13899,6 +14121,22 @@ static const struct genl_ops nl80211_ops[] = {
|
|||
.internal_flags = NL80211_FLAG_NEED_NETDEV |
|
||||
NL80211_FLAG_NEED_RTNL,
|
||||
},
|
||||
{
|
||||
.cmd = NL80211_CMD_PEER_MEASUREMENT_START,
|
||||
.doit = nl80211_pmsr_start,
|
||||
.policy = nl80211_policy,
|
||||
.flags = GENL_UNS_ADMIN_PERM,
|
||||
.internal_flags = NL80211_FLAG_NEED_WDEV_UP |
|
||||
NL80211_FLAG_NEED_RTNL,
|
||||
},
|
||||
{
|
||||
.cmd = NL80211_CMD_NOTIFY_RADAR,
|
||||
.doit = nl80211_notify_radar_detection,
|
||||
.policy = nl80211_policy,
|
||||
.flags = GENL_UNS_ADMIN_PERM,
|
||||
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
|
||||
NL80211_FLAG_NEED_RTNL,
|
||||
},
|
||||
};
|
||||
|
||||
static struct genl_family nl80211_fam __ro_after_init = {
|
||||
|
|
@ -13946,15 +14184,11 @@ void nl80211_notify_iface(struct cfg80211_registered_device *rdev,
|
|||
{
|
||||
struct sk_buff *msg;
|
||||
|
||||
WARN_ON(cmd != NL80211_CMD_NEW_INTERFACE &&
|
||||
cmd != NL80211_CMD_DEL_INTERFACE);
|
||||
|
||||
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
||||
if (!msg)
|
||||
return;
|
||||
|
||||
if (nl80211_send_iface(msg, 0, 0, 0, rdev, wdev,
|
||||
cmd == NL80211_CMD_DEL_INTERFACE) < 0) {
|
||||
if (nl80211_send_iface(msg, 0, 0, 0, rdev, wdev, cmd) < 0) {
|
||||
nlmsg_free(msg);
|
||||
return;
|
||||
}
|
||||
|
|
@ -14573,7 +14807,8 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
|
|||
}
|
||||
|
||||
void cfg80211_notify_new_peer_candidate(struct net_device *dev, const u8 *addr,
|
||||
const u8* ie, u8 ie_len, gfp_t gfp)
|
||||
const u8 *ie, u8 ie_len,
|
||||
int sig_dbm, gfp_t gfp)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
|
||||
|
|
@ -14599,7 +14834,9 @@ void cfg80211_notify_new_peer_candidate(struct net_device *dev, const u8 *addr,
|
|||
nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
|
||||
nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
|
||||
(ie_len && ie &&
|
||||
nla_put(msg, NL80211_ATTR_IE, ie_len , ie)))
|
||||
nla_put(msg, NL80211_ATTR_IE, ie_len, ie)) ||
|
||||
(sig_dbm &&
|
||||
nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)))
|
||||
goto nla_put_failure;
|
||||
|
||||
genlmsg_end(msg, hdr);
|
||||
|
|
@ -15882,6 +16119,8 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
|
|||
} else if (wdev->conn_owner_nlportid == notify->portid) {
|
||||
schedule_work(&wdev->disconnect_wk);
|
||||
}
|
||||
|
||||
cfg80211_release_pmsr(wdev, notify->portid);
|
||||
}
|
||||
|
||||
spin_lock_bh(&rdev->beacon_registrations_lock);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Portions of this file
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
*/
|
||||
#ifndef __NET_WIRELESS_NL80211_H
|
||||
#define __NET_WIRELESS_NL80211_H
|
||||
|
||||
|
|
@ -6,6 +10,30 @@
|
|||
|
||||
int nl80211_init(void);
|
||||
void nl80211_exit(void);
|
||||
|
||||
extern const struct nla_policy nl80211_policy[NUM_NL80211_ATTR];
|
||||
|
||||
void *nl80211hdr_put(struct sk_buff *skb, u32 portid, u32 seq,
|
||||
int flags, u8 cmd);
|
||||
bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info,
|
||||
int attr);
|
||||
|
||||
static inline u64 wdev_id(struct wireless_dev *wdev)
|
||||
{
|
||||
return (u64)wdev->identifier |
|
||||
((u64)wiphy_to_rdev(wdev->wiphy)->wiphy_idx << 32);
|
||||
}
|
||||
|
||||
int nl80211_prepare_wdev_dump(struct netlink_callback *cb,
|
||||
struct cfg80211_registered_device **rdev,
|
||||
struct wireless_dev **wdev);
|
||||
|
||||
int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
|
||||
struct genl_info *info,
|
||||
struct cfg80211_chan_def *chandef);
|
||||
int nl80211_parse_random_mac(struct nlattr **attrs,
|
||||
u8 *mac_addr, u8 *mac_addr_mask);
|
||||
|
||||
void nl80211_notify_wiphy(struct cfg80211_registered_device *rdev,
|
||||
enum nl80211_commands cmd);
|
||||
void nl80211_notify_iface(struct cfg80211_registered_device *rdev,
|
||||
|
|
@ -95,4 +123,8 @@ void nl80211_send_ap_stopped(struct wireless_dev *wdev);
|
|||
|
||||
void cfg80211_rdev_free_coalesce(struct cfg80211_registered_device *rdev);
|
||||
|
||||
/* peer measurement */
|
||||
int nl80211_pmsr_start(struct sk_buff *skb, struct genl_info *info);
|
||||
int nl80211_pmsr_dump_results(struct sk_buff *skb, struct netlink_callback *cb);
|
||||
|
||||
#endif /* __NET_WIRELESS_NL80211_H */
|
||||
|
|
|
|||
590
net/wireless/pmsr.c
Normal file
590
net/wireless/pmsr.c
Normal file
|
|
@ -0,0 +1,590 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
*/
|
||||
#ifndef __PMSR_H
|
||||
#define __PMSR_H
|
||||
#include <net/cfg80211.h>
|
||||
#include "core.h"
|
||||
#include "nl80211.h"
|
||||
#include "rdev-ops.h"
|
||||
|
||||
static int pmsr_parse_ftm(struct cfg80211_registered_device *rdev,
|
||||
struct nlattr *ftmreq,
|
||||
struct cfg80211_pmsr_request_peer *out,
|
||||
struct genl_info *info)
|
||||
{
|
||||
const struct cfg80211_pmsr_capabilities *capa = rdev->wiphy.pmsr_capa;
|
||||
struct nlattr *tb[NL80211_PMSR_FTM_REQ_ATTR_MAX + 1];
|
||||
u32 preamble = NL80211_PREAMBLE_DMG; /* only optional in DMG */
|
||||
|
||||
/* validate existing data */
|
||||
if (!(rdev->wiphy.pmsr_capa->ftm.bandwidths & BIT(out->chandef.width))) {
|
||||
NL_SET_ERR_MSG(info->extack, "FTM: unsupported bandwidth");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* no validation needed - was already done via nested policy */
|
||||
nla_parse_nested(tb, NL80211_PMSR_FTM_REQ_ATTR_MAX, ftmreq, NULL, NULL);
|
||||
|
||||
if (tb[NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE])
|
||||
preamble = nla_get_u32(tb[NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE]);
|
||||
|
||||
/* set up values - struct is 0-initialized */
|
||||
out->ftm.requested = true;
|
||||
|
||||
switch (out->chandef.chan->band) {
|
||||
case NL80211_BAND_60GHZ:
|
||||
/* optional */
|
||||
break;
|
||||
default:
|
||||
if (!tb[NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE]) {
|
||||
NL_SET_ERR_MSG(info->extack,
|
||||
"FTM: must specify preamble");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(capa->ftm.preambles & BIT(preamble))) {
|
||||
NL_SET_ERR_MSG_ATTR(info->extack,
|
||||
tb[NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE],
|
||||
"FTM: invalid preamble");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
out->ftm.preamble = preamble;
|
||||
|
||||
out->ftm.burst_period = 0;
|
||||
if (tb[NL80211_PMSR_FTM_REQ_ATTR_BURST_PERIOD])
|
||||
out->ftm.burst_period =
|
||||
nla_get_u32(tb[NL80211_PMSR_FTM_REQ_ATTR_BURST_PERIOD]);
|
||||
|
||||
out->ftm.asap = !!tb[NL80211_PMSR_FTM_REQ_ATTR_ASAP];
|
||||
if (out->ftm.asap && !capa->ftm.asap) {
|
||||
NL_SET_ERR_MSG_ATTR(info->extack,
|
||||
tb[NL80211_PMSR_FTM_REQ_ATTR_ASAP],
|
||||
"FTM: ASAP mode not supported");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!out->ftm.asap && !capa->ftm.non_asap) {
|
||||
NL_SET_ERR_MSG(info->extack,
|
||||
"FTM: non-ASAP mode not supported");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
out->ftm.num_bursts_exp = 0;
|
||||
if (tb[NL80211_PMSR_FTM_REQ_ATTR_NUM_BURSTS_EXP])
|
||||
out->ftm.num_bursts_exp =
|
||||
nla_get_u32(tb[NL80211_PMSR_FTM_REQ_ATTR_NUM_BURSTS_EXP]);
|
||||
|
||||
if (capa->ftm.max_bursts_exponent >= 0 &&
|
||||
out->ftm.num_bursts_exp > capa->ftm.max_bursts_exponent) {
|
||||
NL_SET_ERR_MSG_ATTR(info->extack,
|
||||
tb[NL80211_PMSR_FTM_REQ_ATTR_NUM_BURSTS_EXP],
|
||||
"FTM: max NUM_BURSTS_EXP must be set lower than the device limit");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
out->ftm.burst_duration = 15;
|
||||
if (tb[NL80211_PMSR_FTM_REQ_ATTR_BURST_DURATION])
|
||||
out->ftm.burst_duration =
|
||||
nla_get_u32(tb[NL80211_PMSR_FTM_REQ_ATTR_BURST_DURATION]);
|
||||
|
||||
out->ftm.ftms_per_burst = 0;
|
||||
if (tb[NL80211_PMSR_FTM_REQ_ATTR_FTMS_PER_BURST])
|
||||
out->ftm.ftms_per_burst =
|
||||
nla_get_u32(tb[NL80211_PMSR_FTM_REQ_ATTR_FTMS_PER_BURST]);
|
||||
|
||||
if (capa->ftm.max_ftms_per_burst &&
|
||||
(out->ftm.ftms_per_burst > capa->ftm.max_ftms_per_burst ||
|
||||
out->ftm.ftms_per_burst == 0)) {
|
||||
NL_SET_ERR_MSG_ATTR(info->extack,
|
||||
tb[NL80211_PMSR_FTM_REQ_ATTR_FTMS_PER_BURST],
|
||||
"FTM: FTMs per burst must be set lower than the device limit but non-zero");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
out->ftm.ftmr_retries = 3;
|
||||
if (tb[NL80211_PMSR_FTM_REQ_ATTR_NUM_FTMR_RETRIES])
|
||||
out->ftm.ftmr_retries =
|
||||
nla_get_u32(tb[NL80211_PMSR_FTM_REQ_ATTR_NUM_FTMR_RETRIES]);
|
||||
|
||||
out->ftm.request_lci = !!tb[NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI];
|
||||
if (out->ftm.request_lci && !capa->ftm.request_lci) {
|
||||
NL_SET_ERR_MSG_ATTR(info->extack,
|
||||
tb[NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI],
|
||||
"FTM: LCI request not supported");
|
||||
}
|
||||
|
||||
out->ftm.request_civicloc =
|
||||
!!tb[NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC];
|
||||
if (out->ftm.request_civicloc && !capa->ftm.request_civicloc) {
|
||||
NL_SET_ERR_MSG_ATTR(info->extack,
|
||||
tb[NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC],
|
||||
"FTM: civic location request not supported");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pmsr_parse_peer(struct cfg80211_registered_device *rdev,
|
||||
struct nlattr *peer,
|
||||
struct cfg80211_pmsr_request_peer *out,
|
||||
struct genl_info *info)
|
||||
{
|
||||
struct nlattr *tb[NL80211_PMSR_PEER_ATTR_MAX + 1];
|
||||
struct nlattr *req[NL80211_PMSR_REQ_ATTR_MAX + 1];
|
||||
struct nlattr *treq;
|
||||
int err, rem;
|
||||
|
||||
/* no validation needed - was already done via nested policy */
|
||||
nla_parse_nested(tb, NL80211_PMSR_PEER_ATTR_MAX, peer, NULL, NULL);
|
||||
|
||||
if (!tb[NL80211_PMSR_PEER_ATTR_ADDR] ||
|
||||
!tb[NL80211_PMSR_PEER_ATTR_CHAN] ||
|
||||
!tb[NL80211_PMSR_PEER_ATTR_REQ]) {
|
||||
NL_SET_ERR_MSG_ATTR(info->extack, peer,
|
||||
"insufficient peer data");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memcpy(out->addr, nla_data(tb[NL80211_PMSR_PEER_ATTR_ADDR]), ETH_ALEN);
|
||||
|
||||
/* reuse info->attrs */
|
||||
memset(info->attrs, 0, sizeof(*info->attrs) * (NL80211_ATTR_MAX + 1));
|
||||
/* need to validate here, we don't want to have validation recursion */
|
||||
err = nla_parse_nested(info->attrs, NL80211_ATTR_MAX,
|
||||
tb[NL80211_PMSR_PEER_ATTR_CHAN],
|
||||
nl80211_policy, info->extack);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = nl80211_parse_chandef(rdev, info, &out->chandef);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* no validation needed - was already done via nested policy */
|
||||
nla_parse_nested(req, NL80211_PMSR_REQ_ATTR_MAX,
|
||||
tb[NL80211_PMSR_PEER_ATTR_REQ],
|
||||
NULL, NULL);
|
||||
|
||||
if (!req[NL80211_PMSR_REQ_ATTR_DATA]) {
|
||||
NL_SET_ERR_MSG_ATTR(info->extack,
|
||||
tb[NL80211_PMSR_PEER_ATTR_REQ],
|
||||
"missing request type/data");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (req[NL80211_PMSR_REQ_ATTR_GET_AP_TSF])
|
||||
out->report_ap_tsf = true;
|
||||
|
||||
if (out->report_ap_tsf && !rdev->wiphy.pmsr_capa->report_ap_tsf) {
|
||||
NL_SET_ERR_MSG_ATTR(info->extack,
|
||||
req[NL80211_PMSR_REQ_ATTR_GET_AP_TSF],
|
||||
"reporting AP TSF is not supported");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
nla_for_each_nested(treq, req[NL80211_PMSR_REQ_ATTR_DATA], rem) {
|
||||
switch (nla_type(treq)) {
|
||||
case NL80211_PMSR_TYPE_FTM:
|
||||
err = pmsr_parse_ftm(rdev, treq, out, info);
|
||||
break;
|
||||
default:
|
||||
NL_SET_ERR_MSG_ATTR(info->extack, treq,
|
||||
"unsupported measurement type");
|
||||
err = -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nl80211_pmsr_start(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct nlattr *reqattr = info->attrs[NL80211_ATTR_PEER_MEASUREMENTS];
|
||||
struct cfg80211_registered_device *rdev = info->user_ptr[0];
|
||||
struct wireless_dev *wdev = info->user_ptr[1];
|
||||
struct cfg80211_pmsr_request *req;
|
||||
struct nlattr *peers, *peer;
|
||||
int count, rem, err, idx;
|
||||
|
||||
if (!rdev->wiphy.pmsr_capa)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!reqattr)
|
||||
return -EINVAL;
|
||||
|
||||
peers = nla_find(nla_data(reqattr), nla_len(reqattr),
|
||||
NL80211_PMSR_ATTR_PEERS);
|
||||
if (!peers)
|
||||
return -EINVAL;
|
||||
|
||||
count = 0;
|
||||
nla_for_each_nested(peer, peers, rem) {
|
||||
count++;
|
||||
|
||||
if (count > rdev->wiphy.pmsr_capa->max_peers) {
|
||||
NL_SET_ERR_MSG_ATTR(info->extack, peer,
|
||||
"Too many peers used");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
req = kzalloc(struct_size(req, peers, count), GFP_KERNEL);
|
||||
if (!req)
|
||||
return -ENOMEM;
|
||||
|
||||
if (info->attrs[NL80211_ATTR_TIMEOUT])
|
||||
req->timeout = nla_get_u32(info->attrs[NL80211_ATTR_TIMEOUT]);
|
||||
|
||||
if (info->attrs[NL80211_ATTR_MAC]) {
|
||||
if (!rdev->wiphy.pmsr_capa->randomize_mac_addr) {
|
||||
NL_SET_ERR_MSG_ATTR(info->extack,
|
||||
info->attrs[NL80211_ATTR_MAC],
|
||||
"device cannot randomize MAC address");
|
||||
err = -EINVAL;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
err = nl80211_parse_random_mac(info->attrs, req->mac_addr,
|
||||
req->mac_addr_mask);
|
||||
if (err)
|
||||
goto out_err;
|
||||
} else {
|
||||
memcpy(req->mac_addr, nla_data(info->attrs[NL80211_ATTR_MAC]),
|
||||
ETH_ALEN);
|
||||
memset(req->mac_addr_mask, 0xff, ETH_ALEN);
|
||||
}
|
||||
|
||||
idx = 0;
|
||||
nla_for_each_nested(peer, peers, rem) {
|
||||
/* NB: this reuses info->attrs, but we no longer need it */
|
||||
err = pmsr_parse_peer(rdev, peer, &req->peers[idx], info);
|
||||
if (err)
|
||||
goto out_err;
|
||||
idx++;
|
||||
}
|
||||
|
||||
req->n_peers = count;
|
||||
req->cookie = cfg80211_assign_cookie(rdev);
|
||||
|
||||
err = rdev_start_pmsr(rdev, wdev, req);
|
||||
if (err)
|
||||
goto out_err;
|
||||
|
||||
list_add_tail(&req->list, &wdev->pmsr_list);
|
||||
|
||||
nl_set_extack_cookie_u64(info->extack, req->cookie);
|
||||
return 0;
|
||||
out_err:
|
||||
kfree(req);
|
||||
return err;
|
||||
}
|
||||
|
||||
void cfg80211_pmsr_complete(struct wireless_dev *wdev,
|
||||
struct cfg80211_pmsr_request *req,
|
||||
gfp_t gfp)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
|
||||
struct sk_buff *msg;
|
||||
void *hdr;
|
||||
|
||||
trace_cfg80211_pmsr_complete(wdev->wiphy, wdev, req->cookie);
|
||||
|
||||
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
|
||||
if (!msg)
|
||||
goto free_request;
|
||||
|
||||
hdr = nl80211hdr_put(msg, 0, 0, 0,
|
||||
NL80211_CMD_PEER_MEASUREMENT_COMPLETE);
|
||||
if (!hdr)
|
||||
goto free_msg;
|
||||
|
||||
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
|
||||
nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
|
||||
NL80211_ATTR_PAD))
|
||||
goto free_msg;
|
||||
|
||||
if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, req->cookie,
|
||||
NL80211_ATTR_PAD))
|
||||
goto free_msg;
|
||||
|
||||
genlmsg_end(msg, hdr);
|
||||
genlmsg_unicast(wiphy_net(wdev->wiphy), msg, req->nl_portid);
|
||||
goto free_request;
|
||||
free_msg:
|
||||
nlmsg_free(msg);
|
||||
free_request:
|
||||
spin_lock_bh(&wdev->pmsr_lock);
|
||||
list_del(&req->list);
|
||||
spin_unlock_bh(&wdev->pmsr_lock);
|
||||
kfree(req);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cfg80211_pmsr_complete);
|
||||
|
||||
static int nl80211_pmsr_send_ftm_res(struct sk_buff *msg,
|
||||
struct cfg80211_pmsr_result *res)
|
||||
{
|
||||
if (res->status == NL80211_PMSR_STATUS_FAILURE) {
|
||||
if (nla_put_u32(msg, NL80211_PMSR_FTM_RESP_ATTR_FAIL_REASON,
|
||||
res->ftm.failure_reason))
|
||||
goto error;
|
||||
|
||||
if (res->ftm.failure_reason ==
|
||||
NL80211_PMSR_FTM_FAILURE_PEER_BUSY &&
|
||||
res->ftm.busy_retry_time &&
|
||||
nla_put_u32(msg, NL80211_PMSR_FTM_RESP_ATTR_BUSY_RETRY_TIME,
|
||||
res->ftm.busy_retry_time))
|
||||
goto error;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define PUT(tp, attr, val) \
|
||||
do { \
|
||||
if (nla_put_##tp(msg, \
|
||||
NL80211_PMSR_FTM_RESP_ATTR_##attr, \
|
||||
res->ftm.val)) \
|
||||
goto error; \
|
||||
} while (0)
|
||||
|
||||
#define PUTOPT(tp, attr, val) \
|
||||
do { \
|
||||
if (res->ftm.val##_valid) \
|
||||
PUT(tp, attr, val); \
|
||||
} while (0)
|
||||
|
||||
#define PUT_U64(attr, val) \
|
||||
do { \
|
||||
if (nla_put_u64_64bit(msg, \
|
||||
NL80211_PMSR_FTM_RESP_ATTR_##attr,\
|
||||
res->ftm.val, \
|
||||
NL80211_PMSR_FTM_RESP_ATTR_PAD)) \
|
||||
goto error; \
|
||||
} while (0)
|
||||
|
||||
#define PUTOPT_U64(attr, val) \
|
||||
do { \
|
||||
if (res->ftm.val##_valid) \
|
||||
PUT_U64(attr, val); \
|
||||
} while (0)
|
||||
|
||||
if (res->ftm.burst_index >= 0)
|
||||
PUT(u32, BURST_INDEX, burst_index);
|
||||
PUTOPT(u32, NUM_FTMR_ATTEMPTS, num_ftmr_attempts);
|
||||
PUTOPT(u32, NUM_FTMR_SUCCESSES, num_ftmr_successes);
|
||||
PUT(u8, NUM_BURSTS_EXP, num_bursts_exp);
|
||||
PUT(u8, BURST_DURATION, burst_duration);
|
||||
PUT(u8, FTMS_PER_BURST, ftms_per_burst);
|
||||
PUTOPT(s32, RSSI_AVG, rssi_avg);
|
||||
PUTOPT(s32, RSSI_SPREAD, rssi_spread);
|
||||
if (res->ftm.tx_rate_valid &&
|
||||
!nl80211_put_sta_rate(msg, &res->ftm.tx_rate,
|
||||
NL80211_PMSR_FTM_RESP_ATTR_TX_RATE))
|
||||
goto error;
|
||||
if (res->ftm.rx_rate_valid &&
|
||||
!nl80211_put_sta_rate(msg, &res->ftm.rx_rate,
|
||||
NL80211_PMSR_FTM_RESP_ATTR_RX_RATE))
|
||||
goto error;
|
||||
PUTOPT_U64(RTT_AVG, rtt_avg);
|
||||
PUTOPT_U64(RTT_VARIANCE, rtt_variance);
|
||||
PUTOPT_U64(RTT_SPREAD, rtt_spread);
|
||||
PUTOPT_U64(DIST_AVG, dist_avg);
|
||||
PUTOPT_U64(DIST_VARIANCE, dist_variance);
|
||||
PUTOPT_U64(DIST_SPREAD, dist_spread);
|
||||
if (res->ftm.lci && res->ftm.lci_len &&
|
||||
nla_put(msg, NL80211_PMSR_FTM_RESP_ATTR_LCI,
|
||||
res->ftm.lci_len, res->ftm.lci))
|
||||
goto error;
|
||||
if (res->ftm.civicloc && res->ftm.civicloc_len &&
|
||||
nla_put(msg, NL80211_PMSR_FTM_RESP_ATTR_CIVICLOC,
|
||||
res->ftm.civicloc_len, res->ftm.civicloc))
|
||||
goto error;
|
||||
#undef PUT
|
||||
#undef PUTOPT
|
||||
#undef PUT_U64
|
||||
#undef PUTOPT_U64
|
||||
|
||||
return 0;
|
||||
error:
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
static int nl80211_pmsr_send_result(struct sk_buff *msg,
|
||||
struct cfg80211_pmsr_result *res)
|
||||
{
|
||||
struct nlattr *pmsr, *peers, *peer, *resp, *data, *typedata;
|
||||
|
||||
pmsr = nla_nest_start(msg, NL80211_ATTR_PEER_MEASUREMENTS);
|
||||
if (!pmsr)
|
||||
goto error;
|
||||
|
||||
peers = nla_nest_start(msg, NL80211_PMSR_ATTR_PEERS);
|
||||
if (!peers)
|
||||
goto error;
|
||||
|
||||
peer = nla_nest_start(msg, 1);
|
||||
if (!peer)
|
||||
goto error;
|
||||
|
||||
if (nla_put(msg, NL80211_PMSR_PEER_ATTR_ADDR, ETH_ALEN, res->addr))
|
||||
goto error;
|
||||
|
||||
resp = nla_nest_start(msg, NL80211_PMSR_PEER_ATTR_RESP);
|
||||
if (!resp)
|
||||
goto error;
|
||||
|
||||
if (nla_put_u32(msg, NL80211_PMSR_RESP_ATTR_STATUS, res->status) ||
|
||||
nla_put_u64_64bit(msg, NL80211_PMSR_RESP_ATTR_HOST_TIME,
|
||||
res->host_time, NL80211_PMSR_RESP_ATTR_PAD))
|
||||
goto error;
|
||||
|
||||
if (res->ap_tsf_valid &&
|
||||
nla_put_u64_64bit(msg, NL80211_PMSR_RESP_ATTR_AP_TSF,
|
||||
res->host_time, NL80211_PMSR_RESP_ATTR_PAD))
|
||||
goto error;
|
||||
|
||||
if (res->final && nla_put_flag(msg, NL80211_PMSR_RESP_ATTR_FINAL))
|
||||
goto error;
|
||||
|
||||
data = nla_nest_start(msg, NL80211_PMSR_RESP_ATTR_DATA);
|
||||
if (!data)
|
||||
goto error;
|
||||
|
||||
typedata = nla_nest_start(msg, res->type);
|
||||
if (!typedata)
|
||||
goto error;
|
||||
|
||||
switch (res->type) {
|
||||
case NL80211_PMSR_TYPE_FTM:
|
||||
if (nl80211_pmsr_send_ftm_res(msg, res))
|
||||
goto error;
|
||||
break;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
}
|
||||
|
||||
nla_nest_end(msg, typedata);
|
||||
nla_nest_end(msg, data);
|
||||
nla_nest_end(msg, resp);
|
||||
nla_nest_end(msg, peer);
|
||||
nla_nest_end(msg, peers);
|
||||
nla_nest_end(msg, pmsr);
|
||||
|
||||
return 0;
|
||||
error:
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
void cfg80211_pmsr_report(struct wireless_dev *wdev,
|
||||
struct cfg80211_pmsr_request *req,
|
||||
struct cfg80211_pmsr_result *result,
|
||||
gfp_t gfp)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
|
||||
struct sk_buff *msg;
|
||||
void *hdr;
|
||||
int err;
|
||||
|
||||
trace_cfg80211_pmsr_report(wdev->wiphy, wdev, req->cookie,
|
||||
result->addr);
|
||||
|
||||
/*
|
||||
* Currently, only variable items are LCI and civic location,
|
||||
* both of which are reasonably short so we don't need to
|
||||
* worry about them here for the allocation.
|
||||
*/
|
||||
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
|
||||
if (!msg)
|
||||
return;
|
||||
|
||||
hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_PEER_MEASUREMENT_RESULT);
|
||||
if (!hdr)
|
||||
goto free;
|
||||
|
||||
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
|
||||
nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
|
||||
NL80211_ATTR_PAD))
|
||||
goto free;
|
||||
|
||||
if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, req->cookie,
|
||||
NL80211_ATTR_PAD))
|
||||
goto free;
|
||||
|
||||
err = nl80211_pmsr_send_result(msg, result);
|
||||
if (err) {
|
||||
pr_err_ratelimited("peer measurement result: message didn't fit!");
|
||||
goto free;
|
||||
}
|
||||
|
||||
genlmsg_end(msg, hdr);
|
||||
genlmsg_unicast(wiphy_net(wdev->wiphy), msg, req->nl_portid);
|
||||
return;
|
||||
free:
|
||||
nlmsg_free(msg);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cfg80211_pmsr_report);
|
||||
|
||||
void cfg80211_pmsr_free_wk(struct work_struct *work)
|
||||
{
|
||||
struct wireless_dev *wdev = container_of(work, struct wireless_dev,
|
||||
pmsr_free_wk);
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
|
||||
struct cfg80211_pmsr_request *req, *tmp;
|
||||
LIST_HEAD(free_list);
|
||||
|
||||
spin_lock_bh(&wdev->pmsr_lock);
|
||||
list_for_each_entry_safe(req, tmp, &wdev->pmsr_list, list) {
|
||||
if (req->nl_portid)
|
||||
continue;
|
||||
list_move_tail(&req->list, &free_list);
|
||||
}
|
||||
spin_unlock_bh(&wdev->pmsr_lock);
|
||||
|
||||
list_for_each_entry_safe(req, tmp, &free_list, list) {
|
||||
wdev_lock(wdev);
|
||||
rdev_abort_pmsr(rdev, wdev, req);
|
||||
wdev_unlock(wdev);
|
||||
|
||||
kfree(req);
|
||||
}
|
||||
}
|
||||
|
||||
void cfg80211_pmsr_wdev_down(struct wireless_dev *wdev)
|
||||
{
|
||||
struct cfg80211_pmsr_request *req;
|
||||
bool found = false;
|
||||
|
||||
spin_lock_bh(&wdev->pmsr_lock);
|
||||
list_for_each_entry(req, &wdev->pmsr_list, list) {
|
||||
found = true;
|
||||
req->nl_portid = 0;
|
||||
}
|
||||
spin_unlock_bh(&wdev->pmsr_lock);
|
||||
|
||||
if (found)
|
||||
schedule_work(&wdev->pmsr_free_wk);
|
||||
flush_work(&wdev->pmsr_free_wk);
|
||||
WARN_ON(!list_empty(&wdev->pmsr_list));
|
||||
}
|
||||
|
||||
void cfg80211_release_pmsr(struct wireless_dev *wdev, u32 portid)
|
||||
{
|
||||
struct cfg80211_pmsr_request *req;
|
||||
|
||||
spin_lock_bh(&wdev->pmsr_lock);
|
||||
list_for_each_entry(req, &wdev->pmsr_list, list) {
|
||||
if (req->nl_portid == portid) {
|
||||
req->nl_portid = 0;
|
||||
schedule_work(&wdev->pmsr_free_wk);
|
||||
}
|
||||
}
|
||||
spin_unlock_bh(&wdev->pmsr_lock);
|
||||
}
|
||||
|
||||
#endif /* __PMSR_H */
|
||||
|
|
@ -1247,4 +1247,29 @@ rdev_get_ftm_responder_stats(struct cfg80211_registered_device *rdev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static inline int
|
||||
rdev_start_pmsr(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev,
|
||||
struct cfg80211_pmsr_request *request)
|
||||
{
|
||||
int ret = -EOPNOTSUPP;
|
||||
|
||||
trace_rdev_start_pmsr(&rdev->wiphy, wdev, request->cookie);
|
||||
if (rdev->ops->start_pmsr)
|
||||
ret = rdev->ops->start_pmsr(&rdev->wiphy, wdev, request);
|
||||
trace_rdev_return_int(&rdev->wiphy, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void
|
||||
rdev_abort_pmsr(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev,
|
||||
struct cfg80211_pmsr_request *request)
|
||||
{
|
||||
trace_rdev_abort_pmsr(&rdev->wiphy, wdev, request->cookie);
|
||||
if (rdev->ops->abort_pmsr)
|
||||
rdev->ops->abort_pmsr(&rdev->wiphy, wdev, request);
|
||||
trace_rdev_return_void(&rdev->wiphy);
|
||||
}
|
||||
|
||||
#endif /* __CFG80211_RDEV_OPS */
|
||||
|
|
|
|||
|
|
@ -1183,7 +1183,7 @@ cfg80211_inform_bss_data(struct wiphy *wiphy,
|
|||
switch (ftype) {
|
||||
case CFG80211_BSS_FTYPE_BEACON:
|
||||
ies->from_beacon = true;
|
||||
/* fall through to assign */
|
||||
/* fall through */
|
||||
case CFG80211_BSS_FTYPE_UNKNOWN:
|
||||
rcu_assign_pointer(tmp.pub.beacon_ies, ies);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -361,6 +361,24 @@ DECLARE_EVENT_CLASS(wiphy_wdev_evt,
|
|||
TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT, WIPHY_PR_ARG, WDEV_PR_ARG)
|
||||
);
|
||||
|
||||
DECLARE_EVENT_CLASS(wiphy_wdev_cookie_evt,
|
||||
TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, u64 cookie),
|
||||
TP_ARGS(wiphy, wdev, cookie),
|
||||
TP_STRUCT__entry(
|
||||
WIPHY_ENTRY
|
||||
WDEV_ENTRY
|
||||
__field(u64, cookie)
|
||||
),
|
||||
TP_fast_assign(
|
||||
WIPHY_ASSIGN;
|
||||
WDEV_ASSIGN;
|
||||
__entry->cookie = cookie;
|
||||
),
|
||||
TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", cookie: %lld",
|
||||
WIPHY_PR_ARG, WDEV_PR_ARG,
|
||||
(unsigned long long)__entry->cookie)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(wiphy_wdev_evt, rdev_return_wdev,
|
||||
TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev),
|
||||
TP_ARGS(wiphy, wdev)
|
||||
|
|
@ -770,9 +788,9 @@ DEFINE_EVENT(wiphy_netdev_mac_evt, rdev_set_wds_peer,
|
|||
);
|
||||
|
||||
TRACE_EVENT(rdev_dump_station,
|
||||
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, int idx,
|
||||
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, int _idx,
|
||||
u8 *mac),
|
||||
TP_ARGS(wiphy, netdev, idx, mac),
|
||||
TP_ARGS(wiphy, netdev, _idx, mac),
|
||||
TP_STRUCT__entry(
|
||||
WIPHY_ENTRY
|
||||
NETDEV_ENTRY
|
||||
|
|
@ -783,7 +801,7 @@ TRACE_EVENT(rdev_dump_station,
|
|||
WIPHY_ASSIGN;
|
||||
NETDEV_ASSIGN;
|
||||
MAC_ASSIGN(sta_mac, mac);
|
||||
__entry->idx = idx;
|
||||
__entry->idx = _idx;
|
||||
),
|
||||
TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", station mac: " MAC_PR_FMT ", idx: %d",
|
||||
WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(sta_mac),
|
||||
|
|
@ -847,9 +865,9 @@ DEFINE_EVENT(mpath_evt, rdev_get_mpath,
|
|||
);
|
||||
|
||||
TRACE_EVENT(rdev_dump_mpath,
|
||||
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, int idx,
|
||||
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, int _idx,
|
||||
u8 *dst, u8 *next_hop),
|
||||
TP_ARGS(wiphy, netdev, idx, dst, next_hop),
|
||||
TP_ARGS(wiphy, netdev, _idx, dst, next_hop),
|
||||
TP_STRUCT__entry(
|
||||
WIPHY_ENTRY
|
||||
NETDEV_ENTRY
|
||||
|
|
@ -862,7 +880,7 @@ TRACE_EVENT(rdev_dump_mpath,
|
|||
NETDEV_ASSIGN;
|
||||
MAC_ASSIGN(dst, dst);
|
||||
MAC_ASSIGN(next_hop, next_hop);
|
||||
__entry->idx = idx;
|
||||
__entry->idx = _idx;
|
||||
),
|
||||
TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", index: %d, destination: "
|
||||
MAC_PR_FMT ", next hop: " MAC_PR_FMT,
|
||||
|
|
@ -892,9 +910,9 @@ TRACE_EVENT(rdev_get_mpp,
|
|||
);
|
||||
|
||||
TRACE_EVENT(rdev_dump_mpp,
|
||||
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, int idx,
|
||||
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, int _idx,
|
||||
u8 *dst, u8 *mpp),
|
||||
TP_ARGS(wiphy, netdev, idx, mpp, dst),
|
||||
TP_ARGS(wiphy, netdev, _idx, mpp, dst),
|
||||
TP_STRUCT__entry(
|
||||
WIPHY_ENTRY
|
||||
NETDEV_ENTRY
|
||||
|
|
@ -907,7 +925,7 @@ TRACE_EVENT(rdev_dump_mpp,
|
|||
NETDEV_ASSIGN;
|
||||
MAC_ASSIGN(dst, dst);
|
||||
MAC_ASSIGN(mpp, mpp);
|
||||
__entry->idx = idx;
|
||||
__entry->idx = _idx;
|
||||
),
|
||||
TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", index: %d, destination: "
|
||||
MAC_PR_FMT ", mpp: " MAC_PR_FMT,
|
||||
|
|
@ -1673,8 +1691,8 @@ TRACE_EVENT(rdev_tdls_mgmt,
|
|||
);
|
||||
|
||||
TRACE_EVENT(rdev_dump_survey,
|
||||
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, int idx),
|
||||
TP_ARGS(wiphy, netdev, idx),
|
||||
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, int _idx),
|
||||
TP_ARGS(wiphy, netdev, _idx),
|
||||
TP_STRUCT__entry(
|
||||
WIPHY_ENTRY
|
||||
NETDEV_ENTRY
|
||||
|
|
@ -1683,7 +1701,7 @@ TRACE_EVENT(rdev_dump_survey,
|
|||
TP_fast_assign(
|
||||
WIPHY_ASSIGN;
|
||||
NETDEV_ASSIGN;
|
||||
__entry->idx = idx;
|
||||
__entry->idx = _idx;
|
||||
),
|
||||
TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", index: %d",
|
||||
WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->idx)
|
||||
|
|
@ -2502,6 +2520,16 @@ TRACE_EVENT(rdev_get_ftm_responder_stats,
|
|||
__entry->out_of_window)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(wiphy_wdev_cookie_evt, rdev_start_pmsr,
|
||||
TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, u64 cookie),
|
||||
TP_ARGS(wiphy, wdev, cookie)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(wiphy_wdev_cookie_evt, rdev_abort_pmsr,
|
||||
TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, u64 cookie),
|
||||
TP_ARGS(wiphy, wdev, cookie)
|
||||
);
|
||||
|
||||
/*************************************************************
|
||||
* cfg80211 exported functions traces *
|
||||
*************************************************************/
|
||||
|
|
@ -3294,6 +3322,46 @@ TRACE_EVENT(cfg80211_stop_iface,
|
|||
TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT,
|
||||
WIPHY_PR_ARG, WDEV_PR_ARG)
|
||||
);
|
||||
|
||||
TRACE_EVENT(cfg80211_pmsr_report,
|
||||
TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
u64 cookie, const u8 *addr),
|
||||
TP_ARGS(wiphy, wdev, cookie, addr),
|
||||
TP_STRUCT__entry(
|
||||
WIPHY_ENTRY
|
||||
WDEV_ENTRY
|
||||
__field(u64, cookie)
|
||||
MAC_ENTRY(addr)
|
||||
),
|
||||
TP_fast_assign(
|
||||
WIPHY_ASSIGN;
|
||||
WDEV_ASSIGN;
|
||||
__entry->cookie = cookie;
|
||||
MAC_ASSIGN(addr, addr);
|
||||
),
|
||||
TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", cookie:%lld, " MAC_PR_FMT,
|
||||
WIPHY_PR_ARG, WDEV_PR_ARG,
|
||||
(unsigned long long)__entry->cookie,
|
||||
MAC_PR_ARG(addr))
|
||||
);
|
||||
|
||||
TRACE_EVENT(cfg80211_pmsr_complete,
|
||||
TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, u64 cookie),
|
||||
TP_ARGS(wiphy, wdev, cookie),
|
||||
TP_STRUCT__entry(
|
||||
WIPHY_ENTRY
|
||||
WDEV_ENTRY
|
||||
__field(u64, cookie)
|
||||
),
|
||||
TP_fast_assign(
|
||||
WIPHY_ASSIGN;
|
||||
WDEV_ASSIGN;
|
||||
__entry->cookie = cookie;
|
||||
),
|
||||
TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", cookie:%lld",
|
||||
WIPHY_PR_ARG, WDEV_PR_ARG,
|
||||
(unsigned long long)__entry->cookie)
|
||||
);
|
||||
#endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */
|
||||
|
||||
#undef TRACE_INCLUDE_PATH
|
||||
|
|
|
|||
|
|
@ -2015,33 +2015,32 @@ int ieee80211_get_vht_max_nss(struct ieee80211_vht_cap *cap,
|
|||
case IEEE80211_VHT_CHANWIDTH_160MHZ:
|
||||
if (supp_width == 0 &&
|
||||
(ext_nss_bw == 1 || ext_nss_bw == 2))
|
||||
return DIV_ROUND_UP(max_vht_nss, 2);
|
||||
return max_vht_nss / 2;
|
||||
if (supp_width == 0 &&
|
||||
ext_nss_bw == 3)
|
||||
return DIV_ROUND_UP(3 * max_vht_nss, 4);
|
||||
return (3 * max_vht_nss) / 4;
|
||||
if (supp_width == 1 &&
|
||||
ext_nss_bw == 3)
|
||||
return 2 * max_vht_nss;
|
||||
break;
|
||||
case IEEE80211_VHT_CHANWIDTH_80P80MHZ:
|
||||
if (supp_width == 0 &&
|
||||
(ext_nss_bw == 1 || ext_nss_bw == 2))
|
||||
if (supp_width == 0 && ext_nss_bw == 1)
|
||||
return 0; /* not possible */
|
||||
if (supp_width == 0 &&
|
||||
ext_nss_bw == 2)
|
||||
return DIV_ROUND_UP(max_vht_nss, 2);
|
||||
return max_vht_nss / 2;
|
||||
if (supp_width == 0 &&
|
||||
ext_nss_bw == 3)
|
||||
return DIV_ROUND_UP(3 * max_vht_nss, 4);
|
||||
return (3 * max_vht_nss) / 4;
|
||||
if (supp_width == 1 &&
|
||||
ext_nss_bw == 0)
|
||||
return 0; /* not possible */
|
||||
if (supp_width == 1 &&
|
||||
ext_nss_bw == 1)
|
||||
return DIV_ROUND_UP(max_vht_nss, 2);
|
||||
return max_vht_nss / 2;
|
||||
if (supp_width == 1 &&
|
||||
ext_nss_bw == 2)
|
||||
return DIV_ROUND_UP(3 * max_vht_nss, 4);
|
||||
return (3 * max_vht_nss) / 4;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue