18c2ecf20Sopenharmony_ci/****************************************************************************** 28c2ecf20Sopenharmony_ci * 38c2ecf20Sopenharmony_ci * This file is provided under a dual BSD/GPLv2 license. When using or 48c2ecf20Sopenharmony_ci * redistributing this file, you may do so under either license. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * GPL LICENSE SUMMARY 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Copyright(c) 2015 - 2017 Intel Deutschland GmbH 98c2ecf20Sopenharmony_ci * Copyright (C) 2018 - 2020 Intel Corporation 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 128c2ecf20Sopenharmony_ci * it under the terms of version 2 of the GNU General Public License as 138c2ecf20Sopenharmony_ci * published by the Free Software Foundation. 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * This program is distributed in the hope that it will be useful, but 168c2ecf20Sopenharmony_ci * WITHOUT ANY WARRANTY; without even the implied warranty of 178c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 188c2ecf20Sopenharmony_ci * General Public License for more details. 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * The full GNU General Public License is included in this distribution 218c2ecf20Sopenharmony_ci * in the file called COPYING. 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * Contact Information: 248c2ecf20Sopenharmony_ci * Intel Linux Wireless <linuxwifi@intel.com> 258c2ecf20Sopenharmony_ci * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 268c2ecf20Sopenharmony_ci * 278c2ecf20Sopenharmony_ci * BSD LICENSE 288c2ecf20Sopenharmony_ci * 298c2ecf20Sopenharmony_ci * Copyright(c) 2015 - 2017 Intel Deutschland GmbH 308c2ecf20Sopenharmony_ci * Copyright (C) 2018 - 2020 Intel Corporation 318c2ecf20Sopenharmony_ci * All rights reserved. 328c2ecf20Sopenharmony_ci * 338c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 348c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions 358c2ecf20Sopenharmony_ci * are met: 368c2ecf20Sopenharmony_ci * 378c2ecf20Sopenharmony_ci * * Redistributions of source code must retain the above copyright 388c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 398c2ecf20Sopenharmony_ci * * Redistributions in binary form must reproduce the above copyright 408c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer in 418c2ecf20Sopenharmony_ci * the documentation and/or other materials provided with the 428c2ecf20Sopenharmony_ci * distribution. 438c2ecf20Sopenharmony_ci * * Neither the name Intel Corporation nor the names of its 448c2ecf20Sopenharmony_ci * contributors may be used to endorse or promote products derived 458c2ecf20Sopenharmony_ci * from this software without specific prior written permission. 468c2ecf20Sopenharmony_ci * 478c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 488c2ecf20Sopenharmony_ci * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 498c2ecf20Sopenharmony_ci * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 508c2ecf20Sopenharmony_ci * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 518c2ecf20Sopenharmony_ci * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 528c2ecf20Sopenharmony_ci * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 538c2ecf20Sopenharmony_ci * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 548c2ecf20Sopenharmony_ci * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 558c2ecf20Sopenharmony_ci * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 568c2ecf20Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 578c2ecf20Sopenharmony_ci * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 588c2ecf20Sopenharmony_ci * 598c2ecf20Sopenharmony_ci *****************************************************************************/ 608c2ecf20Sopenharmony_ci#include <net/cfg80211.h> 618c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 628c2ecf20Sopenharmony_ci#include "mvm.h" 638c2ecf20Sopenharmony_ci#include "constants.h" 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistruct iwl_mvm_pasn_sta { 668c2ecf20Sopenharmony_ci struct list_head list; 678c2ecf20Sopenharmony_ci struct iwl_mvm_int_sta int_sta; 688c2ecf20Sopenharmony_ci u8 addr[ETH_ALEN]; 698c2ecf20Sopenharmony_ci}; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistruct iwl_mvm_pasn_hltk_data { 728c2ecf20Sopenharmony_ci u8 *addr; 738c2ecf20Sopenharmony_ci u8 cipher; 748c2ecf20Sopenharmony_ci u8 *hltk; 758c2ecf20Sopenharmony_ci}; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic int iwl_mvm_ftm_responder_set_bw_v1(struct cfg80211_chan_def *chandef, 788c2ecf20Sopenharmony_ci u8 *bw, u8 *ctrl_ch_position) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci switch (chandef->width) { 818c2ecf20Sopenharmony_ci case NL80211_CHAN_WIDTH_20_NOHT: 828c2ecf20Sopenharmony_ci *bw = IWL_TOF_BW_20_LEGACY; 838c2ecf20Sopenharmony_ci break; 848c2ecf20Sopenharmony_ci case NL80211_CHAN_WIDTH_20: 858c2ecf20Sopenharmony_ci *bw = IWL_TOF_BW_20_HT; 868c2ecf20Sopenharmony_ci break; 878c2ecf20Sopenharmony_ci case NL80211_CHAN_WIDTH_40: 888c2ecf20Sopenharmony_ci *bw = IWL_TOF_BW_40; 898c2ecf20Sopenharmony_ci *ctrl_ch_position = iwl_mvm_get_ctrl_pos(chandef); 908c2ecf20Sopenharmony_ci break; 918c2ecf20Sopenharmony_ci case NL80211_CHAN_WIDTH_80: 928c2ecf20Sopenharmony_ci *bw = IWL_TOF_BW_80; 938c2ecf20Sopenharmony_ci *ctrl_ch_position = iwl_mvm_get_ctrl_pos(chandef); 948c2ecf20Sopenharmony_ci break; 958c2ecf20Sopenharmony_ci default: 968c2ecf20Sopenharmony_ci return -ENOTSUPP; 978c2ecf20Sopenharmony_ci } 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci return 0; 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cistatic int iwl_mvm_ftm_responder_set_bw_v2(struct cfg80211_chan_def *chandef, 1038c2ecf20Sopenharmony_ci u8 *format_bw, 1048c2ecf20Sopenharmony_ci u8 *ctrl_ch_position) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci switch (chandef->width) { 1078c2ecf20Sopenharmony_ci case NL80211_CHAN_WIDTH_20_NOHT: 1088c2ecf20Sopenharmony_ci *format_bw = IWL_LOCATION_FRAME_FORMAT_LEGACY; 1098c2ecf20Sopenharmony_ci *format_bw |= IWL_LOCATION_BW_20MHZ << LOCATION_BW_POS; 1108c2ecf20Sopenharmony_ci break; 1118c2ecf20Sopenharmony_ci case NL80211_CHAN_WIDTH_20: 1128c2ecf20Sopenharmony_ci *format_bw = IWL_LOCATION_FRAME_FORMAT_HT; 1138c2ecf20Sopenharmony_ci *format_bw |= IWL_LOCATION_BW_20MHZ << LOCATION_BW_POS; 1148c2ecf20Sopenharmony_ci break; 1158c2ecf20Sopenharmony_ci case NL80211_CHAN_WIDTH_40: 1168c2ecf20Sopenharmony_ci *format_bw = IWL_LOCATION_FRAME_FORMAT_HT; 1178c2ecf20Sopenharmony_ci *format_bw |= IWL_LOCATION_BW_40MHZ << LOCATION_BW_POS; 1188c2ecf20Sopenharmony_ci *ctrl_ch_position = iwl_mvm_get_ctrl_pos(chandef); 1198c2ecf20Sopenharmony_ci break; 1208c2ecf20Sopenharmony_ci case NL80211_CHAN_WIDTH_80: 1218c2ecf20Sopenharmony_ci *format_bw = IWL_LOCATION_FRAME_FORMAT_VHT; 1228c2ecf20Sopenharmony_ci *format_bw |= IWL_LOCATION_BW_80MHZ << LOCATION_BW_POS; 1238c2ecf20Sopenharmony_ci *ctrl_ch_position = iwl_mvm_get_ctrl_pos(chandef); 1248c2ecf20Sopenharmony_ci break; 1258c2ecf20Sopenharmony_ci default: 1268c2ecf20Sopenharmony_ci return -ENOTSUPP; 1278c2ecf20Sopenharmony_ci } 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci return 0; 1308c2ecf20Sopenharmony_ci} 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cistatic int 1338c2ecf20Sopenharmony_ciiwl_mvm_ftm_responder_cmd(struct iwl_mvm *mvm, 1348c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, 1358c2ecf20Sopenharmony_ci struct cfg80211_chan_def *chandef) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 1388c2ecf20Sopenharmony_ci /* 1398c2ecf20Sopenharmony_ci * The command structure is the same for versions 6 and 7, (only the 1408c2ecf20Sopenharmony_ci * field interpretation is different), so the same struct can be use 1418c2ecf20Sopenharmony_ci * for all cases. 1428c2ecf20Sopenharmony_ci */ 1438c2ecf20Sopenharmony_ci struct iwl_tof_responder_config_cmd cmd = { 1448c2ecf20Sopenharmony_ci .channel_num = chandef->chan->hw_value, 1458c2ecf20Sopenharmony_ci .cmd_valid_fields = 1468c2ecf20Sopenharmony_ci cpu_to_le32(IWL_TOF_RESPONDER_CMD_VALID_CHAN_INFO | 1478c2ecf20Sopenharmony_ci IWL_TOF_RESPONDER_CMD_VALID_BSSID | 1488c2ecf20Sopenharmony_ci IWL_TOF_RESPONDER_CMD_VALID_STA_ID), 1498c2ecf20Sopenharmony_ci .sta_id = mvmvif->bcast_sta.sta_id, 1508c2ecf20Sopenharmony_ci }; 1518c2ecf20Sopenharmony_ci u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, LOCATION_GROUP, 1528c2ecf20Sopenharmony_ci TOF_RESPONDER_CONFIG_CMD, 6); 1538c2ecf20Sopenharmony_ci int err; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci lockdep_assert_held(&mvm->mutex); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci if (cmd_ver == 7) 1588c2ecf20Sopenharmony_ci err = iwl_mvm_ftm_responder_set_bw_v2(chandef, &cmd.format_bw, 1598c2ecf20Sopenharmony_ci &cmd.ctrl_ch_position); 1608c2ecf20Sopenharmony_ci else 1618c2ecf20Sopenharmony_ci err = iwl_mvm_ftm_responder_set_bw_v1(chandef, &cmd.format_bw, 1628c2ecf20Sopenharmony_ci &cmd.ctrl_ch_position); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci if (err) { 1658c2ecf20Sopenharmony_ci IWL_ERR(mvm, "Failed to set responder bandwidth\n"); 1668c2ecf20Sopenharmony_ci return err; 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci memcpy(cmd.bssid, vif->addr, ETH_ALEN); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci return iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(TOF_RESPONDER_CONFIG_CMD, 1728c2ecf20Sopenharmony_ci LOCATION_GROUP, 0), 1738c2ecf20Sopenharmony_ci 0, sizeof(cmd), &cmd); 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cistatic int 1778c2ecf20Sopenharmony_ciiwl_mvm_ftm_responder_dyn_cfg_v2(struct iwl_mvm *mvm, 1788c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, 1798c2ecf20Sopenharmony_ci struct ieee80211_ftm_responder_params *params) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci struct iwl_tof_responder_dyn_config_cmd_v2 cmd = { 1828c2ecf20Sopenharmony_ci .lci_len = cpu_to_le32(params->lci_len + 2), 1838c2ecf20Sopenharmony_ci .civic_len = cpu_to_le32(params->civicloc_len + 2), 1848c2ecf20Sopenharmony_ci }; 1858c2ecf20Sopenharmony_ci u8 data[IWL_LCI_CIVIC_IE_MAX_SIZE] = {0}; 1868c2ecf20Sopenharmony_ci struct iwl_host_cmd hcmd = { 1878c2ecf20Sopenharmony_ci .id = iwl_cmd_id(TOF_RESPONDER_DYN_CONFIG_CMD, 1888c2ecf20Sopenharmony_ci LOCATION_GROUP, 0), 1898c2ecf20Sopenharmony_ci .data[0] = &cmd, 1908c2ecf20Sopenharmony_ci .len[0] = sizeof(cmd), 1918c2ecf20Sopenharmony_ci .data[1] = &data, 1928c2ecf20Sopenharmony_ci /* .len[1] set later */ 1938c2ecf20Sopenharmony_ci /* may not be able to DMA from stack */ 1948c2ecf20Sopenharmony_ci .dataflags[1] = IWL_HCMD_DFL_DUP, 1958c2ecf20Sopenharmony_ci }; 1968c2ecf20Sopenharmony_ci u32 aligned_lci_len = ALIGN(params->lci_len + 2, 4); 1978c2ecf20Sopenharmony_ci u32 aligned_civicloc_len = ALIGN(params->civicloc_len + 2, 4); 1988c2ecf20Sopenharmony_ci u8 *pos = data; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci lockdep_assert_held(&mvm->mutex); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci if (aligned_lci_len + aligned_civicloc_len > sizeof(data)) { 2038c2ecf20Sopenharmony_ci IWL_ERR(mvm, "LCI/civicloc data too big (%zd + %zd)\n", 2048c2ecf20Sopenharmony_ci params->lci_len, params->civicloc_len); 2058c2ecf20Sopenharmony_ci return -ENOBUFS; 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci pos[0] = WLAN_EID_MEASURE_REPORT; 2098c2ecf20Sopenharmony_ci pos[1] = params->lci_len; 2108c2ecf20Sopenharmony_ci memcpy(pos + 2, params->lci, params->lci_len); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci pos += aligned_lci_len; 2138c2ecf20Sopenharmony_ci pos[0] = WLAN_EID_MEASURE_REPORT; 2148c2ecf20Sopenharmony_ci pos[1] = params->civicloc_len; 2158c2ecf20Sopenharmony_ci memcpy(pos + 2, params->civicloc, params->civicloc_len); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci hcmd.len[1] = aligned_lci_len + aligned_civicloc_len; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci return iwl_mvm_send_cmd(mvm, &hcmd); 2208c2ecf20Sopenharmony_ci} 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_cistatic int 2238c2ecf20Sopenharmony_ciiwl_mvm_ftm_responder_dyn_cfg_v3(struct iwl_mvm *mvm, 2248c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, 2258c2ecf20Sopenharmony_ci struct ieee80211_ftm_responder_params *params, 2268c2ecf20Sopenharmony_ci struct iwl_mvm_pasn_hltk_data *hltk_data) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci struct iwl_tof_responder_dyn_config_cmd cmd; 2298c2ecf20Sopenharmony_ci struct iwl_host_cmd hcmd = { 2308c2ecf20Sopenharmony_ci .id = iwl_cmd_id(TOF_RESPONDER_DYN_CONFIG_CMD, 2318c2ecf20Sopenharmony_ci LOCATION_GROUP, 0), 2328c2ecf20Sopenharmony_ci .data[0] = &cmd, 2338c2ecf20Sopenharmony_ci .len[0] = sizeof(cmd), 2348c2ecf20Sopenharmony_ci /* may not be able to DMA from stack */ 2358c2ecf20Sopenharmony_ci .dataflags[0] = IWL_HCMD_DFL_DUP, 2368c2ecf20Sopenharmony_ci }; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci lockdep_assert_held(&mvm->mutex); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci cmd.valid_flags = 0; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci if (params) { 2438c2ecf20Sopenharmony_ci if (params->lci_len + 2 > sizeof(cmd.lci_buf) || 2448c2ecf20Sopenharmony_ci params->civicloc_len + 2 > sizeof(cmd.civic_buf)) { 2458c2ecf20Sopenharmony_ci IWL_ERR(mvm, 2468c2ecf20Sopenharmony_ci "LCI/civic data too big (lci=%zd, civic=%zd)\n", 2478c2ecf20Sopenharmony_ci params->lci_len, params->civicloc_len); 2488c2ecf20Sopenharmony_ci return -ENOBUFS; 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci cmd.lci_buf[0] = WLAN_EID_MEASURE_REPORT; 2528c2ecf20Sopenharmony_ci cmd.lci_buf[1] = params->lci_len; 2538c2ecf20Sopenharmony_ci memcpy(cmd.lci_buf + 2, params->lci, params->lci_len); 2548c2ecf20Sopenharmony_ci cmd.lci_len = params->lci_len + 2; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci cmd.civic_buf[0] = WLAN_EID_MEASURE_REPORT; 2578c2ecf20Sopenharmony_ci cmd.civic_buf[1] = params->civicloc_len; 2588c2ecf20Sopenharmony_ci memcpy(cmd.civic_buf + 2, params->civicloc, 2598c2ecf20Sopenharmony_ci params->civicloc_len); 2608c2ecf20Sopenharmony_ci cmd.civic_len = params->civicloc_len + 2; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci cmd.valid_flags |= IWL_RESPONDER_DYN_CFG_VALID_LCI | 2638c2ecf20Sopenharmony_ci IWL_RESPONDER_DYN_CFG_VALID_CIVIC; 2648c2ecf20Sopenharmony_ci } 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci if (hltk_data) { 2678c2ecf20Sopenharmony_ci if (hltk_data->cipher > IWL_LOCATION_CIPHER_GCMP_256) { 2688c2ecf20Sopenharmony_ci IWL_ERR(mvm, "invalid cipher: %u\n", 2698c2ecf20Sopenharmony_ci hltk_data->cipher); 2708c2ecf20Sopenharmony_ci return -EINVAL; 2718c2ecf20Sopenharmony_ci } 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci cmd.cipher = hltk_data->cipher; 2748c2ecf20Sopenharmony_ci memcpy(cmd.addr, hltk_data->addr, sizeof(cmd.addr)); 2758c2ecf20Sopenharmony_ci memcpy(cmd.hltk_buf, hltk_data->hltk, sizeof(cmd.hltk_buf)); 2768c2ecf20Sopenharmony_ci cmd.valid_flags |= IWL_RESPONDER_DYN_CFG_VALID_PASN_STA; 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci return iwl_mvm_send_cmd(mvm, &hcmd); 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_cistatic int 2838c2ecf20Sopenharmony_ciiwl_mvm_ftm_responder_dyn_cfg_cmd(struct iwl_mvm *mvm, 2848c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, 2858c2ecf20Sopenharmony_ci struct ieee80211_ftm_responder_params *params) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci int ret; 2888c2ecf20Sopenharmony_ci u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, LOCATION_GROUP, 2898c2ecf20Sopenharmony_ci TOF_RESPONDER_DYN_CONFIG_CMD, 2); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci switch (cmd_ver) { 2928c2ecf20Sopenharmony_ci case 2: 2938c2ecf20Sopenharmony_ci ret = iwl_mvm_ftm_responder_dyn_cfg_v2(mvm, vif, 2948c2ecf20Sopenharmony_ci params); 2958c2ecf20Sopenharmony_ci break; 2968c2ecf20Sopenharmony_ci case 3: 2978c2ecf20Sopenharmony_ci ret = iwl_mvm_ftm_responder_dyn_cfg_v3(mvm, vif, 2988c2ecf20Sopenharmony_ci params, NULL); 2998c2ecf20Sopenharmony_ci break; 3008c2ecf20Sopenharmony_ci default: 3018c2ecf20Sopenharmony_ci IWL_ERR(mvm, "Unsupported DYN_CONFIG_CMD version %u\n", 3028c2ecf20Sopenharmony_ci cmd_ver); 3038c2ecf20Sopenharmony_ci ret = -ENOTSUPP; 3048c2ecf20Sopenharmony_ci } 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci return ret; 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_cistatic void iwl_mvm_resp_del_pasn_sta(struct iwl_mvm *mvm, 3108c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, 3118c2ecf20Sopenharmony_ci struct iwl_mvm_pasn_sta *sta) 3128c2ecf20Sopenharmony_ci{ 3138c2ecf20Sopenharmony_ci list_del(&sta->list); 3148c2ecf20Sopenharmony_ci iwl_mvm_rm_sta_id(mvm, vif, sta->int_sta.sta_id); 3158c2ecf20Sopenharmony_ci iwl_mvm_dealloc_int_sta(mvm, &sta->int_sta); 3168c2ecf20Sopenharmony_ci kfree(sta); 3178c2ecf20Sopenharmony_ci} 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ciint iwl_mvm_ftm_respoder_add_pasn_sta(struct iwl_mvm *mvm, 3208c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, 3218c2ecf20Sopenharmony_ci u8 *addr, u32 cipher, u8 *tk, u32 tk_len, 3228c2ecf20Sopenharmony_ci u8 *hltk, u32 hltk_len) 3238c2ecf20Sopenharmony_ci{ 3248c2ecf20Sopenharmony_ci int ret; 3258c2ecf20Sopenharmony_ci struct iwl_mvm_pasn_sta *sta = NULL; 3268c2ecf20Sopenharmony_ci struct iwl_mvm_pasn_hltk_data hltk_data = { 3278c2ecf20Sopenharmony_ci .addr = addr, 3288c2ecf20Sopenharmony_ci .hltk = hltk, 3298c2ecf20Sopenharmony_ci }; 3308c2ecf20Sopenharmony_ci u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, LOCATION_GROUP, 3318c2ecf20Sopenharmony_ci TOF_RESPONDER_DYN_CONFIG_CMD, 2); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci lockdep_assert_held(&mvm->mutex); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci if (cmd_ver < 3) { 3368c2ecf20Sopenharmony_ci IWL_ERR(mvm, "Adding PASN station not supported by FW\n"); 3378c2ecf20Sopenharmony_ci return -ENOTSUPP; 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci hltk_data.cipher = iwl_mvm_cipher_to_location_cipher(cipher); 3418c2ecf20Sopenharmony_ci if (hltk_data.cipher == IWL_LOCATION_CIPHER_INVALID) { 3428c2ecf20Sopenharmony_ci IWL_ERR(mvm, "invalid cipher: %u\n", cipher); 3438c2ecf20Sopenharmony_ci return -EINVAL; 3448c2ecf20Sopenharmony_ci } 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci if (tk && tk_len) { 3478c2ecf20Sopenharmony_ci sta = kzalloc(sizeof(*sta), GFP_KERNEL); 3488c2ecf20Sopenharmony_ci if (!sta) 3498c2ecf20Sopenharmony_ci return -ENOBUFS; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci ret = iwl_mvm_add_pasn_sta(mvm, vif, &sta->int_sta, addr, 3528c2ecf20Sopenharmony_ci cipher, tk, tk_len); 3538c2ecf20Sopenharmony_ci if (ret) { 3548c2ecf20Sopenharmony_ci kfree(sta); 3558c2ecf20Sopenharmony_ci return ret; 3568c2ecf20Sopenharmony_ci } 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci memcpy(sta->addr, addr, ETH_ALEN); 3598c2ecf20Sopenharmony_ci list_add_tail(&sta->list, &mvm->resp_pasn_list); 3608c2ecf20Sopenharmony_ci } 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci ret = iwl_mvm_ftm_responder_dyn_cfg_v3(mvm, vif, NULL, &hltk_data); 3638c2ecf20Sopenharmony_ci if (ret && sta) 3648c2ecf20Sopenharmony_ci iwl_mvm_resp_del_pasn_sta(mvm, vif, sta); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci return ret; 3678c2ecf20Sopenharmony_ci} 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ciint iwl_mvm_ftm_resp_remove_pasn_sta(struct iwl_mvm *mvm, 3708c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, u8 *addr) 3718c2ecf20Sopenharmony_ci{ 3728c2ecf20Sopenharmony_ci struct iwl_mvm_pasn_sta *sta, *prev; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci lockdep_assert_held(&mvm->mutex); 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci list_for_each_entry_safe(sta, prev, &mvm->resp_pasn_list, list) { 3778c2ecf20Sopenharmony_ci if (!memcmp(sta->addr, addr, ETH_ALEN)) { 3788c2ecf20Sopenharmony_ci iwl_mvm_resp_del_pasn_sta(mvm, vif, sta); 3798c2ecf20Sopenharmony_ci return 0; 3808c2ecf20Sopenharmony_ci } 3818c2ecf20Sopenharmony_ci } 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci IWL_ERR(mvm, "FTM: PASN station %pM not found\n", addr); 3848c2ecf20Sopenharmony_ci return -EINVAL; 3858c2ecf20Sopenharmony_ci} 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ciint iwl_mvm_ftm_start_responder(struct iwl_mvm *mvm, struct ieee80211_vif *vif) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 3908c2ecf20Sopenharmony_ci struct ieee80211_ftm_responder_params *params; 3918c2ecf20Sopenharmony_ci struct ieee80211_chanctx_conf ctx, *pctx; 3928c2ecf20Sopenharmony_ci u16 *phy_ctxt_id; 3938c2ecf20Sopenharmony_ci struct iwl_mvm_phy_ctxt *phy_ctxt; 3948c2ecf20Sopenharmony_ci int ret; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci params = vif->bss_conf.ftmr_params; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci lockdep_assert_held(&mvm->mutex); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(!vif->bss_conf.ftm_responder)) 4018c2ecf20Sopenharmony_ci return -EINVAL; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci if (vif->p2p || vif->type != NL80211_IFTYPE_AP || 4048c2ecf20Sopenharmony_ci !mvmvif->ap_ibss_active) { 4058c2ecf20Sopenharmony_ci IWL_ERR(mvm, "Cannot start responder, not in AP mode\n"); 4068c2ecf20Sopenharmony_ci return -EIO; 4078c2ecf20Sopenharmony_ci } 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci rcu_read_lock(); 4108c2ecf20Sopenharmony_ci pctx = rcu_dereference(vif->chanctx_conf); 4118c2ecf20Sopenharmony_ci /* Copy the ctx to unlock the rcu and send the phy ctxt. We don't care 4128c2ecf20Sopenharmony_ci * about changes in the ctx after releasing the lock because the driver 4138c2ecf20Sopenharmony_ci * is still protected by the mutex. */ 4148c2ecf20Sopenharmony_ci ctx = *pctx; 4158c2ecf20Sopenharmony_ci phy_ctxt_id = (u16 *)pctx->drv_priv; 4168c2ecf20Sopenharmony_ci rcu_read_unlock(); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id]; 4198c2ecf20Sopenharmony_ci ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx.def, 4208c2ecf20Sopenharmony_ci ctx.rx_chains_static, 4218c2ecf20Sopenharmony_ci ctx.rx_chains_dynamic); 4228c2ecf20Sopenharmony_ci if (ret) 4238c2ecf20Sopenharmony_ci return ret; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci ret = iwl_mvm_ftm_responder_cmd(mvm, vif, &ctx.def); 4268c2ecf20Sopenharmony_ci if (ret) 4278c2ecf20Sopenharmony_ci return ret; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci if (params) 4308c2ecf20Sopenharmony_ci ret = iwl_mvm_ftm_responder_dyn_cfg_cmd(mvm, vif, params); 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci return ret; 4338c2ecf20Sopenharmony_ci} 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_civoid iwl_mvm_ftm_responder_clear(struct iwl_mvm *mvm, 4368c2ecf20Sopenharmony_ci struct ieee80211_vif *vif) 4378c2ecf20Sopenharmony_ci{ 4388c2ecf20Sopenharmony_ci struct iwl_mvm_pasn_sta *sta, *prev; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci lockdep_assert_held(&mvm->mutex); 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci list_for_each_entry_safe(sta, prev, &mvm->resp_pasn_list, list) 4438c2ecf20Sopenharmony_ci iwl_mvm_resp_del_pasn_sta(mvm, vif, sta); 4448c2ecf20Sopenharmony_ci} 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_civoid iwl_mvm_ftm_restart_responder(struct iwl_mvm *mvm, 4478c2ecf20Sopenharmony_ci struct ieee80211_vif *vif) 4488c2ecf20Sopenharmony_ci{ 4498c2ecf20Sopenharmony_ci if (!vif->bss_conf.ftm_responder) 4508c2ecf20Sopenharmony_ci return; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci iwl_mvm_ftm_responder_clear(mvm, vif); 4538c2ecf20Sopenharmony_ci iwl_mvm_ftm_start_responder(mvm, vif); 4548c2ecf20Sopenharmony_ci} 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_civoid iwl_mvm_ftm_responder_stats(struct iwl_mvm *mvm, 4578c2ecf20Sopenharmony_ci struct iwl_rx_cmd_buffer *rxb) 4588c2ecf20Sopenharmony_ci{ 4598c2ecf20Sopenharmony_ci struct iwl_rx_packet *pkt = rxb_addr(rxb); 4608c2ecf20Sopenharmony_ci struct iwl_ftm_responder_stats *resp = (void *)pkt->data; 4618c2ecf20Sopenharmony_ci struct cfg80211_ftm_responder_stats *stats = &mvm->ftm_resp_stats; 4628c2ecf20Sopenharmony_ci u32 flags = le32_to_cpu(resp->flags); 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci if (resp->success_ftm == resp->ftm_per_burst) 4658c2ecf20Sopenharmony_ci stats->success_num++; 4668c2ecf20Sopenharmony_ci else if (resp->success_ftm >= 2) 4678c2ecf20Sopenharmony_ci stats->partial_num++; 4688c2ecf20Sopenharmony_ci else 4698c2ecf20Sopenharmony_ci stats->failed_num++; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci if ((flags & FTM_RESP_STAT_ASAP_REQ) && 4728c2ecf20Sopenharmony_ci (flags & FTM_RESP_STAT_ASAP_RESP)) 4738c2ecf20Sopenharmony_ci stats->asap_num++; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci if (flags & FTM_RESP_STAT_NON_ASAP_RESP) 4768c2ecf20Sopenharmony_ci stats->non_asap_num++; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci stats->total_duration_ms += le32_to_cpu(resp->duration) / USEC_PER_MSEC; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci if (flags & FTM_RESP_STAT_TRIGGER_UNKNOWN) 4818c2ecf20Sopenharmony_ci stats->unknown_triggers_num++; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci if (flags & FTM_RESP_STAT_DUP) 4848c2ecf20Sopenharmony_ci stats->reschedule_requests_num++; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci if (flags & FTM_RESP_STAT_NON_ASAP_OUT_WIN) 4878c2ecf20Sopenharmony_ci stats->out_of_window_triggers_num++; 4888c2ecf20Sopenharmony_ci} 489