From 7ffcd595d61a6a83d4c3313c1e7c9478921b95fb Mon Sep 17 00:00:00 2001 From: Lior David Date: Mon, 13 Nov 2017 09:56:37 +0200 Subject: [PATCH 1/5] wil6210: potential buffer overflow in wmi_evt_aoa_meas The code in wmi_evt_aoa_meas can potentially overflow a data buffer if the len parameter is smaller than offsetof(struct wmi_aoa_meas_event, meas_data). Add protection against this case. Change-Id: I3f86f231e0c6b5ac54abbb9865cba0cbbd8d0448 Signed-off-by: Lior David Signed-off-by: Alexei Avshalom Lazar --- drivers/net/wireless/ath/wil6210/ftm.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/ath/wil6210/ftm.c b/drivers/net/wireless/ath/wil6210/ftm.c index bb51fd4ba9b9..bdcaad7080ff 100644 --- a/drivers/net/wireless/ath/wil6210/ftm.c +++ b/drivers/net/wireless/ath/wil6210/ftm.c @@ -681,6 +681,10 @@ void wil_aoa_evt_meas(struct wil6210_vif *vif, int data_len = len - offsetof(struct wmi_aoa_meas_event, meas_data); struct wil_aoa_meas_result *res; + if (data_len < 0) { + wil_err(wil, "AOA event too short (%d)\n", len); + return; + } data_len = min_t(int, le16_to_cpu(evt->length), data_len); res = kmalloc(sizeof(*res) + data_len, GFP_KERNEL); From e805517b18be5173913a0c64fed74db513cdf0e5 Mon Sep 17 00:00:00 2001 From: Lior David Date: Sun, 8 Dec 2019 10:42:34 +0200 Subject: [PATCH 2/5] wil6210: support AOA in FTM session Add support for running AOA measurement as part of an FTM session. In order to simplify the implementation both in the driver and FW, AOA measurement is reported using the same vendor event and not using QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_AOA_MEAS. This way we can also report the antenna array mask which was missing from the vendor commands API for AOA inside FTM session. Change-Id: I3962487b2e6fd8e56e6e3953c86fd95abe6a9aa0 Signed-off-by: Lior David Signed-off-by: Alexei Avshalom Lazar [liord@codeaurora.org: fix merge conflicts] Signed-off-by: Lior David Signed-off-by: Alexei Avshalom Lazar --- drivers/net/wireless/ath/wil6210/ftm.c | 37 +++++++++++++++++++++++--- drivers/net/wireless/ath/wil6210/ftm.h | 2 ++ 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/ftm.c b/drivers/net/wireless/ath/wil6210/ftm.c index bdcaad7080ff..58d49043a25b 100644 --- a/drivers/net/wireless/ath/wil6210/ftm.c +++ b/drivers/net/wireless/ath/wil6210/ftm.c @@ -25,6 +25,9 @@ /* initial token to use on non-secure FTM measurement */ #define WIL_TOF_FTM_DEFAULT_INITIAL_TOKEN 2 +/* maximum AOA burst period, limited by FW */ +#define WIL_AOA_MAX_BURST_PERIOD 255 + #define WIL_TOF_FTM_MAX_LCI_LENGTH (240) #define WIL_TOF_FTM_MAX_LCR_LENGTH (240) @@ -53,6 +56,7 @@ nla_policy wil_nl80211_ftm_peer_policy[QCA_ATTR_FTM_PEER_MAX + 1] = { [QCA_ATTR_FTM_PEER_MEAS_FLAGS] = { .type = NLA_U32 }, [QCA_ATTR_FTM_PEER_MEAS_PARAMS] = { .type = NLA_NESTED }, [QCA_ATTR_FTM_PEER_SEC_TOK_ID] = { .type = NLA_U8 }, + [QCA_ATTR_FTM_PEER_AOA_BURST_PERIOD] = { .type = NLA_U16 }, [QCA_ATTR_FTM_PEER_FREQ] = { .type = NLA_U32 }, }; @@ -351,6 +355,7 @@ wil_ftm_cfg80211_start_session(struct wil6210_vif *vif, } cmd->session_id = cpu_to_le32(WIL_FTM_FW_SESSION_ID); + cmd->aoa_type = request->aoa_type; 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, @@ -393,6 +398,8 @@ wil_ftm_cfg80211_start_session(struct wil6210_vif *vif, request->peers[i].params.burst_duration; cmd->ftm_dest_info[i].burst_period = cpu_to_le16(request->peers[i].params.burst_period); + cmd->ftm_dest_info[i].num_burst_per_aoa_meas = + request->peers[i].aoa_burst_period; } rc = wmi_send(wil, WMI_TOF_SESSION_START_CMDID, vif->mid, @@ -482,8 +489,8 @@ wil_aoa_cfg80211_start_measurement(struct wil6210_vif *vif, mutex_lock(&vif->ftm.lock); - if (vif->ftm.aoa_started) { - wil_err(wil, "AOA measurement already running\n"); + if (vif->ftm.aoa_started || vif->ftm.session_started) { + wil_err(wil, "AOA or FTM measurement already running\n"); rc = -EAGAIN; goto out; } @@ -525,8 +532,8 @@ void wil_aoa_cfg80211_meas_result(struct wil6210_vif *vif, mutex_lock(&vif->ftm.lock); - if (!vif->ftm.aoa_started) { - wil_info(wil, "AOA not started, not sending result\n"); + if (!vif->ftm.aoa_started && !vif->ftm.session_started) { + wil_info(wil, "AOA/FTM not started, not sending result\n"); goto out; } @@ -757,6 +764,7 @@ int wil_ftm_start_session(struct wiphy *wiphy, struct wireless_dev *wdev, struct nlattr *tb2[QCA_ATTR_FTM_PEER_MAX + 1]; struct nlattr *peer; int rc, n_peers = 0, index = 0, tmp; + u32 aoa_type = 0; if (!test_bit(WMI_FW_CAPABILITY_FTM, wil->fw_capabilities)) return -ENOTSUPP; @@ -778,6 +786,14 @@ int wil_ftm_start_session(struct wiphy *wiphy, struct wireless_dev *wdev, return -EINVAL; } + if (tb[QCA_ATTR_AOA_TYPE]) { + aoa_type = nla_get_u32(tb[QCA_ATTR_AOA_TYPE]); + if (aoa_type >= QCA_ATTR_AOA_TYPE_MAX) { + wil_err(wil, "invalid AOA type: %d\n", aoa_type); + return -EINVAL; + } + } + nla_for_each_nested(peer, tb[QCA_ATTR_FTM_MEAS_PEERS], tmp) n_peers++; @@ -801,6 +817,7 @@ int wil_ftm_start_session(struct wiphy *wiphy, struct wireless_dev *wdev, request->session_cookie = nla_get_u64(tb[QCA_ATTR_FTM_SESSION_COOKIE]); + request->aoa_type = aoa_type; request->n_peers = n_peers; nla_for_each_nested(peer, tb[QCA_ATTR_FTM_MEAS_PEERS], tmp) { @@ -829,6 +846,18 @@ int wil_ftm_start_session(struct wiphy *wiphy, struct wireless_dev *wdev, if (tb2[QCA_ATTR_FTM_PEER_SEC_TOK_ID]) request->peers[index].secure_token_id = nla_get_u8(tb2[QCA_ATTR_FTM_PEER_SEC_TOK_ID]); + if (tb2[QCA_ATTR_FTM_PEER_AOA_BURST_PERIOD]) { + request->peers[index].aoa_burst_period = + nla_get_u16(tb2[QCA_ATTR_FTM_PEER_AOA_BURST_PERIOD]); + if (request->peers[index].aoa_burst_period > + WIL_AOA_MAX_BURST_PERIOD) { + wil_err(wil, "Invalid AOA burst period at index: %d\n", + index); + rc = -EINVAL; + goto out; + } + } + rc = wil_ftm_parse_meas_params(wil, tb2[QCA_ATTR_FTM_PEER_MEAS_PARAMS], diff --git a/drivers/net/wireless/ath/wil6210/ftm.h b/drivers/net/wireless/ath/wil6210/ftm.h index 7b6f219f1eff..ec9a1464a657 100644 --- a/drivers/net/wireless/ath/wil6210/ftm.h +++ b/drivers/net/wireless/ath/wil6210/ftm.h @@ -421,12 +421,14 @@ struct wil_ftm_meas_peer_info { u32 flags; /* enum qca_attr_ftm_peer_meas_flags */ struct wil_ftm_meas_params params; u8 secure_token_id; + u16 aoa_burst_period; /* 0 if no AOA, >0 every bursts */ }; /* session request, passed to wil_ftm_cfg80211_start_session */ struct wil_ftm_session_request { u64 session_cookie; u32 n_peers; + u32 aoa_type; /* enum qca_wlan_vendor_attr_aoa_type */ /* keep last, variable size according to n_peers */ struct wil_ftm_meas_peer_info peers[0]; }; From abc9fe894f268a86133147986389d4cdc9046615 Mon Sep 17 00:00:00 2001 From: Dedy Lansky Date: Mon, 2 Dec 2019 15:42:59 +0200 Subject: [PATCH 3/5] wil6210: add sysfs for setting connect SNR threshold snr_thresh sysfs can be used to set omni and direct SNR threshold for connection. Change-Id: I091a6b61a1a4cb98e0e8c0f70b2fff4d22486e61 Signed-off-by: Dedy Lansky CRs-Fixed: 2143032 Signed-off-by: Alexei Avshalom Lazar [liord@codeaurora.org: fix merge conflicts, SPDX license] Signed-off-by: Lior David Signed-off-by: Alexei Avshalom Lazar --- drivers/net/wireless/ath/wil6210/main.c | 10 ++++-- drivers/net/wireless/ath/wil6210/sysfs.c | 37 ++++++++++++++++++++++ drivers/net/wireless/ath/wil6210/wil6210.h | 7 ++++ drivers/net/wireless/ath/wil6210/wmi.c | 31 ++++++++++++++++++ drivers/net/wireless/ath/wil6210/wmi.h | 14 ++------ 5 files changed, 84 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 7a19fefa5b85..4ba1495b9aeb 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -1768,14 +1768,18 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) return rc; } - if (wil->tt_data_set) - wmi_set_tt_cfg(wil, &wil->tt_data); - wil_collect_fw_info(wil); if (wil->ps_profile != WMI_PS_PROFILE_TYPE_DEFAULT) wil_ps_update(wil, wil->ps_profile); + if (wil->tt_data_set) + wmi_set_tt_cfg(wil, &wil->tt_data); + + if (wil->snr_thresh.enabled) + wmi_set_snr_thresh(wil, wil->snr_thresh.omni, + wil->snr_thresh.direct); + if (wil->platform_ops.notify) { rc = wil->platform_ops.notify(wil->platform_handle, WIL_PLATFORM_EVT_FW_RDY); diff --git a/drivers/net/wireless/ath/wil6210/sysfs.c b/drivers/net/wireless/ath/wil6210/sysfs.c index cece8ec1ada7..501ee1f1bf5e 100644 --- a/drivers/net/wireless/ath/wil6210/sysfs.c +++ b/drivers/net/wireless/ath/wil6210/sysfs.c @@ -253,10 +253,47 @@ out: static DEVICE_ATTR_RW(fst_link_loss); +static ssize_t +snr_thresh_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct wil6210_priv *wil = dev_get_drvdata(dev); + ssize_t len = 0; + + if (wil->snr_thresh.enabled) + len = snprintf(buf, PAGE_SIZE, "omni=%d, direct=%d\n", + wil->snr_thresh.omni, wil->snr_thresh.direct); + + return len; +} + +static ssize_t +snr_thresh_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct wil6210_priv *wil = dev_get_drvdata(dev); + int rc; + short omni, direct; + + /* to disable snr threshold, set both omni and direct to 0 */ + if (sscanf(buf, "%hd %hd", &omni, &direct) != 2) + return -EINVAL; + + rc = wmi_set_snr_thresh(wil, omni, direct); + if (!rc) + rc = count; + + return rc; +} + +static DEVICE_ATTR_RW(snr_thresh); + static struct attribute *wil6210_sysfs_entries[] = { &dev_attr_ftm_txrx_offset.attr, &dev_attr_thermal_throttling.attr, &dev_attr_fst_link_loss.attr, + &dev_attr_snr_thresh.attr, NULL }; diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 213cb58d3802..fddc8bccc524 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -1039,6 +1039,11 @@ struct wil6210_priv { int fw_calib_result; u8 tt_data_set; struct wmi_tt_data tt_data; + struct { + u8 enabled; + short omni; + short direct; + } snr_thresh; struct notifier_block pm_notify; @@ -1440,6 +1445,8 @@ int wmi_link_maintain_cfg_write(struct wil6210_priv *wil, const u8 *addr, bool fst_link_loss); +int wmi_set_snr_thresh(struct wil6210_priv *wil, short omni, short direct); + int wmi_start_sched_scan(struct wil6210_priv *wil, struct cfg80211_sched_scan_request *request); int wmi_stop_sched_scan(struct wil6210_priv *wil); diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 423d273fc740..91b4211cb52d 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -3579,6 +3579,37 @@ out: return rc; } +int wmi_set_snr_thresh(struct wil6210_priv *wil, short omni, short direct) +{ + struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev); + int rc; + struct wmi_set_connect_snr_thr_cmd cmd = { + .enable = true, + .omni_snr_thr = cpu_to_le16(omni), + .direct_snr_thr = cpu_to_le16(direct), + }; + + if (!test_bit(WMI_FW_CAPABILITY_CONNECT_SNR_THR, wil->fw_capabilities)) + return -ENOTSUPP; + + if (omni == 0 && direct == 0) + cmd.enable = false; + + wil_dbg_wmi(wil, "%s snr thresh omni=%d, direct=%d (1/4 dB units)\n", + cmd.enable ? "enable" : "disable", omni, direct); + + rc = wmi_send(wil, WMI_SET_CONNECT_SNR_THR_CMDID, vif->mid, + &cmd, sizeof(cmd)); + if (rc) + return rc; + + wil->snr_thresh.enabled = cmd.enable; + wil->snr_thresh.omni = omni; + wil->snr_thresh.direct = direct; + + return 0; +} + static void wmi_sched_scan_set_ssids(struct wil6210_priv *wil, struct wmi_start_sched_scan_cmd *cmd, diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h index a2f7034489ae..38a829a32489 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.h +++ b/drivers/net/wireless/ath/wil6210/wmi.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: ISC */ /* * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. * Copyright (c) 2006-2012 Wilocity - * - * 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. */ /* @@ -97,6 +86,7 @@ enum wmi_fw_capability { WMI_FW_CAPABILITY_SET_SILENT_RSSI_TABLE = 13, WMI_FW_CAPABILITY_LO_POWER_CALIB_FROM_OTP = 14, WMI_FW_CAPABILITY_PNO = 15, + WMI_FW_CAPABILITY_CONNECT_SNR_THR = 16, WMI_FW_CAPABILITY_CHANNEL_BONDING = 17, WMI_FW_CAPABILITY_REF_CLOCK_CONTROL = 18, WMI_FW_CAPABILITY_AP_SME_OFFLOAD_NONE = 19, From 7ce702f31ba13623d5f12a7d00dd5135667effe4 Mon Sep 17 00:00:00 2001 From: Dedy Lansky Date: Mon, 2 Dec 2019 15:46:31 +0200 Subject: [PATCH 4/5] wil6210: drop RX probe reponses with low SNR FW now reports SNR for RX management frames. Drop probe responses with SNR lower than the configured threshold. Change-Id: Ife1863b07aebe5cb6097420290c0c10b590c2da1 Signed-off-by: Dedy Lansky CRs-Fixed: 2143032 Signed-off-by: Alexei Avshalom Lazar [liord@codeaurora.org: fix merge conflicts] Signed-off-by: Lior David Signed-off-by: Alexei Avshalom Lazar --- drivers/net/wireless/ath/wil6210/wmi.c | 11 ++++++++--- drivers/net/wireless/ath/wil6210/wmi.h | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 91b4211cb52d..51978483f6d5 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -826,7 +826,7 @@ static void wmi_evt_rx_mgmt(struct wil6210_vif *vif, int id, void *d, int len) s32 signal; __le16 fc; u32 d_len; - u16 d_status; + s16 snr; if (flen < 0) { wil_err(wil, "MGMT Rx: short event, len %d\n", len); @@ -848,13 +848,13 @@ static void wmi_evt_rx_mgmt(struct wil6210_vif *vif, int id, void *d, int len) signal = 100 * data->info.rssi; else signal = data->info.sqi; - d_status = le16_to_cpu(data->info.status); + snr = le16_to_cpu(data->info.snr); /* 1/4 dB units */ fc = rx_mgmt_frame->frame_control; wil_dbg_wmi(wil, "MGMT Rx: channel %d MCS %d RSSI %d SQI %d%%\n", data->info.channel, data->info.mcs, data->info.rssi, data->info.sqi); - wil_dbg_wmi(wil, "status 0x%04x len %d fc 0x%04x\n", d_status, d_len, + wil_dbg_wmi(wil, "snr %ddB len %d fc 0x%04x\n", snr / 4, d_len, le16_to_cpu(fc)); wil_dbg_wmi(wil, "qid %d mid %d cid %d\n", data->info.qid, data->info.mid, data->info.cid); @@ -888,6 +888,11 @@ static void wmi_evt_rx_mgmt(struct wil6210_vif *vif, int id, void *d, int len) wil_dbg_wmi(wil, "Capability info : 0x%04x\n", cap); + if (wil->snr_thresh.enabled && snr < wil->snr_thresh.omni) { + wil_dbg_wmi(wil, "snr below threshold. dropping\n"); + return; + } + bss = cfg80211_inform_bss_frame_data(wiphy, &bss_data, rx_mgmt_frame, d_len, GFP_KERNEL); diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h index 38a829a32489..87138708f32b 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.h +++ b/drivers/net/wireless/ath/wil6210/wmi.h @@ -2426,7 +2426,7 @@ struct wmi_rx_mgmt_info { u8 range; u8 sqi; __le16 stype; - __le16 status; + __le16 snr; __le32 len; /* Not resolved when == 0xFFFFFFFF == > Broadcast to all MIDS */ u8 qid; From bc997e94d3effce4d9f20c6e9494ea0201059444 Mon Sep 17 00:00:00 2001 From: Alexei Avshalom Lazar Date: Wed, 28 Feb 2018 11:24:09 +0200 Subject: [PATCH 5/5] wil6210: allow flashless boot when OTP is empty Use random MAC address for non wmi_only firmware. Change-Id: Iab8f0aa494528d12051f103a94c6049187e79505 Signed-off-by: Alexei Avshalom Lazar Signed-off-by: Lior David --- drivers/net/wireless/ath/wil6210/main.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 4ba1495b9aeb..89238bd046e9 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -1425,8 +1425,14 @@ static int wil_get_otp_info(struct wil6210_priv *wil) } if (!is_valid_ether_addr(mac)) { - wil_err(wil, "Invalid MAC %pM\n", mac); - return -EINVAL; + u8 dummy_mac[ETH_ALEN] = { + 0x00, 0xde, 0xad, 0x12, 0x34, 0x56, + }; + if (!test_bit(WMI_FW_CAPABILITY_WMI_ONLY, wil->fw_capabilities)) + get_random_bytes(dummy_mac + 3, 3); + wil_err(wil, "Invalid MAC %pM, using random %pM\n", mac, + dummy_mac); + ether_addr_copy(mac, dummy_mac); } ether_addr_copy(ndev->perm_addr, mac);