mirror of
https://github.com/rd-stuffs/msm-4.14.git
synced 2025-02-20 11:45:48 +08:00
Merge changes If77667f2,I549752fe,Ib0ba52c5,I54ebc1bd into msm-next
* changes: wil6210: added sysfs file for FTM calibration wil6210: fix QCA_WLAN_VENDOR_ATTR_FREQ attribute ID wil6210: support FTM/AOA while unassociated wil6210: initial support for FTM and AOA
This commit is contained in:
commit
0b84313453
@ -6,6 +6,7 @@ wil6210-y += netdev.o
|
||||
wil6210-y += cfg80211.o
|
||||
wil6210-y += pcie_bus.o
|
||||
wil6210-$(CONFIG_WIL6210_DEBUGFS) += debugfs.o
|
||||
wil6210-y += sysfs.o
|
||||
wil6210-y += wmi.o
|
||||
wil6210-y += interrupt.o
|
||||
wil6210-y += txrx.o
|
||||
@ -19,6 +20,7 @@ wil6210-y += wil_platform.o
|
||||
wil6210-y += ethtool.o
|
||||
wil6210-y += wil_crash_dump.o
|
||||
wil6210-y += p2p.o
|
||||
wil6210-y += ftm.o
|
||||
|
||||
# for tracing framework to find trace.h
|
||||
CFLAGS_trace.o := -I$(src)
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <net/netlink.h>
|
||||
#include "wil6210.h"
|
||||
#include "wmi.h"
|
||||
#include "ftm.h"
|
||||
|
||||
#define WIL_MAX_ROC_DURATION_MS 5000
|
||||
|
||||
@ -115,6 +116,15 @@ nla_policy wil_rf_sector_cfg_policy[QCA_ATTR_DMG_RF_SECTOR_CFG_MAX + 1] = {
|
||||
};
|
||||
|
||||
enum qca_nl80211_vendor_subcmds {
|
||||
QCA_NL80211_VENDOR_SUBCMD_LOC_GET_CAPA = 128,
|
||||
QCA_NL80211_VENDOR_SUBCMD_FTM_START_SESSION = 129,
|
||||
QCA_NL80211_VENDOR_SUBCMD_FTM_ABORT_SESSION = 130,
|
||||
QCA_NL80211_VENDOR_SUBCMD_FTM_MEAS_RESULT = 131,
|
||||
QCA_NL80211_VENDOR_SUBCMD_FTM_SESSION_DONE = 132,
|
||||
QCA_NL80211_VENDOR_SUBCMD_FTM_CFG_RESPONDER = 133,
|
||||
QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS = 134,
|
||||
QCA_NL80211_VENDOR_SUBCMD_AOA_ABORT_MEAS = 135,
|
||||
QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS_RESULT = 136,
|
||||
QCA_NL80211_VENDOR_SUBCMD_DMG_RF_GET_SECTOR_CFG = 139,
|
||||
QCA_NL80211_VENDOR_SUBCMD_DMG_RF_SET_SECTOR_CFG = 140,
|
||||
QCA_NL80211_VENDOR_SUBCMD_DMG_RF_GET_SELECTED_SECTOR = 141,
|
||||
@ -136,6 +146,48 @@ static int wil_rf_sector_set_selected(struct wiphy *wiphy,
|
||||
|
||||
/* vendor specific commands */
|
||||
static const struct wiphy_vendor_command wil_nl80211_vendor_commands[] = {
|
||||
{
|
||||
.info.vendor_id = QCA_NL80211_VENDOR_ID,
|
||||
.info.subcmd = QCA_NL80211_VENDOR_SUBCMD_LOC_GET_CAPA,
|
||||
.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
|
||||
WIPHY_VENDOR_CMD_NEED_RUNNING,
|
||||
.doit = wil_ftm_get_capabilities
|
||||
},
|
||||
{
|
||||
.info.vendor_id = QCA_NL80211_VENDOR_ID,
|
||||
.info.subcmd = QCA_NL80211_VENDOR_SUBCMD_FTM_START_SESSION,
|
||||
.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
|
||||
WIPHY_VENDOR_CMD_NEED_RUNNING,
|
||||
.doit = wil_ftm_start_session
|
||||
},
|
||||
{
|
||||
.info.vendor_id = QCA_NL80211_VENDOR_ID,
|
||||
.info.subcmd = QCA_NL80211_VENDOR_SUBCMD_FTM_ABORT_SESSION,
|
||||
.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
|
||||
WIPHY_VENDOR_CMD_NEED_RUNNING,
|
||||
.doit = wil_ftm_abort_session
|
||||
},
|
||||
{
|
||||
.info.vendor_id = QCA_NL80211_VENDOR_ID,
|
||||
.info.subcmd = QCA_NL80211_VENDOR_SUBCMD_FTM_CFG_RESPONDER,
|
||||
.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
|
||||
WIPHY_VENDOR_CMD_NEED_RUNNING,
|
||||
.doit = wil_ftm_configure_responder
|
||||
},
|
||||
{
|
||||
.info.vendor_id = QCA_NL80211_VENDOR_ID,
|
||||
.info.subcmd = QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS,
|
||||
.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
|
||||
WIPHY_VENDOR_CMD_NEED_RUNNING,
|
||||
.doit = wil_aoa_start_measurement
|
||||
},
|
||||
{
|
||||
.info.vendor_id = QCA_NL80211_VENDOR_ID,
|
||||
.info.subcmd = QCA_NL80211_VENDOR_SUBCMD_AOA_ABORT_MEAS,
|
||||
.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
|
||||
WIPHY_VENDOR_CMD_NEED_RUNNING,
|
||||
.doit = wil_aoa_abort_measurement
|
||||
},
|
||||
{
|
||||
.info.vendor_id = QCA_NL80211_VENDOR_ID,
|
||||
.info.subcmd = QCA_NL80211_VENDOR_SUBCMD_DMG_RF_GET_SECTOR_CFG,
|
||||
@ -168,6 +220,22 @@ static const struct wiphy_vendor_command wil_nl80211_vendor_commands[] = {
|
||||
},
|
||||
};
|
||||
|
||||
/* vendor specific events */
|
||||
static const struct nl80211_vendor_cmd_info wil_nl80211_vendor_events[] = {
|
||||
[QCA_NL80211_VENDOR_EVENT_FTM_MEAS_RESULT_INDEX] = {
|
||||
.vendor_id = QCA_NL80211_VENDOR_ID,
|
||||
.subcmd = QCA_NL80211_VENDOR_SUBCMD_FTM_MEAS_RESULT
|
||||
},
|
||||
[QCA_NL80211_VENDOR_EVENT_FTM_SESSION_DONE_INDEX] = {
|
||||
.vendor_id = QCA_NL80211_VENDOR_ID,
|
||||
.subcmd = QCA_NL80211_VENDOR_SUBCMD_FTM_SESSION_DONE
|
||||
},
|
||||
[QCA_NL80211_VENDOR_EVENT_AOA_MEAS_RESULT_INDEX] = {
|
||||
.vendor_id = QCA_NL80211_VENDOR_ID,
|
||||
.subcmd = QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS_RESULT
|
||||
},
|
||||
};
|
||||
|
||||
static struct ieee80211_supported_band wil_band_60ghz = {
|
||||
.channels = wil_60ghz_channels,
|
||||
.n_channels = ARRAY_SIZE(wil_60ghz_channels),
|
||||
@ -1815,6 +1883,8 @@ static void wil_wiphy_init(struct wiphy *wiphy)
|
||||
|
||||
wiphy->n_vendor_commands = ARRAY_SIZE(wil_nl80211_vendor_commands);
|
||||
wiphy->vendor_commands = wil_nl80211_vendor_commands;
|
||||
wiphy->vendor_events = wil_nl80211_vendor_events;
|
||||
wiphy->n_vendor_events = ARRAY_SIZE(wil_nl80211_vendor_events);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
wiphy->wowlan = &wil_wowlan_support;
|
||||
|
929
drivers/net/wireless/ath/wil6210/ftm.c
Normal file
929
drivers/net/wireless/ath/wil6210/ftm.c
Normal file
@ -0,0 +1,929 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/etherdevice.h>
|
||||
#include <net/netlink.h>
|
||||
#include "wil6210.h"
|
||||
#include "ftm.h"
|
||||
#include "wmi.h"
|
||||
|
||||
/* FTM session ID we use with FW */
|
||||
#define WIL_FTM_FW_SESSION_ID 1
|
||||
|
||||
/* fixed spare allocation we reserve in NL messages we allocate */
|
||||
#define WIL_FTM_NL_EXTRA_ALLOC 32
|
||||
|
||||
/* approx maximum length for FTM_MEAS_RESULT NL80211 event */
|
||||
#define WIL_FTM_MEAS_RESULT_MAX_LENGTH 2048
|
||||
|
||||
/* timeout for waiting for standalone AOA measurement, milliseconds */
|
||||
#define WIL_AOA_MEASUREMENT_TIMEOUT 1000
|
||||
|
||||
/* maximum number of allowed FTM measurements per burst */
|
||||
#define WIL_FTM_MAX_MEAS_PER_BURST 31
|
||||
|
||||
/* initial token to use on non-secure FTM measurement */
|
||||
#define WIL_TOF_FTM_DEFAULT_INITIAL_TOKEN 2
|
||||
|
||||
#define WIL_TOF_FTM_MAX_LCI_LENGTH (240)
|
||||
#define WIL_TOF_FTM_MAX_LCR_LENGTH (240)
|
||||
|
||||
static const struct
|
||||
nla_policy wil_nl80211_loc_policy[QCA_WLAN_VENDOR_ATTR_LOC_MAX + 1] = {
|
||||
[QCA_WLAN_VENDOR_ATTR_FTM_SESSION_COOKIE] = { .type = NLA_U64 },
|
||||
[QCA_WLAN_VENDOR_ATTR_LOC_CAPA] = { .type = NLA_NESTED },
|
||||
[QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PEERS] = { .type = NLA_NESTED },
|
||||
[QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PEER_RESULTS] = { .type = NLA_NESTED },
|
||||
[QCA_WLAN_VENDOR_ATTR_FTM_RESPONDER_ENABLE] = { .type = NLA_FLAG },
|
||||
[QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS] = { .type = NLA_U32 },
|
||||
[QCA_WLAN_VENDOR_ATTR_FTM_INITIAL_TOKEN] = { .type = NLA_U8 },
|
||||
[QCA_WLAN_VENDOR_ATTR_AOA_TYPE] = { .type = NLA_U32 },
|
||||
[QCA_WLAN_VENDOR_ATTR_LOC_ANTENNA_ARRAY_MASK] = { .type = NLA_U32 },
|
||||
[QCA_WLAN_VENDOR_ATTR_FREQ] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
static const struct
|
||||
nla_policy wil_nl80211_ftm_peer_policy[
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PEER_MAX + 1] = {
|
||||
[QCA_WLAN_VENDOR_ATTR_FTM_PEER_MAC_ADDR] = { .len = ETH_ALEN },
|
||||
[QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAGS] = { .type = NLA_U32 },
|
||||
[QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_PARAMS] = { .type = NLA_NESTED },
|
||||
[QCA_WLAN_VENDOR_ATTR_FTM_PEER_SECURE_TOKEN_ID] = { .type = NLA_U8 },
|
||||
[QCA_WLAN_VENDOR_ATTR_FTM_PEER_FREQ] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
static const struct
|
||||
nla_policy wil_nl80211_ftm_meas_param_policy[
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PARAM_MAX + 1] = {
|
||||
[QCA_WLAN_VENDOR_ATTR_FTM_PARAM_MEAS_PER_BURST] = { .type = NLA_U8 },
|
||||
[QCA_WLAN_VENDOR_ATTR_FTM_PARAM_NUM_BURSTS_EXP] = { .type = NLA_U8 },
|
||||
[QCA_WLAN_VENDOR_ATTR_FTM_PARAM_BURST_DURATION] = { .type = NLA_U8 },
|
||||
[QCA_WLAN_VENDOR_ATTR_FTM_PARAM_BURST_PERIOD] = { .type = NLA_U16 },
|
||||
};
|
||||
|
||||
static u8 wil_ftm_get_channel(struct wil6210_priv *wil,
|
||||
const u8 *mac_addr, u32 freq)
|
||||
{
|
||||
struct wiphy *wiphy = wil_to_wiphy(wil);
|
||||
struct cfg80211_bss *bss;
|
||||
struct ieee80211_channel *chan;
|
||||
u8 channel;
|
||||
|
||||
if (freq) {
|
||||
chan = ieee80211_get_channel(wiphy, freq);
|
||||
if (!chan) {
|
||||
wil_err(wil, "invalid freq: %d\n", freq);
|
||||
return 0;
|
||||
}
|
||||
channel = chan->hw_value;
|
||||
} else {
|
||||
bss = cfg80211_get_bss(wiphy, NULL, mac_addr,
|
||||
NULL, 0, IEEE80211_BSS_TYPE_ANY,
|
||||
IEEE80211_PRIVACY_ANY);
|
||||
if (!bss) {
|
||||
wil_err(wil, "Unable to find BSS\n");
|
||||
return 0;
|
||||
}
|
||||
channel = bss->channel->hw_value;
|
||||
cfg80211_put_bss(wiphy, bss);
|
||||
}
|
||||
|
||||
wil_dbg_misc(wil, "target %pM at channel %d\n", mac_addr, channel);
|
||||
return channel;
|
||||
}
|
||||
|
||||
static int wil_ftm_parse_meas_params(struct wil6210_priv *wil,
|
||||
struct nlattr *attr,
|
||||
struct wil_ftm_meas_params *params)
|
||||
{
|
||||
struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_FTM_PARAM_MAX + 1];
|
||||
int rc;
|
||||
|
||||
if (!attr) {
|
||||
/* temporary defaults for one-shot measurement */
|
||||
params->meas_per_burst = 1;
|
||||
params->burst_period = 5; /* 500 milliseconds */
|
||||
return 0;
|
||||
}
|
||||
rc = nla_parse_nested(tb, QCA_WLAN_VENDOR_ATTR_FTM_PARAM_MAX,
|
||||
attr, wil_nl80211_ftm_meas_param_policy, NULL);
|
||||
if (rc) {
|
||||
wil_err(wil, "invalid measurement params\n");
|
||||
return rc;
|
||||
}
|
||||
if (tb[QCA_WLAN_VENDOR_ATTR_FTM_PARAM_MEAS_PER_BURST])
|
||||
params->meas_per_burst = nla_get_u8(
|
||||
tb[QCA_WLAN_VENDOR_ATTR_FTM_PARAM_MEAS_PER_BURST]);
|
||||
if (tb[QCA_WLAN_VENDOR_ATTR_FTM_PARAM_NUM_BURSTS_EXP])
|
||||
params->num_of_bursts_exp = nla_get_u8(
|
||||
tb[QCA_WLAN_VENDOR_ATTR_FTM_PARAM_NUM_BURSTS_EXP]);
|
||||
if (tb[QCA_WLAN_VENDOR_ATTR_FTM_PARAM_BURST_DURATION])
|
||||
params->burst_duration = nla_get_u8(
|
||||
tb[QCA_WLAN_VENDOR_ATTR_FTM_PARAM_BURST_DURATION]);
|
||||
if (tb[QCA_WLAN_VENDOR_ATTR_FTM_PARAM_BURST_PERIOD])
|
||||
params->burst_period = nla_get_u16(
|
||||
tb[QCA_WLAN_VENDOR_ATTR_FTM_PARAM_BURST_PERIOD]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wil_ftm_validate_meas_params(struct wil6210_priv *wil,
|
||||
struct wil_ftm_meas_params *params)
|
||||
{
|
||||
/* temporary allow only single-burst */
|
||||
if (params->meas_per_burst > WIL_FTM_MAX_MEAS_PER_BURST ||
|
||||
params->num_of_bursts_exp != 0) {
|
||||
wil_err(wil, "invalid measurement params\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wil_ftm_append_meas_params(struct wil6210_priv *wil,
|
||||
struct sk_buff *msg,
|
||||
struct wil_ftm_meas_params *params)
|
||||
{
|
||||
struct nlattr *nl_p;
|
||||
|
||||
nl_p = nla_nest_start(
|
||||
msg, QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MEAS_PARAMS);
|
||||
if (!nl_p)
|
||||
goto out_put_failure;
|
||||
if (nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_FTM_PARAM_MEAS_PER_BURST,
|
||||
params->meas_per_burst) ||
|
||||
nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_FTM_PARAM_NUM_BURSTS_EXP,
|
||||
params->num_of_bursts_exp) ||
|
||||
nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_FTM_PARAM_BURST_DURATION,
|
||||
params->burst_duration) ||
|
||||
nla_put_u16(msg, QCA_WLAN_VENDOR_ATTR_FTM_PARAM_BURST_PERIOD,
|
||||
params->burst_period))
|
||||
goto out_put_failure;
|
||||
nla_nest_end(msg, nl_p);
|
||||
return 0;
|
||||
out_put_failure:
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
static int wil_ftm_append_peer_meas_res(struct wil6210_priv *wil,
|
||||
struct sk_buff *msg,
|
||||
struct wil_ftm_peer_meas_res *res)
|
||||
{
|
||||
struct nlattr *nl_mres, *nl_f;
|
||||
int i;
|
||||
|
||||
if (nla_put(msg, QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MAC_ADDR,
|
||||
ETH_ALEN, res->mac_addr) ||
|
||||
nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_FLAGS,
|
||||
res->flags) ||
|
||||
nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS,
|
||||
res->status))
|
||||
goto out_put_failure;
|
||||
if (res->status == QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_FAILED &&
|
||||
nla_put_u8(msg,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_VALUE_SECONDS,
|
||||
res->value_seconds))
|
||||
goto out_put_failure;
|
||||
if (res->has_params &&
|
||||
wil_ftm_append_meas_params(wil, msg, &res->params))
|
||||
goto out_put_failure;
|
||||
nl_mres = nla_nest_start(msg, QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MEAS);
|
||||
if (!nl_mres)
|
||||
goto out_put_failure;
|
||||
for (i = 0; i < res->n_meas; i++) {
|
||||
nl_f = nla_nest_start(msg, i);
|
||||
if (!nl_f)
|
||||
goto out_put_failure;
|
||||
if (nla_put_u64_64bit(msg, QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T1,
|
||||
res->meas[i].t1,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PAD) ||
|
||||
nla_put_u64_64bit(msg, QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T2,
|
||||
res->meas[i].t2,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PAD) ||
|
||||
nla_put_u64_64bit(msg, QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T3,
|
||||
res->meas[i].t3,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PAD) ||
|
||||
nla_put_u64_64bit(msg, QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T4,
|
||||
res->meas[i].t4,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PAD))
|
||||
goto out_put_failure;
|
||||
nla_nest_end(msg, nl_f);
|
||||
}
|
||||
nla_nest_end(msg, nl_mres);
|
||||
return 0;
|
||||
out_put_failure:
|
||||
wil_err(wil, "fail to append peer result\n");
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
static void wil_ftm_send_meas_result(struct wil6210_priv *wil,
|
||||
struct wil_ftm_peer_meas_res *res)
|
||||
{
|
||||
struct sk_buff *vendor_event = NULL;
|
||||
struct nlattr *nl_res;
|
||||
int rc = 0;
|
||||
|
||||
wil_dbg_misc(wil, "sending %d results for peer %pM\n",
|
||||
res->n_meas, res->mac_addr);
|
||||
|
||||
vendor_event = cfg80211_vendor_event_alloc(
|
||||
wil_to_wiphy(wil),
|
||||
wil->wdev,
|
||||
WIL_FTM_MEAS_RESULT_MAX_LENGTH,
|
||||
QCA_NL80211_VENDOR_EVENT_FTM_MEAS_RESULT_INDEX,
|
||||
GFP_KERNEL);
|
||||
if (!vendor_event) {
|
||||
wil_err(wil, "fail to allocate measurement result\n");
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (nla_put_u64_64bit(
|
||||
vendor_event, QCA_WLAN_VENDOR_ATTR_FTM_SESSION_COOKIE,
|
||||
wil->ftm.session_cookie, QCA_WLAN_VENDOR_ATTR_PAD)) {
|
||||
rc = -ENOBUFS;
|
||||
goto out;
|
||||
}
|
||||
|
||||
nl_res = nla_nest_start(vendor_event,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PEER_RESULTS);
|
||||
if (!nl_res) {
|
||||
rc = -ENOBUFS;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = wil_ftm_append_peer_meas_res(wil, vendor_event, res);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
nla_nest_end(vendor_event, nl_res);
|
||||
cfg80211_vendor_event(vendor_event, GFP_KERNEL);
|
||||
vendor_event = NULL;
|
||||
out:
|
||||
if (vendor_event)
|
||||
kfree_skb(vendor_event);
|
||||
if (rc)
|
||||
wil_err(wil, "send peer result failed, err %d\n", rc);
|
||||
}
|
||||
|
||||
static void wil_ftm_send_peer_res(struct wil6210_priv *wil)
|
||||
{
|
||||
if (!wil->ftm.has_ftm_res || !wil->ftm.ftm_res)
|
||||
return;
|
||||
|
||||
wil_ftm_send_meas_result(wil, wil->ftm.ftm_res);
|
||||
wil->ftm.has_ftm_res = 0;
|
||||
wil->ftm.ftm_res->n_meas = 0;
|
||||
}
|
||||
|
||||
static void wil_aoa_measurement_timeout(struct work_struct *work)
|
||||
{
|
||||
struct wil_ftm_priv *ftm = container_of(work, struct wil_ftm_priv,
|
||||
aoa_timeout_work);
|
||||
struct wil6210_priv *wil = container_of(ftm, struct wil6210_priv, ftm);
|
||||
struct wil_aoa_meas_result res;
|
||||
|
||||
wil_dbg_misc(wil, "AOA measurement timeout\n");
|
||||
|
||||
memset(&res, 0, sizeof(res));
|
||||
ether_addr_copy(res.mac_addr, wil->ftm.aoa_peer_mac_addr);
|
||||
res.type = wil->ftm.aoa_type;
|
||||
res.status = QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_ABORTED;
|
||||
wil_aoa_cfg80211_meas_result(wil, &res);
|
||||
}
|
||||
|
||||
static int
|
||||
wil_ftm_cfg80211_start_session(struct wil6210_priv *wil,
|
||||
struct wil_ftm_session_request *request)
|
||||
{
|
||||
int rc = 0;
|
||||
bool has_lci = false, has_lcr = false;
|
||||
u8 max_meas = 0, channel, *ptr;
|
||||
u32 i, cmd_len;
|
||||
struct wmi_tof_session_start_cmd *cmd;
|
||||
|
||||
mutex_lock(&wil->ftm.lock);
|
||||
if (wil->ftm.session_started) {
|
||||
wil_err(wil, "FTM session already running\n");
|
||||
rc = -EAGAIN;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < request->n_peers; i++) {
|
||||
if (request->peers[i].flags &
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_LCI)
|
||||
has_lci = true;
|
||||
if (request->peers[i].flags &
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_LCR)
|
||||
has_lcr = true;
|
||||
max_meas = max(max_meas,
|
||||
request->peers[i].params.meas_per_burst);
|
||||
}
|
||||
|
||||
wil->ftm.ftm_res = kzalloc(sizeof(*wil->ftm.ftm_res) +
|
||||
max_meas * sizeof(struct wil_ftm_peer_meas) +
|
||||
(has_lci ? WIL_TOF_FTM_MAX_LCI_LENGTH : 0) +
|
||||
(has_lcr ? WIL_TOF_FTM_MAX_LCR_LENGTH : 0), GFP_KERNEL);
|
||||
if (!wil->ftm.ftm_res) {
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
ptr = (u8 *)wil->ftm.ftm_res;
|
||||
ptr += sizeof(struct wil_ftm_peer_meas_res) +
|
||||
max_meas * sizeof(struct wil_ftm_peer_meas);
|
||||
if (has_lci) {
|
||||
wil->ftm.ftm_res->lci = ptr;
|
||||
ptr += WIL_TOF_FTM_MAX_LCI_LENGTH;
|
||||
}
|
||||
if (has_lcr)
|
||||
wil->ftm.ftm_res->lcr = ptr;
|
||||
wil->ftm.max_ftm_meas = max_meas;
|
||||
|
||||
cmd_len = sizeof(struct wmi_tof_session_start_cmd) +
|
||||
request->n_peers * sizeof(struct wmi_ftm_dest_info);
|
||||
cmd = kzalloc(cmd_len, GFP_KERNEL);
|
||||
if (!cmd) {
|
||||
rc = -ENOMEM;
|
||||
goto out_ftm_res;
|
||||
}
|
||||
|
||||
cmd->session_id = cpu_to_le32(WIL_FTM_FW_SESSION_ID);
|
||||
cmd->num_of_dest = cpu_to_le16(request->n_peers);
|
||||
for (i = 0; i < request->n_peers; i++) {
|
||||
ether_addr_copy(cmd->ftm_dest_info[i].dst_mac,
|
||||
request->peers[i].mac_addr);
|
||||
channel = wil_ftm_get_channel(wil, request->peers[i].mac_addr,
|
||||
request->peers[i].freq);
|
||||
if (!channel) {
|
||||
wil_err(wil, "can't find FTM target at index %d\n", i);
|
||||
rc = -EINVAL;
|
||||
goto out_cmd;
|
||||
}
|
||||
cmd->ftm_dest_info[i].channel = channel - 1;
|
||||
if (request->peers[i].flags &
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_SECURE) {
|
||||
cmd->ftm_dest_info[i].flags |=
|
||||
WMI_TOF_SESSION_START_FLAG_SECURED;
|
||||
cmd->ftm_dest_info[i].initial_token =
|
||||
request->peers[i].secure_token_id;
|
||||
} else {
|
||||
cmd->ftm_dest_info[i].initial_token =
|
||||
WIL_TOF_FTM_DEFAULT_INITIAL_TOKEN;
|
||||
}
|
||||
if (request->peers[i].flags &
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_ASAP)
|
||||
cmd->ftm_dest_info[i].flags |=
|
||||
WMI_TOF_SESSION_START_FLAG_ASAP;
|
||||
if (request->peers[i].flags &
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_LCI)
|
||||
cmd->ftm_dest_info[i].flags |=
|
||||
WMI_TOF_SESSION_START_FLAG_LCI_REQ;
|
||||
if (request->peers[i].flags &
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_LCR)
|
||||
cmd->ftm_dest_info[i].flags |=
|
||||
WMI_TOF_SESSION_START_FLAG_LCR_REQ;
|
||||
cmd->ftm_dest_info[i].num_of_ftm_per_burst =
|
||||
request->peers[i].params.meas_per_burst;
|
||||
cmd->ftm_dest_info[i].num_of_bursts_exp =
|
||||
request->peers[i].params.num_of_bursts_exp;
|
||||
cmd->ftm_dest_info[i].burst_duration =
|
||||
request->peers[i].params.burst_duration;
|
||||
cmd->ftm_dest_info[i].burst_period =
|
||||
cpu_to_le16(request->peers[i].params.burst_period);
|
||||
}
|
||||
|
||||
rc = wmi_send(wil, WMI_TOF_SESSION_START_CMDID, cmd, cmd_len);
|
||||
|
||||
if (!rc) {
|
||||
wil->ftm.session_cookie = request->session_cookie;
|
||||
wil->ftm.session_started = 1;
|
||||
}
|
||||
out_cmd:
|
||||
kfree(cmd);
|
||||
out_ftm_res:
|
||||
if (rc) {
|
||||
kfree(wil->ftm.ftm_res);
|
||||
wil->ftm.ftm_res = NULL;
|
||||
}
|
||||
out:
|
||||
mutex_unlock(&wil->ftm.lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void
|
||||
wil_ftm_cfg80211_session_ended(struct wil6210_priv *wil, u32 status)
|
||||
{
|
||||
struct sk_buff *vendor_event = NULL;
|
||||
|
||||
mutex_lock(&wil->ftm.lock);
|
||||
|
||||
if (!wil->ftm.session_started) {
|
||||
wil_dbg_misc(wil, "FTM session not started, ignoring event\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* finish the session */
|
||||
wil_dbg_misc(wil, "finishing FTM session\n");
|
||||
|
||||
/* send left-over results if any */
|
||||
wil_ftm_send_peer_res(wil);
|
||||
|
||||
wil->ftm.session_started = 0;
|
||||
kfree(wil->ftm.ftm_res);
|
||||
wil->ftm.ftm_res = NULL;
|
||||
|
||||
vendor_event = cfg80211_vendor_event_alloc(
|
||||
wil_to_wiphy(wil),
|
||||
wil->wdev,
|
||||
WIL_FTM_NL_EXTRA_ALLOC,
|
||||
QCA_NL80211_VENDOR_EVENT_FTM_SESSION_DONE_INDEX,
|
||||
GFP_KERNEL);
|
||||
if (!vendor_event)
|
||||
goto out;
|
||||
|
||||
if (nla_put_u64_64bit(vendor_event,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_SESSION_COOKIE,
|
||||
wil->ftm.session_cookie,
|
||||
QCA_WLAN_VENDOR_ATTR_PAD) ||
|
||||
nla_put_u32(vendor_event,
|
||||
QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS, status)) {
|
||||
wil_err(wil, "failed to fill session done event\n");
|
||||
goto out;
|
||||
}
|
||||
cfg80211_vendor_event(vendor_event, GFP_KERNEL);
|
||||
vendor_event = NULL;
|
||||
out:
|
||||
kfree_skb(vendor_event);
|
||||
mutex_unlock(&wil->ftm.lock);
|
||||
}
|
||||
|
||||
static void wil_aoa_timer_fn(ulong x)
|
||||
{
|
||||
struct wil6210_priv *wil = (void *)x;
|
||||
|
||||
wil_dbg_misc(wil, "AOA timer\n");
|
||||
schedule_work(&wil->ftm.aoa_timeout_work);
|
||||
}
|
||||
|
||||
static int
|
||||
wil_aoa_cfg80211_start_measurement(struct wil6210_priv *wil,
|
||||
struct wil_aoa_meas_request *request)
|
||||
{
|
||||
int rc = 0;
|
||||
struct wmi_aoa_meas_cmd cmd;
|
||||
u8 channel;
|
||||
|
||||
mutex_lock(&wil->ftm.lock);
|
||||
|
||||
if (wil->ftm.aoa_started) {
|
||||
wil_err(wil, "AOA measurement already running\n");
|
||||
rc = -EAGAIN;
|
||||
goto out;
|
||||
}
|
||||
if (request->type >= QCA_WLAN_VENDOR_ATTR_AOA_TYPE_MAX) {
|
||||
wil_err(wil, "invalid AOA type: %d\n", request->type);
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
channel = wil_ftm_get_channel(wil, request->mac_addr, request->freq);
|
||||
if (!channel) {
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
ether_addr_copy(cmd.mac_addr, request->mac_addr);
|
||||
cmd.channel = channel - 1;
|
||||
cmd.aoa_meas_type = request->type;
|
||||
|
||||
rc = wmi_send(wil, WMI_AOA_MEAS_CMDID, &cmd, sizeof(cmd));
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
ether_addr_copy(wil->ftm.aoa_peer_mac_addr, request->mac_addr);
|
||||
mod_timer(&wil->ftm.aoa_timer,
|
||||
jiffies + msecs_to_jiffies(WIL_AOA_MEASUREMENT_TIMEOUT));
|
||||
wil->ftm.aoa_started = 1;
|
||||
out:
|
||||
mutex_unlock(&wil->ftm.lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
void wil_aoa_cfg80211_meas_result(struct wil6210_priv *wil,
|
||||
struct wil_aoa_meas_result *result)
|
||||
{
|
||||
struct sk_buff *vendor_event = NULL;
|
||||
|
||||
mutex_lock(&wil->ftm.lock);
|
||||
|
||||
if (!wil->ftm.aoa_started) {
|
||||
wil_info(wil, "AOA not started, not sending result\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
wil_dbg_misc(wil, "sending AOA measurement result\n");
|
||||
|
||||
vendor_event = cfg80211_vendor_event_alloc(
|
||||
wil_to_wiphy(wil),
|
||||
wil->wdev,
|
||||
result->length + WIL_FTM_NL_EXTRA_ALLOC,
|
||||
QCA_NL80211_VENDOR_EVENT_AOA_MEAS_RESULT_INDEX,
|
||||
GFP_KERNEL);
|
||||
if (!vendor_event) {
|
||||
wil_err(wil, "fail to allocate measurement result\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_MAC_ADDR,
|
||||
ETH_ALEN, result->mac_addr) ||
|
||||
nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_AOA_TYPE,
|
||||
result->type) ||
|
||||
nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS,
|
||||
result->status) ||
|
||||
nla_put_u32(vendor_event,
|
||||
QCA_WLAN_VENDOR_ATTR_LOC_ANTENNA_ARRAY_MASK,
|
||||
result->antenna_array_mask)) {
|
||||
wil_err(wil, "failed to fill vendor event\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (result->length > 0 &&
|
||||
nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_AOA_MEAS_RESULT,
|
||||
result->length, result->data)) {
|
||||
wil_err(wil, "failed to fill vendor event with AOA data\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
cfg80211_vendor_event(vendor_event, GFP_KERNEL);
|
||||
|
||||
del_timer_sync(&wil->ftm.aoa_timer);
|
||||
wil->ftm.aoa_started = 0;
|
||||
out:
|
||||
mutex_unlock(&wil->ftm.lock);
|
||||
}
|
||||
|
||||
void wil_ftm_evt_session_ended(struct wil6210_priv *wil,
|
||||
struct wmi_tof_session_end_event *evt)
|
||||
{
|
||||
u32 status;
|
||||
|
||||
switch (evt->status) {
|
||||
case WMI_TOF_SESSION_END_NO_ERROR:
|
||||
status = QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_OK;
|
||||
break;
|
||||
case WMI_TOF_SESSION_END_PARAMS_ERROR:
|
||||
status = QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_INVALID;
|
||||
break;
|
||||
case WMI_TOF_SESSION_END_FAIL:
|
||||
status = QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_FAILED;
|
||||
break;
|
||||
case WMI_TOF_SESSION_END_ABORTED:
|
||||
status = QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_ABORTED;
|
||||
break;
|
||||
default:
|
||||
status = QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_FAILED;
|
||||
break;
|
||||
}
|
||||
|
||||
wil_ftm_cfg80211_session_ended(wil, status);
|
||||
}
|
||||
|
||||
void wil_ftm_evt_per_dest_res(struct wil6210_priv *wil,
|
||||
struct wmi_tof_ftm_per_dest_res_event *evt)
|
||||
{
|
||||
u32 i, index;
|
||||
__le64 tmp = 0;
|
||||
u8 n_meas;
|
||||
|
||||
mutex_lock(&wil->ftm.lock);
|
||||
|
||||
if (!wil->ftm.session_started || !wil->ftm.ftm_res) {
|
||||
wil_dbg_misc(wil, "Session not running, ignoring res event\n");
|
||||
goto out;
|
||||
}
|
||||
if (wil->ftm.has_ftm_res &&
|
||||
!ether_addr_equal(evt->dst_mac, wil->ftm.ftm_res->mac_addr)) {
|
||||
wil_dbg_misc(wil,
|
||||
"Results for previous peer not properly terminated\n");
|
||||
wil_ftm_send_peer_res(wil);
|
||||
}
|
||||
|
||||
if (!wil->ftm.has_ftm_res) {
|
||||
ether_addr_copy(wil->ftm.ftm_res->mac_addr, evt->dst_mac);
|
||||
wil->ftm.has_ftm_res = 1;
|
||||
}
|
||||
|
||||
n_meas = evt->actual_ftm_per_burst;
|
||||
switch (evt->status) {
|
||||
case WMI_PER_DEST_RES_NO_ERROR:
|
||||
wil->ftm.ftm_res->status =
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_OK;
|
||||
break;
|
||||
case WMI_PER_DEST_RES_TX_RX_FAIL:
|
||||
/* FW reports corrupted results here, discard. */
|
||||
n_meas = 0;
|
||||
wil->ftm.ftm_res->status =
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_OK;
|
||||
break;
|
||||
case WMI_PER_DEST_RES_PARAM_DONT_MATCH:
|
||||
wil->ftm.ftm_res->status =
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_INVALID;
|
||||
break;
|
||||
default:
|
||||
wil_err(wil, "unexpected status %d\n", evt->status);
|
||||
wil->ftm.ftm_res->status =
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_INVALID;
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < n_meas; i++) {
|
||||
index = wil->ftm.ftm_res->n_meas;
|
||||
if (index >= wil->ftm.max_ftm_meas) {
|
||||
wil_dbg_misc(wil, "Too many measurements, some lost\n");
|
||||
break;
|
||||
}
|
||||
memcpy(&tmp, evt->responder_ftm_res[i].t1,
|
||||
sizeof(evt->responder_ftm_res[i].t1));
|
||||
wil->ftm.ftm_res->meas[index].t1 = le64_to_cpu(tmp);
|
||||
memcpy(&tmp, evt->responder_ftm_res[i].t2,
|
||||
sizeof(evt->responder_ftm_res[i].t2));
|
||||
wil->ftm.ftm_res->meas[index].t2 = le64_to_cpu(tmp);
|
||||
memcpy(&tmp, evt->responder_ftm_res[i].t3,
|
||||
sizeof(evt->responder_ftm_res[i].t3));
|
||||
wil->ftm.ftm_res->meas[index].t3 = le64_to_cpu(tmp);
|
||||
memcpy(&tmp, evt->responder_ftm_res[i].t4,
|
||||
sizeof(evt->responder_ftm_res[i].t4));
|
||||
wil->ftm.ftm_res->meas[index].t4 = le64_to_cpu(tmp);
|
||||
wil->ftm.ftm_res->n_meas++;
|
||||
}
|
||||
|
||||
if (evt->flags & WMI_PER_DEST_RES_BURST_REPORT_END)
|
||||
wil_ftm_send_peer_res(wil);
|
||||
out:
|
||||
mutex_unlock(&wil->ftm.lock);
|
||||
}
|
||||
|
||||
void wil_aoa_evt_meas(struct wil6210_priv *wil,
|
||||
struct wmi_aoa_meas_event *evt,
|
||||
int len)
|
||||
{
|
||||
int data_len = len - offsetof(struct wmi_aoa_meas_event, meas_data);
|
||||
struct wil_aoa_meas_result *res;
|
||||
|
||||
data_len = min_t(int, le16_to_cpu(evt->length), data_len);
|
||||
|
||||
res = kmalloc(sizeof(*res) + data_len, GFP_KERNEL);
|
||||
if (!res)
|
||||
return;
|
||||
|
||||
ether_addr_copy(res->mac_addr, evt->mac_addr);
|
||||
res->type = evt->aoa_meas_type;
|
||||
res->antenna_array_mask = le32_to_cpu(evt->meas_rf_mask);
|
||||
res->status = evt->meas_status;
|
||||
res->length = data_len;
|
||||
memcpy(res->data, evt->meas_data, data_len);
|
||||
|
||||
wil_dbg_misc(wil, "AOA result status %d type %d mask %d length %d\n",
|
||||
res->status, res->type,
|
||||
res->antenna_array_mask, res->length);
|
||||
|
||||
wil_aoa_cfg80211_meas_result(wil, res);
|
||||
kfree(res);
|
||||
}
|
||||
|
||||
int wil_ftm_get_capabilities(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
const void *data, int data_len)
|
||||
{
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
struct sk_buff *skb;
|
||||
struct nlattr *attr;
|
||||
|
||||
if (!test_bit(WMI_FW_CAPABILITY_FTM, wil->fw_capabilities))
|
||||
return -ENOTSUPP;
|
||||
|
||||
/* we should get the capabilities from the FW. for now,
|
||||
* report dummy capabilities for one shot measurement
|
||||
*/
|
||||
skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, 128);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
attr = nla_nest_start(skb, QCA_WLAN_VENDOR_ATTR_LOC_CAPA);
|
||||
if (!attr ||
|
||||
nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAGS,
|
||||
QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_FTM_RESPONDER |
|
||||
QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_FTM_INITIATOR |
|
||||
QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_ASAP |
|
||||
QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_AOA) ||
|
||||
nla_put_u16(skb, QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_NUM_SESSIONS,
|
||||
1) ||
|
||||
nla_put_u16(skb, QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_NUM_PEERS, 1) ||
|
||||
nla_put_u8(skb, QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_NUM_BURSTS_EXP,
|
||||
0) ||
|
||||
nla_put_u8(skb, QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_MEAS_PER_BURST,
|
||||
4) ||
|
||||
nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_AOA_CAPA_SUPPORTED_TYPES,
|
||||
BIT(QCA_WLAN_VENDOR_ATTR_AOA_TYPE_TOP_CIR_PHASE))) {
|
||||
wil_err(wil, "fail to fill get_capabilities reply\n");
|
||||
kfree_skb(skb);
|
||||
return -ENOMEM;
|
||||
}
|
||||
nla_nest_end(skb, attr);
|
||||
|
||||
return cfg80211_vendor_cmd_reply(skb);
|
||||
}
|
||||
|
||||
int wil_ftm_start_session(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
const void *data, int data_len)
|
||||
{
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
struct wil_ftm_session_request *request;
|
||||
struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_LOC_MAX + 1];
|
||||
struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_FTM_PEER_MAX + 1];
|
||||
struct nlattr *peer;
|
||||
int rc, n_peers = 0, index = 0, tmp;
|
||||
|
||||
if (!test_bit(WMI_FW_CAPABILITY_FTM, wil->fw_capabilities))
|
||||
return -ENOTSUPP;
|
||||
|
||||
rc = nla_parse(tb, QCA_WLAN_VENDOR_ATTR_LOC_MAX, data, data_len,
|
||||
wil_nl80211_loc_policy, NULL);
|
||||
if (rc) {
|
||||
wil_err(wil, "Invalid ATTR\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (!tb[QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PEERS]) {
|
||||
wil_err(wil, "no peers specified\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!tb[QCA_WLAN_VENDOR_ATTR_FTM_SESSION_COOKIE]) {
|
||||
wil_err(wil, "session cookie not specified\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
nla_for_each_nested(peer, tb[QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PEERS],
|
||||
tmp)
|
||||
n_peers++;
|
||||
|
||||
if (!n_peers) {
|
||||
wil_err(wil, "empty peer list\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* for now only allow measurement for a single peer */
|
||||
if (n_peers != 1) {
|
||||
wil_err(wil, "only single peer allowed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
request = kzalloc(sizeof(*request) +
|
||||
n_peers * sizeof(struct wil_ftm_meas_peer_info),
|
||||
GFP_KERNEL);
|
||||
if (!request)
|
||||
return -ENOMEM;
|
||||
|
||||
request->session_cookie =
|
||||
nla_get_u64(tb[QCA_WLAN_VENDOR_ATTR_FTM_SESSION_COOKIE]);
|
||||
request->n_peers = n_peers;
|
||||
nla_for_each_nested(peer, tb[QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PEERS],
|
||||
tmp) {
|
||||
rc = nla_parse_nested(tb2, QCA_WLAN_VENDOR_ATTR_FTM_PEER_MAX,
|
||||
peer, wil_nl80211_ftm_peer_policy, NULL);
|
||||
if (rc) {
|
||||
wil_err(wil, "Invalid peer ATTR\n");
|
||||
goto out;
|
||||
}
|
||||
if (!tb2[QCA_WLAN_VENDOR_ATTR_FTM_PEER_MAC_ADDR] ||
|
||||
nla_len(tb2[QCA_WLAN_VENDOR_ATTR_FTM_PEER_MAC_ADDR])
|
||||
!= ETH_ALEN) {
|
||||
wil_err(wil, "Peer MAC address missing or invalid\n");
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
memcpy(request->peers[index].mac_addr,
|
||||
nla_data(tb2[QCA_WLAN_VENDOR_ATTR_FTM_PEER_MAC_ADDR]),
|
||||
ETH_ALEN);
|
||||
if (tb2[QCA_WLAN_VENDOR_ATTR_FTM_PEER_FREQ])
|
||||
request->peers[index].freq = nla_get_u32(
|
||||
tb2[QCA_WLAN_VENDOR_ATTR_FTM_PEER_FREQ]);
|
||||
if (tb2[QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAGS])
|
||||
request->peers[index].flags = nla_get_u32(
|
||||
tb2[QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAGS]);
|
||||
if (tb2[QCA_WLAN_VENDOR_ATTR_FTM_PEER_SECURE_TOKEN_ID])
|
||||
request->peers[index].secure_token_id = nla_get_u8(
|
||||
tb2[QCA_WLAN_VENDOR_ATTR_FTM_PEER_SECURE_TOKEN_ID]);
|
||||
rc = wil_ftm_parse_meas_params(
|
||||
wil,
|
||||
tb2[QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_PARAMS],
|
||||
&request->peers[index].params);
|
||||
if (!rc)
|
||||
rc = wil_ftm_validate_meas_params(
|
||||
wil, &request->peers[index].params);
|
||||
if (rc)
|
||||
goto out;
|
||||
index++;
|
||||
}
|
||||
|
||||
rc = wil_ftm_cfg80211_start_session(wil, request);
|
||||
out:
|
||||
kfree(request);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int wil_ftm_abort_session(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
const void *data, int data_len)
|
||||
{
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
|
||||
wil_dbg_misc(wil, "stub\n");
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
int wil_ftm_configure_responder(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
const void *data, int data_len)
|
||||
{
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
|
||||
wil_dbg_misc(wil, "stub\n");
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
int wil_aoa_start_measurement(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
const void *data, int data_len)
|
||||
{
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
struct wil_aoa_meas_request request;
|
||||
struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_LOC_MAX + 1];
|
||||
int rc;
|
||||
|
||||
if (!test_bit(WMI_FW_CAPABILITY_FTM, wil->fw_capabilities))
|
||||
return -ENOTSUPP;
|
||||
|
||||
wil_dbg_misc(wil, "AOA start measurement\n");
|
||||
|
||||
rc = nla_parse(tb, QCA_WLAN_VENDOR_ATTR_LOC_MAX, data, data_len,
|
||||
wil_nl80211_loc_policy, NULL);
|
||||
if (rc) {
|
||||
wil_err(wil, "Invalid ATTR\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (!tb[QCA_WLAN_VENDOR_ATTR_MAC_ADDR] ||
|
||||
!tb[QCA_WLAN_VENDOR_ATTR_AOA_TYPE]) {
|
||||
wil_err(wil, "Must specify MAC address and type\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(&request, 0, sizeof(request));
|
||||
ether_addr_copy(request.mac_addr,
|
||||
nla_data(tb[QCA_WLAN_VENDOR_ATTR_MAC_ADDR]));
|
||||
request.type = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_AOA_TYPE]);
|
||||
if (tb[QCA_WLAN_VENDOR_ATTR_FREQ])
|
||||
request.freq = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_FREQ]);
|
||||
|
||||
rc = wil_aoa_cfg80211_start_measurement(wil, &request);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int wil_aoa_abort_measurement(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
const void *data, int data_len)
|
||||
{
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
|
||||
wil_dbg_misc(wil, "stub\n");
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
void wil_ftm_init(struct wil6210_priv *wil)
|
||||
{
|
||||
mutex_init(&wil->ftm.lock);
|
||||
setup_timer(&wil->ftm.aoa_timer, wil_aoa_timer_fn, (ulong)wil);
|
||||
INIT_WORK(&wil->ftm.aoa_timeout_work, wil_aoa_measurement_timeout);
|
||||
}
|
||||
|
||||
void wil_ftm_deinit(struct wil6210_priv *wil)
|
||||
{
|
||||
del_timer_sync(&wil->ftm.aoa_timer);
|
||||
cancel_work_sync(&wil->ftm.aoa_timeout_work);
|
||||
kfree(wil->ftm.ftm_res);
|
||||
}
|
||||
|
||||
void wil_ftm_stop_operations(struct wil6210_priv *wil)
|
||||
{
|
||||
wil_ftm_cfg80211_session_ended(
|
||||
wil, QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_ABORTED);
|
||||
}
|
520
drivers/net/wireless/ath/wil6210/ftm.h
Normal file
520
drivers/net/wireless/ath/wil6210/ftm.h
Normal file
@ -0,0 +1,520 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __WIL6210_FTM_H__
|
||||
#define __WIL6210_FTM_H__
|
||||
|
||||
/**
|
||||
* NOTE: The authoritative place for definition of QCA_NL80211_VENDOR_ID,
|
||||
* vendor subcmd definitions prefixed with QCA_NL80211_VENDOR_SUBCMD, and
|
||||
* qca_wlan_vendor_attr is open source file src/common/qca-vendor.h in
|
||||
* git://w1.fi/srv/git/hostap.git; the values here are just a copy of that
|
||||
*/
|
||||
|
||||
/**
|
||||
* enum qca_vendor_attr_loc - attributes for FTM and AOA commands
|
||||
*
|
||||
* @QCA_WLAN_VENDOR_ATTR_FTM_SESSION_COOKIE: Session cookie, specified in
|
||||
* %QCA_NL80211_VENDOR_SUBCMD_FTM_START_SESSION. It will be provided by driver
|
||||
* events and can be used to identify events targeted for this session.
|
||||
* @QCA_WLAN_VENDOR_ATTR_LOC_CAPA: Nested attribute containing extra
|
||||
* FTM/AOA capabilities, returned by %QCA_NL80211_VENDOR_SUBCMD_LOC_GET_CAPA.
|
||||
* see %enum qca_wlan_vendor_attr_loc_capa.
|
||||
* @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PEERS: array of nested attributes
|
||||
* containing information about each peer in measurement session
|
||||
* request. See %enum qca_wlan_vendor_attr_peer_info for supported
|
||||
* attributes for each peer
|
||||
* @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RESULTS: nested attribute containing
|
||||
* measurement results for a peer. reported by the
|
||||
* %QCA_NL80211_VENDOR_SUBCMD_FTM_MEAS_RESULT event.
|
||||
* See %enum qca_wlan_vendor_attr_peer_result for list of supported
|
||||
* attributes.
|
||||
* @QCA_WLAN_VENDOR_ATTR_FTM_RESPONDER_ENABLE: flag attribute for
|
||||
* enabling or disabling responder functionality.
|
||||
* @QCA_WLAN_VENDOR_ATTR_FTM_LCI: used in the
|
||||
* %QCA_NL80211_VENDOR_SUBCMD_FTM_CFG_RESPONDER command in order to
|
||||
* specify the LCI report that will be sent by the responder during
|
||||
* a measurement exchange. The format is defined in IEEE P802.11-REVmc/D5.0,
|
||||
* 9.4.2.22.10
|
||||
* @QCA_WLAN_VENDOR_ATTR_FTM_LCR: provided with the
|
||||
* %QCA_NL80211_VENDOR_SUBCMD_FTM_CFG_RESPONDER command in order to
|
||||
* specify the location civic report that will be sent by the responder during
|
||||
* a measurement exchange. The format is defined in IEEE P802.11-REVmc/D5.0,
|
||||
* 9.4.2.22.13
|
||||
* @QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS: session/measurement completion
|
||||
* status code, reported in %QCA_NL80211_VENDOR_SUBCMD_FTM_SESSION_DONE
|
||||
* and %QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS_RESULT
|
||||
* @QCA_WLAN_VENDOR_ATTR_FTM_INITIAL_TOKEN: initial dialog token used
|
||||
* by responder (0 if not specified)
|
||||
* @QCA_WLAN_VENDOR_ATTR_AOA_TYPE: AOA measurement type. Requested in
|
||||
* %QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS and optionally in
|
||||
* %QCA_NL80211_VENDOR_SUBCMD_FTM_START_SESSION if AOA measurements
|
||||
* are needed as part of an FTM session.
|
||||
* Reported by QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS_RESULT.
|
||||
* See enum qca_wlan_vendor_attr_aoa_type.
|
||||
* @QCA_WLAN_VENDOR_ATTR_LOC_ANTENNA_ARRAY_MASK: bit mask indicating
|
||||
* which antenna arrays were used in location measurement.
|
||||
* Reported in %QCA_NL80211_VENDOR_SUBCMD_FTM_MEAS_RESULT and
|
||||
* %QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS_RESULT
|
||||
* @QCA_WLAN_VENDOR_ATTR_AOA_MEAS_RESULT: AOA measurement data.
|
||||
* Its contents depends on the AOA type and antenna array mask:
|
||||
* %QCA_WLAN_VENDOR_ATTR_AOA_TYPE_TOP_CIR_PHASE: array of U16 values,
|
||||
* phase of the strongest CIR path for each antenna in the measured
|
||||
* array(s).
|
||||
* %QCA_WLAN_VENDOR_ATTR_AOA_TYPE_TOP_CIR_PHASE_AMP: array of 2 U16
|
||||
* values, phase and amplitude of the strongest CIR path for each
|
||||
* antenna in the measured array(s)
|
||||
* @QCA_WLAN_VENDOR_ATTR_FREQ: Frequency where peer is listening, in MHz.
|
||||
* Unsigned 32 bit value.
|
||||
*/
|
||||
enum qca_wlan_vendor_attr_loc {
|
||||
/* we reuse these attributes */
|
||||
QCA_WLAN_VENDOR_ATTR_MAC_ADDR = 6,
|
||||
QCA_WLAN_VENDOR_ATTR_PAD = 13,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_SESSION_COOKIE = 14,
|
||||
QCA_WLAN_VENDOR_ATTR_LOC_CAPA = 15,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PEERS = 16,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PEER_RESULTS = 17,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_RESPONDER_ENABLE = 18,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_LCI = 19,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_LCR = 20,
|
||||
QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS = 21,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_INITIAL_TOKEN = 22,
|
||||
QCA_WLAN_VENDOR_ATTR_AOA_TYPE = 23,
|
||||
QCA_WLAN_VENDOR_ATTR_LOC_ANTENNA_ARRAY_MASK = 24,
|
||||
QCA_WLAN_VENDOR_ATTR_AOA_MEAS_RESULT = 25,
|
||||
QCA_WLAN_VENDOR_ATTR_FREQ = 28,
|
||||
/* keep last */
|
||||
QCA_WLAN_VENDOR_ATTR_LOC_AFTER_LAST,
|
||||
QCA_WLAN_VENDOR_ATTR_LOC_MAX = QCA_WLAN_VENDOR_ATTR_LOC_AFTER_LAST - 1,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum qca_wlan_vendor_attr_loc_capa - indoor location capabilities
|
||||
*
|
||||
* @QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAGS: various flags. See
|
||||
* %enum qca_wlan_vendor_attr_loc_capa_flags
|
||||
* @QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_NUM_SESSIONS: Maximum number
|
||||
* of measurement sessions that can run concurrently.
|
||||
* Default is one session (no session concurrency)
|
||||
* @QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_NUM_PEERS: The total number of unique
|
||||
* peers that are supported in running sessions. For example,
|
||||
* if the value is 8 and maximum number of sessions is 2, you can
|
||||
* have one session with 8 unique peers, or 2 sessions with 4 unique
|
||||
* peers each, and so on.
|
||||
* @QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_NUM_BURSTS_EXP: Maximum number
|
||||
* of bursts per peer, as an exponent (2^value). Default is 0,
|
||||
* meaning no multi-burst support.
|
||||
* @QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_MEAS_PER_BURST: Maximum number
|
||||
* of measurement exchanges allowed in a single burst
|
||||
* @QCA_WLAN_VENDOR_ATTR_AOA_CAPA_SUPPORTED_TYPES: Supported AOA measurement
|
||||
* types. A bit mask (unsigned 32 bit value), each bit corresponds
|
||||
* to an AOA type as defined by %enum qca_vendor_attr_aoa_type.
|
||||
*/
|
||||
enum qca_wlan_vendor_attr_loc_capa {
|
||||
QCA_WLAN_VENDOR_ATTR_LOC_CAPA_INVALID,
|
||||
QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAGS,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_NUM_SESSIONS,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_NUM_PEERS,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_NUM_BURSTS_EXP,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_MEAS_PER_BURST,
|
||||
QCA_WLAN_VENDOR_ATTR_AOA_CAPA_SUPPORTED_TYPES,
|
||||
/* keep last */
|
||||
QCA_WLAN_VENDOR_ATTR_LOC_CAPA_AFTER_LAST,
|
||||
QCA_WLAN_VENDOR_ATTR_LOC_CAPA_MAX =
|
||||
QCA_WLAN_VENDOR_ATTR_LOC_CAPA_AFTER_LAST - 1,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum qca_wlan_vendor_attr_loc_capa_flags: Indoor location capability flags
|
||||
*
|
||||
* @QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_FTM_RESPONDER: Set if driver
|
||||
* can be configured as an FTM responder (for example, an AP that
|
||||
* services FTM requests). %QCA_NL80211_VENDOR_SUBCMD_FTM_CFG_RESPONDER
|
||||
* will be supported if set.
|
||||
* @QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_FTM_INITIATOR: Set if driver
|
||||
* can run FTM sessions. %QCA_NL80211_VENDOR_SUBCMD_FTM_START_SESSION
|
||||
* will be supported if set.
|
||||
* @QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_ASAP: Set if FTM responder
|
||||
* supports immediate (ASAP) response.
|
||||
* @QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_AOA: Set if driver supports standalone
|
||||
* AOA measurement using %QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS
|
||||
* @QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_AOA_IN_FTM: Set if driver supports
|
||||
* requesting AOA measurements as part of an FTM session.
|
||||
*/
|
||||
enum qca_wlan_vendor_attr_loc_capa_flags {
|
||||
QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_FTM_RESPONDER = 1 << 0,
|
||||
QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_FTM_INITIATOR = 1 << 1,
|
||||
QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_ASAP = 1 << 2,
|
||||
QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_AOA = 1 << 3,
|
||||
QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_AOA_IN_FTM = 1 << 4,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum qca_wlan_vendor_attr_peer_info: information about
|
||||
* a single peer in a measurement session.
|
||||
*
|
||||
* @QCA_WLAN_VENDOR_ATTR_FTM_PEER_MAC_ADDR: The MAC address of the peer.
|
||||
* @QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAGS: Various flags related
|
||||
* to measurement. See %enum qca_wlan_vendor_attr_ftm_peer_meas_flags.
|
||||
* @QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_PARAMS: Nested attribute of
|
||||
* FTM measurement parameters, as specified by IEEE P802.11-REVmc/D7.0,
|
||||
* 9.4.2.167. See %enum qca_wlan_vendor_attr_ftm_meas_param for
|
||||
* list of supported attributes.
|
||||
* @QCA_WLAN_VENDOR_ATTR_FTM_PEER_SECURE_TOKEN_ID: Initial token ID for
|
||||
* secure measurement
|
||||
* @QCA_WLAN_VENDOR_ATTR_FTM_PEER_AOA_BURST_PERIOD: Request AOA
|
||||
* measurement every _value_ bursts. If 0 or not specified,
|
||||
* AOA measurements will be disabled for this peer.
|
||||
* @QCA_WLAN_VENDOR_ATTR_FTM_PEER_FREQ: Frequency in MHz where
|
||||
* peer is listening. Optional; if not specified, use the
|
||||
* entry from the kernel scan results cache.
|
||||
*/
|
||||
enum qca_wlan_vendor_attr_ftm_peer_info {
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PEER_INVALID,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PEER_MAC_ADDR,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAGS,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_PARAMS,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PEER_SECURE_TOKEN_ID,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PEER_AOA_BURST_PERIOD,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PEER_FREQ,
|
||||
/* keep last */
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PEER_AFTER_LAST,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PEER_MAX =
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PEER_AFTER_LAST - 1,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum qca_wlan_vendor_attr_ftm_peer_meas_flags: Measurement request flags,
|
||||
* per-peer
|
||||
* @QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_ASAP: If set, request
|
||||
* immediate (ASAP) response from peer
|
||||
* @QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_LCI: If set, request
|
||||
* LCI report from peer. The LCI report includes the absolute
|
||||
* location of the peer in "official" coordinates (similar to GPS).
|
||||
* See IEEE P802.11-REVmc/D7.0, 11.24.6.7 for more information.
|
||||
* @QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_LCR: If set, request
|
||||
* Location civic report from peer. The LCR includes the location
|
||||
* of the peer in free-form format. See IEEE P802.11-REVmc/D7.0,
|
||||
* 11.24.6.7 for more information.
|
||||
* @QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_SECURE: If set,
|
||||
* request a secure measurement.
|
||||
* %QCA_WLAN_VENDOR_ATTR_FTM_PEER_SECURE_TOKEN_ID must also be provided.
|
||||
*/
|
||||
enum qca_wlan_vendor_attr_ftm_peer_meas_flags {
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_ASAP = 1 << 0,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_LCI = 1 << 1,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_LCR = 1 << 2,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_SECURE = 1 << 3,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum qca_wlan_vendor_attr_ftm_meas_param: Measurement parameters
|
||||
*
|
||||
* @QCA_WLAN_VENDOR_ATTR_FTM_PARAM_MEAS_PER_BURST: Number of measurements
|
||||
* to perform in a single burst.
|
||||
* @QCA_WLAN_VENDOR_ATTR_FTM_PARAM_NUM_BURSTS_EXP: Number of bursts to
|
||||
* perform, specified as an exponent (2^value)
|
||||
* @QCA_WLAN_VENDOR_ATTR_FTM_PARAM_BURST_DURATION: Duration of burst
|
||||
* instance, as specified in IEEE P802.11-REVmc/D7.0, 9.4.2.167
|
||||
* @QCA_WLAN_VENDOR_ATTR_FTM_PARAM_BURST_PERIOD: Time between bursts,
|
||||
* as specified in IEEE P802.11-REVmc/D7.0, 9.4.2.167. Must
|
||||
* be larger than %QCA_WLAN_VENDOR_ATTR_FTM_PARAM_BURST_DURATION
|
||||
*/
|
||||
enum qca_wlan_vendor_attr_ftm_meas_param {
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PARAM_INVALID,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PARAM_MEAS_PER_BURST,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PARAM_NUM_BURSTS_EXP,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PARAM_BURST_DURATION,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PARAM_BURST_PERIOD,
|
||||
/* keep last */
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PARAM_AFTER_LAST,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PARAM_MAX =
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PARAM_AFTER_LAST - 1,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum qca_wlan_vendor_attr_ftm_peer_result: Per-peer results
|
||||
*
|
||||
* @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MAC_ADDR: MAC address of the reported
|
||||
* peer
|
||||
* @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS: Status of measurement
|
||||
* request for this peer.
|
||||
* See %enum qca_wlan_vendor_attr_ftm_peer_result_status
|
||||
* @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_FLAGS: Various flags related
|
||||
* to measurement results for this peer.
|
||||
* See %enum qca_wlan_vendor_attr_ftm_peer_result_flags
|
||||
* @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_VALUE_SECONDS: Specified when
|
||||
* request failed and peer requested not to send an additional request
|
||||
* for this number of seconds.
|
||||
* @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_LCI: LCI report when received
|
||||
* from peer. In the format specified by IEEE P802.11-REVmc/D7.0,
|
||||
* 9.4.2.22.10
|
||||
* @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_LCR: Location civic report when
|
||||
* received from peer.In the format specified by IEEE P802.11-REVmc/D7.0,
|
||||
* 9.4.2.22.13
|
||||
* @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MEAS_PARAMS: Reported when peer
|
||||
* overridden some measurement request parameters. See
|
||||
* enum qca_wlan_vendor_attr_ftm_meas_param.
|
||||
* @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_AOA_MEAS: AOA measurement
|
||||
* for this peer. Same contents as %QCA_WLAN_VENDOR_ATTR_AOA_MEAS_RESULT
|
||||
* @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MEAS: Array of measurement
|
||||
* results. Each entry is a nested attribute defined
|
||||
* by enum qca_wlan_vendor_attr_ftm_meas.
|
||||
*/
|
||||
enum qca_wlan_vendor_attr_ftm_peer_result {
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_INVALID,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MAC_ADDR,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_FLAGS,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_VALUE_SECONDS,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_LCI,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_LCR,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MEAS_PARAMS,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_AOA_MEAS,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MEAS,
|
||||
/* keep last */
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_AFTER_LAST,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MAX =
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_AFTER_LAST - 1,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum qca_wlan_vendor_attr_ftm_peer_result_status
|
||||
*
|
||||
* @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_OK: Request sent ok and results
|
||||
* will be provided. Peer may have overridden some measurement parameters,
|
||||
* in which case overridden parameters will be report by
|
||||
* %QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MEAS_PARAMS attribute
|
||||
* @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_INCAPABLE: Peer is incapable
|
||||
* of performing the measurement request. No more results will be sent
|
||||
* for this peer in this session.
|
||||
* @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_FAILED: Peer reported request
|
||||
* failed, and requested not to send an additional request for number
|
||||
* of seconds specified by %QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_VALUE_SECONDS
|
||||
* attribute.
|
||||
* @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_INVALID: Request validation
|
||||
* failed. Request was not sent over the air.
|
||||
*/
|
||||
enum qca_wlan_vendor_attr_ftm_peer_result_status {
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_OK,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_INCAPABLE,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_FAILED,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_INVALID,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum qca_wlan_vendor_attr_ftm_peer_result_flags : Various flags
|
||||
* for measurement result, per-peer
|
||||
*
|
||||
* @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_FLAG_DONE: If set,
|
||||
* measurement completed for this peer. No more results will be reported
|
||||
* for this peer in this session.
|
||||
*/
|
||||
enum qca_wlan_vendor_attr_ftm_peer_result_flags {
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_FLAG_DONE = 1 << 0,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum qca_vendor_attr_loc_session_status: Session completion status code
|
||||
*
|
||||
* @QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_OK: Session completed
|
||||
* successfully.
|
||||
* @QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_ABORTED: Session aborted
|
||||
* by request
|
||||
* @QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_INVALID: Session request
|
||||
* was invalid and was not started
|
||||
* @QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_FAILED: Session had an error
|
||||
* and did not complete normally (for example out of resources)
|
||||
*
|
||||
*/
|
||||
enum qca_vendor_attr_loc_session_status {
|
||||
QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_OK,
|
||||
QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_ABORTED,
|
||||
QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_INVALID,
|
||||
QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_FAILED,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum qca_wlan_vendor_attr_ftm_meas: Single measurement data
|
||||
*
|
||||
* @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T1: Time of departure(TOD) of FTM packet as
|
||||
* recorded by responder, in picoseconds.
|
||||
* See IEEE P802.11-REVmc/D7.0, 11.24.6.4 for more information.
|
||||
* @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T2: Time of arrival(TOA) of FTM packet at
|
||||
* initiator, in picoseconds.
|
||||
* See IEEE P802.11-REVmc/D7.0, 11.24.6.4 for more information.
|
||||
* @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T3: TOD of ACK packet as recorded by
|
||||
* initiator, in picoseconds.
|
||||
* See IEEE P802.11-REVmc/D7.0, 11.24.6.4 for more information.
|
||||
* @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T4: TOA of ACK packet at
|
||||
* responder, in picoseconds.
|
||||
* See IEEE P802.11-REVmc/D7.0, 11.24.6.4 for more information.
|
||||
* @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_RSSI: RSSI (signal level) as recorded
|
||||
* during this measurement exchange. Optional and will be provided if
|
||||
* the hardware can measure it.
|
||||
* @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_TOD_ERR: TOD error reported by
|
||||
* responder. Not always provided.
|
||||
* See IEEE P802.11-REVmc/D7.0, 9.6.8.33 for more information.
|
||||
* @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_TOA_ERR: TOA error reported by
|
||||
* responder. Not always provided.
|
||||
* See IEEE P802.11-REVmc/D7.0, 9.6.8.33 for more information.
|
||||
* @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_INITIATOR_TOD_ERR: TOD error measured by
|
||||
* initiator. Not always provided.
|
||||
* See IEEE P802.11-REVmc/D7.0, 9.6.8.33 for more information.
|
||||
* @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_INITIATOR_TOA_ERR: TOA error measured by
|
||||
* initiator. Not always provided.
|
||||
* See IEEE P802.11-REVmc/D7.0, 9.6.8.33 for more information.
|
||||
* @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PAD: Dummy attribute for padding.
|
||||
*/
|
||||
enum qca_wlan_vendor_attr_ftm_meas {
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_MEAS_INVALID,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T1,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T2,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T3,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T4,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_MEAS_RSSI,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_MEAS_TOD_ERR,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_MEAS_TOA_ERR,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_MEAS_INITIATOR_TOD_ERR,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_MEAS_INITIATOR_TOA_ERR,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PAD,
|
||||
/* keep last */
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_MEAS_AFTER_LAST,
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_MEAS_MAX =
|
||||
QCA_WLAN_VENDOR_ATTR_FTM_MEAS_AFTER_LAST - 1,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum qca_wlan_vendor_attr_aoa_type: AOA measurement type
|
||||
*
|
||||
* @QCA_WLAN_VENDOR_ATTR_AOA_TYPE_TOP_CIR_PHASE: Phase of the strongest
|
||||
* CIR (channel impulse response) path for each antenna.
|
||||
* @QCA_WLAN_VENDOR_ATTR_AOA_TYPE_TOP_CIR_PHASE_AMP: Phase and amplitude
|
||||
* of the strongest CIR path for each antenna.
|
||||
*/
|
||||
enum qca_wlan_vendor_attr_aoa_type {
|
||||
QCA_WLAN_VENDOR_ATTR_AOA_TYPE_TOP_CIR_PHASE,
|
||||
QCA_WLAN_VENDOR_ATTR_AOA_TYPE_TOP_CIR_PHASE_AMP,
|
||||
QCA_WLAN_VENDOR_ATTR_AOA_TYPE_MAX,
|
||||
};
|
||||
|
||||
/* vendor event indices, used from both cfg80211.c and ftm.c */
|
||||
enum qca_nl80211_vendor_events_index {
|
||||
QCA_NL80211_VENDOR_EVENT_FTM_MEAS_RESULT_INDEX,
|
||||
QCA_NL80211_VENDOR_EVENT_FTM_SESSION_DONE_INDEX,
|
||||
QCA_NL80211_VENDOR_EVENT_AOA_MEAS_RESULT_INDEX,
|
||||
};
|
||||
|
||||
/* measurement parameters. Specified for each peer as part
|
||||
* of measurement request, or provided with measurement
|
||||
* results for peer in case peer overridden parameters
|
||||
*/
|
||||
struct wil_ftm_meas_params {
|
||||
u8 meas_per_burst;
|
||||
u8 num_of_bursts_exp;
|
||||
u8 burst_duration;
|
||||
u16 burst_period;
|
||||
};
|
||||
|
||||
/* measurement request for a single peer */
|
||||
struct wil_ftm_meas_peer_info {
|
||||
u8 mac_addr[ETH_ALEN];
|
||||
u32 freq;
|
||||
u32 flags; /* enum qca_wlan_vendor_attr_ftm_peer_meas_flags */
|
||||
struct wil_ftm_meas_params params;
|
||||
u8 secure_token_id;
|
||||
};
|
||||
|
||||
/* session request, passed to wil_ftm_cfg80211_start_session */
|
||||
struct wil_ftm_session_request {
|
||||
u64 session_cookie;
|
||||
u32 n_peers;
|
||||
/* keep last, variable size according to n_peers */
|
||||
struct wil_ftm_meas_peer_info peers[0];
|
||||
};
|
||||
|
||||
/* single measurement for a peer */
|
||||
struct wil_ftm_peer_meas {
|
||||
u64 t1, t2, t3, t4;
|
||||
};
|
||||
|
||||
/* measurement results for a single peer */
|
||||
struct wil_ftm_peer_meas_res {
|
||||
u8 mac_addr[ETH_ALEN];
|
||||
u32 flags; /* enum qca_wlan_vendor_attr_ftm_peer_result_flags */
|
||||
u8 status; /* enum qca_wlan_vendor_attr_ftm_peer_result_status */
|
||||
u8 value_seconds;
|
||||
bool has_params; /* true if params is valid */
|
||||
struct wil_ftm_meas_params params; /* peer overridden params */
|
||||
u8 *lci;
|
||||
u8 lci_length;
|
||||
u8 *lcr;
|
||||
u8 lcr_length;
|
||||
u32 n_meas;
|
||||
/* keep last, variable size according to n_meas */
|
||||
struct wil_ftm_peer_meas meas[0];
|
||||
};
|
||||
|
||||
/* standalone AOA measurement request */
|
||||
struct wil_aoa_meas_request {
|
||||
u8 mac_addr[ETH_ALEN];
|
||||
u32 freq;
|
||||
u32 type;
|
||||
};
|
||||
|
||||
/* AOA measurement result */
|
||||
struct wil_aoa_meas_result {
|
||||
u8 mac_addr[ETH_ALEN];
|
||||
u32 type;
|
||||
u32 antenna_array_mask;
|
||||
u32 status;
|
||||
u32 length;
|
||||
/* keep last, variable size according to length */
|
||||
u8 data[0];
|
||||
};
|
||||
|
||||
/* private data related to FTM. Part of the wil6210_priv structure */
|
||||
struct wil_ftm_priv {
|
||||
struct mutex lock; /* protects the FTM data */
|
||||
u8 session_started;
|
||||
u64 session_cookie;
|
||||
struct wil_ftm_peer_meas_res *ftm_res;
|
||||
u8 has_ftm_res;
|
||||
u32 max_ftm_meas;
|
||||
|
||||
/* standalone AOA measurement */
|
||||
u8 aoa_started;
|
||||
u8 aoa_peer_mac_addr[ETH_ALEN];
|
||||
u32 aoa_type;
|
||||
struct timer_list aoa_timer;
|
||||
struct work_struct aoa_timeout_work;
|
||||
};
|
||||
|
||||
int wil_ftm_get_capabilities(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
const void *data, int data_len);
|
||||
int wil_ftm_start_session(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
const void *data, int data_len);
|
||||
int wil_ftm_abort_session(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
const void *data, int data_len);
|
||||
int wil_ftm_configure_responder(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
const void *data, int data_len);
|
||||
int wil_aoa_start_measurement(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
const void *data, int data_len);
|
||||
int wil_aoa_abort_measurement(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
const void *data, int data_len);
|
||||
|
||||
#endif /* __WIL6210_FTM_H__ */
|
@ -558,6 +558,8 @@ int wil_priv_init(struct wil6210_priv *wil)
|
||||
wil->net_queue_stopped = 1;
|
||||
init_waitqueue_head(&wil->wq);
|
||||
|
||||
wil_ftm_init(wil);
|
||||
|
||||
wil->wmi_wq = create_singlethread_workqueue(WIL_NAME "_wmi");
|
||||
if (!wil->wmi_wq)
|
||||
return -EAGAIN;
|
||||
@ -622,6 +624,7 @@ void wil_priv_deinit(struct wil6210_priv *wil)
|
||||
{
|
||||
wil_dbg_misc(wil, "priv_deinit\n");
|
||||
|
||||
wil_ftm_deinit(wil);
|
||||
wil_set_recovery_state(wil, fw_recovery_idle);
|
||||
del_timer_sync(&wil->scan_timer);
|
||||
del_timer_sync(&wil->p2p.discovery_timer);
|
||||
@ -1189,6 +1192,8 @@ int __wil_down(struct wil6210_priv *wil)
|
||||
}
|
||||
wil_enable_irq(wil);
|
||||
|
||||
wil_ftm_stop_operations(wil);
|
||||
|
||||
mutex_lock(&wil->p2p_wdev_mutex);
|
||||
wil_p2p_stop_radio_operations(wil);
|
||||
wil_abort_scan(wil, false);
|
||||
|
@ -332,7 +332,7 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
wil6210_debugfs_init(wil);
|
||||
|
||||
wil6210_sysfs_init(wil);
|
||||
|
||||
return 0;
|
||||
|
||||
@ -365,6 +365,7 @@ static void wil_pcie_remove(struct pci_dev *pdev)
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
wil6210_sysfs_remove(wil);
|
||||
wil6210_debugfs_remove(wil);
|
||||
rtnl_lock();
|
||||
wil_p2p_wdev_free(wil);
|
||||
|
126
drivers/net/wireless/ath/wil6210/sysfs.c
Normal file
126
drivers/net/wireless/ath/wil6210/sysfs.c
Normal file
@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright (c) 2017, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/sysfs.h>
|
||||
|
||||
#include "wil6210.h"
|
||||
#include "wmi.h"
|
||||
|
||||
static ssize_t
|
||||
wil_ftm_txrx_offset_sysfs_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct wil6210_priv *wil = dev_get_drvdata(dev);
|
||||
struct {
|
||||
struct wmi_cmd_hdr wmi;
|
||||
struct wmi_tof_get_tx_rx_offset_event evt;
|
||||
} __packed reply;
|
||||
int rc;
|
||||
ssize_t len;
|
||||
|
||||
if (!test_bit(WMI_FW_CAPABILITY_FTM, wil->fw_capabilities))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
memset(&reply, 0, sizeof(reply));
|
||||
rc = wmi_call(wil, WMI_TOF_GET_TX_RX_OFFSET_CMDID, NULL, 0,
|
||||
WMI_TOF_GET_TX_RX_OFFSET_EVENTID,
|
||||
&reply, sizeof(reply), 100);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
if (reply.evt.status) {
|
||||
wil_err(wil, "get_tof_tx_rx_offset failed, error %d\n",
|
||||
reply.evt.status);
|
||||
return -EIO;
|
||||
}
|
||||
len = snprintf(buf, PAGE_SIZE, "%u %u\n",
|
||||
le32_to_cpu(reply.evt.tx_offset),
|
||||
le32_to_cpu(reply.evt.rx_offset));
|
||||
return len;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
wil_ftm_txrx_offset_sysfs_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct wil6210_priv *wil = dev_get_drvdata(dev);
|
||||
struct wmi_tof_set_tx_rx_offset_cmd cmd;
|
||||
struct {
|
||||
struct wmi_cmd_hdr wmi;
|
||||
struct wmi_tof_set_tx_rx_offset_event evt;
|
||||
} __packed reply;
|
||||
unsigned int tx_offset, rx_offset;
|
||||
int rc;
|
||||
|
||||
if (sscanf(buf, "%u %u", &tx_offset, &rx_offset) != 2)
|
||||
return -EINVAL;
|
||||
|
||||
if (!test_bit(WMI_FW_CAPABILITY_FTM, wil->fw_capabilities))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.tx_offset = cpu_to_le32(tx_offset);
|
||||
cmd.rx_offset = cpu_to_le32(rx_offset);
|
||||
memset(&reply, 0, sizeof(reply));
|
||||
rc = wmi_call(wil, WMI_TOF_SET_TX_RX_OFFSET_CMDID, &cmd, sizeof(cmd),
|
||||
WMI_TOF_SET_TX_RX_OFFSET_EVENTID,
|
||||
&reply, sizeof(reply), 100);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
if (reply.evt.status) {
|
||||
wil_err(wil, "set_tof_tx_rx_offset failed, error %d\n",
|
||||
reply.evt.status);
|
||||
return -EIO;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(ftm_txrx_offset, 0644,
|
||||
wil_ftm_txrx_offset_sysfs_show,
|
||||
wil_ftm_txrx_offset_sysfs_store);
|
||||
|
||||
static struct attribute *wil6210_sysfs_entries[] = {
|
||||
&dev_attr_ftm_txrx_offset.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group wil6210_attribute_group = {
|
||||
.name = "wil6210",
|
||||
.attrs = wil6210_sysfs_entries,
|
||||
};
|
||||
|
||||
int wil6210_sysfs_init(struct wil6210_priv *wil)
|
||||
{
|
||||
struct device *dev = wil_to_dev(wil);
|
||||
int err;
|
||||
|
||||
err = sysfs_create_group(&dev->kobj, &wil6210_attribute_group);
|
||||
if (err) {
|
||||
wil_err(wil, "failed to create sysfs group: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void wil6210_sysfs_remove(struct wil6210_priv *wil)
|
||||
{
|
||||
struct device *dev = wil_to_dev(wil);
|
||||
|
||||
sysfs_remove_group(&dev->kobj, &wil6210_attribute_group);
|
||||
}
|
@ -25,6 +25,7 @@
|
||||
#include <linux/types.h>
|
||||
#include "wmi.h"
|
||||
#include "wil_platform.h"
|
||||
#include "ftm.h"
|
||||
|
||||
extern bool no_fw_recovery;
|
||||
extern unsigned int mtu_max;
|
||||
@ -731,6 +732,8 @@ struct wil6210_priv {
|
||||
|
||||
int fw_calib_result;
|
||||
|
||||
struct wil_ftm_priv ftm;
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
struct notifier_block pm_notify;
|
||||
@ -949,6 +952,9 @@ static inline int wil6210_debugfs_init(struct wil6210_priv *wil) { return 0; }
|
||||
static inline void wil6210_debugfs_remove(struct wil6210_priv *wil) {}
|
||||
#endif
|
||||
|
||||
int wil6210_sysfs_init(struct wil6210_priv *wil);
|
||||
void wil6210_sysfs_remove(struct wil6210_priv *wil);
|
||||
|
||||
int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid,
|
||||
struct station_info *sinfo);
|
||||
|
||||
@ -964,6 +970,8 @@ int wmi_led_cfg(struct wil6210_priv *wil, bool enable);
|
||||
int wmi_abort_scan(struct wil6210_priv *wil);
|
||||
void wil_abort_scan(struct wil6210_priv *wil, bool sync);
|
||||
void wil6210_bus_request(struct wil6210_priv *wil, u32 kbps);
|
||||
int wmi_aoa_meas(struct wil6210_priv *wil, const void *mac_addr, u8 chan,
|
||||
u8 type);
|
||||
void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
|
||||
u16 reason_code, bool from_event);
|
||||
void wil_probe_client_flush(struct wil6210_priv *wil);
|
||||
@ -1016,4 +1024,18 @@ void wil_halp_unvote(struct wil6210_priv *wil);
|
||||
void wil6210_set_halp(struct wil6210_priv *wil);
|
||||
void wil6210_clear_halp(struct wil6210_priv *wil);
|
||||
|
||||
void wil_ftm_init(struct wil6210_priv *wil);
|
||||
void wil_ftm_deinit(struct wil6210_priv *wil);
|
||||
void wil_ftm_stop_operations(struct wil6210_priv *wil);
|
||||
void wil_aoa_cfg80211_meas_result(struct wil6210_priv *wil,
|
||||
struct wil_aoa_meas_result *result);
|
||||
|
||||
void wil_ftm_evt_session_ended(struct wil6210_priv *wil,
|
||||
struct wmi_tof_session_end_event *evt);
|
||||
void wil_ftm_evt_per_dest_res(struct wil6210_priv *wil,
|
||||
struct wmi_tof_ftm_per_dest_res_event *evt);
|
||||
void wil_aoa_evt_meas(struct wil6210_priv *wil,
|
||||
struct wmi_aoa_meas_event *evt,
|
||||
int len);
|
||||
|
||||
#endif /* __WIL6210_H__ */
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "txrx.h"
|
||||
#include "wmi.h"
|
||||
#include "trace.h"
|
||||
#include "ftm.h"
|
||||
|
||||
static uint max_assoc_sta = WIL6210_MAX_CID;
|
||||
module_param(max_assoc_sta, uint, 0644);
|
||||
@ -830,6 +831,30 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
|
||||
spin_unlock_bh(&sta->tid_rx_lock);
|
||||
}
|
||||
|
||||
static void wmi_evt_aoa_meas(struct wil6210_priv *wil, int id,
|
||||
void *d, int len)
|
||||
{
|
||||
struct wmi_aoa_meas_event *evt = d;
|
||||
|
||||
wil_aoa_evt_meas(wil, evt, len);
|
||||
}
|
||||
|
||||
static void wmi_evt_ftm_session_ended(struct wil6210_priv *wil, int id,
|
||||
void *d, int len)
|
||||
{
|
||||
struct wmi_tof_session_end_event *evt = d;
|
||||
|
||||
wil_ftm_evt_session_ended(wil, evt);
|
||||
}
|
||||
|
||||
static void wmi_evt_per_dest_res(struct wil6210_priv *wil, int id,
|
||||
void *d, int len)
|
||||
{
|
||||
struct wmi_tof_ftm_per_dest_res_event *evt = d;
|
||||
|
||||
wil_ftm_evt_per_dest_res(wil, evt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Some events are ignored for purpose; and need not be interpreted as
|
||||
* "unhandled events"
|
||||
@ -857,6 +882,13 @@ static const struct {
|
||||
{WMI_DELBA_EVENTID, wmi_evt_delba},
|
||||
{WMI_VRING_EN_EVENTID, wmi_evt_vring_en},
|
||||
{WMI_DATA_PORT_OPEN_EVENTID, wmi_evt_ignore},
|
||||
{WMI_AOA_MEAS_EVENTID, wmi_evt_aoa_meas},
|
||||
{WMI_TOF_SESSION_END_EVENTID, wmi_evt_ftm_session_ended},
|
||||
{WMI_TOF_GET_CAPABILITIES_EVENTID, wmi_evt_ignore},
|
||||
{WMI_TOF_SET_LCR_EVENTID, wmi_evt_ignore},
|
||||
{WMI_TOF_SET_LCI_EVENTID, wmi_evt_ignore},
|
||||
{WMI_TOF_FTM_PER_DEST_RES_EVENTID, wmi_evt_per_dest_res},
|
||||
{WMI_TOF_CHANNEL_INFO_EVENTID, wmi_evt_ignore},
|
||||
};
|
||||
|
||||
/*
|
||||
|
Loading…
x
Reference in New Issue
Block a user