diff options
Diffstat (limited to 'drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c')
| -rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c | 307 |
1 files changed, 219 insertions, 88 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c index 0b6c32098b5a..83f6e508a094 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c @@ -1,67 +1,28 @@ -/****************************************************************************** - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2015 - 2017 Intel Deutschland GmbH - * Copyright (C) 2018 - 2019 Intel Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * The full GNU General Public License is included in this distribution - * in the file called COPYING. - * - * Contact Information: - * Intel Linux Wireless <linuxwifi@intel.com> - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2015 - 2017 Intel Deutschland GmbH - * Copyright (C) 2018 - 2019 Intel Corporation - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - *****************************************************************************/ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* + * Copyright (C) 2015-2017 Intel Deutschland GmbH + * Copyright (C) 2018-2024 Intel Corporation + */ #include <net/cfg80211.h> #include <linux/etherdevice.h> #include "mvm.h" #include "constants.h" +struct iwl_mvm_pasn_sta { + struct list_head list; + struct iwl_mvm_int_sta int_sta; + u8 addr[ETH_ALEN]; + + /* must be last as it followed by buffer holding the key */ + struct ieee80211_key_conf keyconf; +}; + +struct iwl_mvm_pasn_hltk_data { + u8 *addr; + u8 cipher; + u8 *hltk; +}; + static int iwl_mvm_ftm_responder_set_bw_v1(struct cfg80211_chan_def *chandef, u8 *bw, u8 *ctrl_ch_position) { @@ -81,15 +42,15 @@ static int iwl_mvm_ftm_responder_set_bw_v1(struct cfg80211_chan_def *chandef, *ctrl_ch_position = iwl_mvm_get_ctrl_pos(chandef); break; default: - return -ENOTSUPP; + return -EOPNOTSUPP; } return 0; } static int iwl_mvm_ftm_responder_set_bw_v2(struct cfg80211_chan_def *chandef, - u8 *format_bw, - u8 *ctrl_ch_position) + u8 *format_bw, u8 *ctrl_ch_position, + u8 cmd_ver) { switch (chandef->width) { case NL80211_CHAN_WIDTH_20_NOHT: @@ -110,21 +71,49 @@ static int iwl_mvm_ftm_responder_set_bw_v2(struct cfg80211_chan_def *chandef, *format_bw |= IWL_LOCATION_BW_80MHZ << LOCATION_BW_POS; *ctrl_ch_position = iwl_mvm_get_ctrl_pos(chandef); break; + case NL80211_CHAN_WIDTH_160: + if (cmd_ver >= 9) { + *format_bw = IWL_LOCATION_FRAME_FORMAT_HE; + *format_bw |= IWL_LOCATION_BW_160MHZ << LOCATION_BW_POS; + *ctrl_ch_position = iwl_mvm_get_ctrl_pos(chandef); + break; + } + fallthrough; default: - return -ENOTSUPP; + return -EOPNOTSUPP; } return 0; } +static void +iwl_mvm_ftm_responder_set_ndp(struct iwl_mvm *mvm, + struct iwl_tof_responder_config_cmd *cmd) +{ + /* Up to 2 R2I STS are allowed on the responder */ + u32 r2i_max_sts = IWL_MVM_FTM_R2I_MAX_STS < 2 ? + IWL_MVM_FTM_R2I_MAX_STS : 1; + + cmd->r2i_ndp_params = IWL_MVM_FTM_R2I_MAX_REP | + (r2i_max_sts << IWL_RESPONDER_STS_POS) | + (IWL_MVM_FTM_R2I_MAX_TOTAL_LTF << IWL_RESPONDER_TOTAL_LTF_POS); + cmd->i2r_ndp_params = IWL_MVM_FTM_I2R_MAX_REP | + (IWL_MVM_FTM_I2R_MAX_STS << IWL_RESPONDER_STS_POS) | + (IWL_MVM_FTM_I2R_MAX_TOTAL_LTF << IWL_RESPONDER_TOTAL_LTF_POS); + cmd->cmd_valid_fields |= + cpu_to_le32(IWL_TOF_RESPONDER_CMD_VALID_NDP_PARAMS); +} + static int iwl_mvm_ftm_responder_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - struct cfg80211_chan_def *chandef) + struct cfg80211_chan_def *chandef, + struct ieee80211_bss_conf *link_conf) { + u32 cmd_id = WIDE_ID(LOCATION_GROUP, TOF_RESPONDER_CONFIG_CMD); struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); /* - * The command structure is the same for versions 6 and 7, (only the + * The command structure is the same for versions 6, 7 and 8 (only the * field interpretation is different), so the same struct can be use * for all cases. */ @@ -134,17 +123,42 @@ iwl_mvm_ftm_responder_cmd(struct iwl_mvm *mvm, cpu_to_le32(IWL_TOF_RESPONDER_CMD_VALID_CHAN_INFO | IWL_TOF_RESPONDER_CMD_VALID_BSSID | IWL_TOF_RESPONDER_CMD_VALID_STA_ID), - .sta_id = mvmvif->bcast_sta.sta_id, + .sta_id = mvmvif->link[link_conf->link_id]->bcast_sta.sta_id, }; - u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, LOCATION_GROUP, - TOF_RESPONDER_CONFIG_CMD); + u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, 6); int err; + int cmd_size; lockdep_assert_held(&mvm->mutex); - if (cmd_ver == 7) + if (cmd_ver >= 10) { + cmd.band = + iwl_mvm_phy_band_from_nl80211(chandef->chan->band); + } + + /* Use a default of bss_color=1 for now */ + if (cmd_ver >= 9) { + cmd.cmd_valid_fields |= + cpu_to_le32(IWL_TOF_RESPONDER_CMD_VALID_BSS_COLOR | + IWL_TOF_RESPONDER_CMD_VALID_MIN_MAX_TIME_BETWEEN_MSR); + cmd.bss_color = 1; + cmd.min_time_between_msr = + cpu_to_le16(IWL_MVM_FTM_NON_TB_MIN_TIME_BETWEEN_MSR); + cmd.max_time_between_msr = + cpu_to_le16(IWL_MVM_FTM_NON_TB_MAX_TIME_BETWEEN_MSR); + cmd_size = sizeof(struct iwl_tof_responder_config_cmd_v9); + } else { + /* All versions up to version 8 have the same size */ + cmd_size = sizeof(struct iwl_tof_responder_config_cmd_v8); + } + + if (cmd_ver >= 8) + iwl_mvm_ftm_responder_set_ndp(mvm, (void *)&cmd); + + if (cmd_ver >= 7) err = iwl_mvm_ftm_responder_set_bw_v2(chandef, &cmd.format_bw, - &cmd.ctrl_ch_position); + &cmd.ctrl_ch_position, + cmd_ver); else err = iwl_mvm_ftm_responder_set_bw_v1(chandef, &cmd.format_bw, &cmd.ctrl_ch_position); @@ -156,24 +170,21 @@ iwl_mvm_ftm_responder_cmd(struct iwl_mvm *mvm, memcpy(cmd.bssid, vif->addr, ETH_ALEN); - return iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(TOF_RESPONDER_CONFIG_CMD, - LOCATION_GROUP, 0), - 0, sizeof(cmd), &cmd); + return iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, cmd_size, &cmd); } static int -iwl_mvm_ftm_responder_dyn_cfg_cmd(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - struct ieee80211_ftm_responder_params *params) +iwl_mvm_ftm_responder_dyn_cfg_v2(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct ieee80211_ftm_responder_params *params) { - struct iwl_tof_responder_dyn_config_cmd cmd = { + struct iwl_tof_responder_dyn_config_cmd_v2 cmd = { .lci_len = cpu_to_le32(params->lci_len + 2), .civic_len = cpu_to_le32(params->civicloc_len + 2), }; u8 data[IWL_LCI_CIVIC_IE_MAX_SIZE] = {0}; struct iwl_host_cmd hcmd = { - .id = iwl_cmd_id(TOF_RESPONDER_DYN_CONFIG_CMD, - LOCATION_GROUP, 0), + .id = WIDE_ID(LOCATION_GROUP, TOF_RESPONDER_DYN_CONFIG_CMD), .data[0] = &cmd, .len[0] = sizeof(cmd), .data[1] = &data, @@ -207,7 +218,114 @@ iwl_mvm_ftm_responder_dyn_cfg_cmd(struct iwl_mvm *mvm, return iwl_mvm_send_cmd(mvm, &hcmd); } -int iwl_mvm_ftm_start_responder(struct iwl_mvm *mvm, struct ieee80211_vif *vif) +static int +iwl_mvm_ftm_responder_dyn_cfg_v3(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct ieee80211_ftm_responder_params *params, + struct iwl_mvm_pasn_hltk_data *hltk_data) +{ + struct iwl_tof_responder_dyn_config_cmd cmd; + struct iwl_host_cmd hcmd = { + .id = WIDE_ID(LOCATION_GROUP, TOF_RESPONDER_DYN_CONFIG_CMD), + .data[0] = &cmd, + .len[0] = sizeof(cmd), + /* may not be able to DMA from stack */ + .dataflags[0] = IWL_HCMD_DFL_DUP, + }; + + lockdep_assert_held(&mvm->mutex); + + cmd.valid_flags = 0; + + if (params) { + if (params->lci_len + 2 > sizeof(cmd.lci_buf) || + params->civicloc_len + 2 > sizeof(cmd.civic_buf)) { + IWL_ERR(mvm, + "LCI/civic data too big (lci=%zd, civic=%zd)\n", + params->lci_len, params->civicloc_len); + return -ENOBUFS; + } + + cmd.lci_buf[0] = WLAN_EID_MEASURE_REPORT; + cmd.lci_buf[1] = params->lci_len; + memcpy(cmd.lci_buf + 2, params->lci, params->lci_len); + cmd.lci_len = params->lci_len + 2; + + cmd.civic_buf[0] = WLAN_EID_MEASURE_REPORT; + cmd.civic_buf[1] = params->civicloc_len; + memcpy(cmd.civic_buf + 2, params->civicloc, + params->civicloc_len); + cmd.civic_len = params->civicloc_len + 2; + + cmd.valid_flags |= IWL_RESPONDER_DYN_CFG_VALID_LCI | + IWL_RESPONDER_DYN_CFG_VALID_CIVIC; + } + + if (hltk_data) { + if (hltk_data->cipher > IWL_LOCATION_CIPHER_GCMP_256) { + IWL_ERR(mvm, "invalid cipher: %u\n", + hltk_data->cipher); + return -EINVAL; + } + + cmd.cipher = hltk_data->cipher; + memcpy(cmd.addr, hltk_data->addr, sizeof(cmd.addr)); + memcpy(cmd.hltk_buf, hltk_data->hltk, sizeof(cmd.hltk_buf)); + cmd.valid_flags |= IWL_RESPONDER_DYN_CFG_VALID_PASN_STA; + } + + return iwl_mvm_send_cmd(mvm, &hcmd); +} + +static int +iwl_mvm_ftm_responder_dyn_cfg_cmd(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct ieee80211_ftm_responder_params *params) +{ + int ret; + u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, + WIDE_ID(LOCATION_GROUP, TOF_RESPONDER_DYN_CONFIG_CMD), + 2); + + switch (cmd_ver) { + case 2: + ret = iwl_mvm_ftm_responder_dyn_cfg_v2(mvm, vif, + params); + break; + case 3: + ret = iwl_mvm_ftm_responder_dyn_cfg_v3(mvm, vif, + params, NULL); + break; + default: + IWL_ERR(mvm, "Unsupported DYN_CONFIG_CMD version %u\n", + cmd_ver); + ret = -EOPNOTSUPP; + } + + return ret; +} + +static void iwl_mvm_resp_del_pasn_sta(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct iwl_mvm_pasn_sta *sta) +{ + list_del(&sta->list); + + if (sta->keyconf.keylen) + iwl_mvm_sec_key_del_pasn(mvm, vif, BIT(sta->int_sta.sta_id), + &sta->keyconf); + + if (iwl_mvm_has_mld_api(mvm->fw)) + iwl_mvm_mld_rm_sta_id(mvm, sta->int_sta.sta_id); + else + iwl_mvm_rm_sta_id(mvm, vif, sta->int_sta.sta_id); + + iwl_mvm_dealloc_int_sta(mvm, &sta->int_sta); + kfree(sta); +} + +int iwl_mvm_ftm_start_responder(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct ieee80211_ftm_responder_params *params; @@ -216,11 +334,11 @@ int iwl_mvm_ftm_start_responder(struct iwl_mvm *mvm, struct ieee80211_vif *vif) struct iwl_mvm_phy_ctxt *phy_ctxt; int ret; - params = vif->bss_conf.ftmr_params; + params = bss_conf->ftmr_params; lockdep_assert_held(&mvm->mutex); - if (WARN_ON_ONCE(!vif->bss_conf.ftm_responder)) + if (WARN_ON_ONCE(!bss_conf->ftm_responder)) return -EINVAL; if (vif->p2p || vif->type != NL80211_IFTYPE_AP || @@ -230,7 +348,7 @@ int iwl_mvm_ftm_start_responder(struct iwl_mvm *mvm, struct ieee80211_vif *vif) } rcu_read_lock(); - pctx = rcu_dereference(vif->chanctx_conf); + pctx = rcu_dereference(bss_conf->chanctx_conf); /* Copy the ctx to unlock the rcu and send the phy ctxt. We don't care * about changes in the ctx after releasing the lock because the driver * is still protected by the mutex. */ @@ -239,13 +357,13 @@ int iwl_mvm_ftm_start_responder(struct iwl_mvm *mvm, struct ieee80211_vif *vif) rcu_read_unlock(); phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id]; - ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx.def, + ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx.def, &ctx.ap, ctx.rx_chains_static, ctx.rx_chains_dynamic); if (ret) return ret; - ret = iwl_mvm_ftm_responder_cmd(mvm, vif, &ctx.def); + ret = iwl_mvm_ftm_responder_cmd(mvm, vif, &ctx.def, bss_conf); if (ret) return ret; @@ -255,13 +373,26 @@ int iwl_mvm_ftm_start_responder(struct iwl_mvm *mvm, struct ieee80211_vif *vif) return ret; } +void iwl_mvm_ftm_responder_clear(struct iwl_mvm *mvm, + struct ieee80211_vif *vif) +{ + struct iwl_mvm_pasn_sta *sta, *prev; + + lockdep_assert_held(&mvm->mutex); + + list_for_each_entry_safe(sta, prev, &mvm->resp_pasn_list, list) + iwl_mvm_resp_del_pasn_sta(mvm, vif, sta); +} + void iwl_mvm_ftm_restart_responder(struct iwl_mvm *mvm, - struct ieee80211_vif *vif) + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf) { - if (!vif->bss_conf.ftm_responder) + if (!bss_conf->ftm_responder) return; - iwl_mvm_ftm_start_responder(mvm, vif); + iwl_mvm_ftm_responder_clear(mvm, vif); + iwl_mvm_ftm_start_responder(mvm, vif, bss_conf); } void iwl_mvm_ftm_responder_stats(struct iwl_mvm *mvm, |
