1 /****************************************************************************** 2 * 3 * This file is provided under a dual BSD/GPLv2 license. When using or 4 * redistributing this file, you may do so under either license. 5 * 6 * GPL LICENSE SUMMARY 7 * 8 * Copyright(c) 2015 - 2017 Intel Deutschland GmbH 9 * Copyright (C) 2018 Intel Corporation 10 * 11 * This program is free software; you can redistribute it and/or modify 12 * it under the terms of version 2 of the GNU General Public License as 13 * published by the Free Software Foundation. 14 * 15 * This program is distributed in the hope that it will be useful, but 16 * WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 * General Public License for more details. 19 * 20 * The full GNU General Public License is included in this distribution 21 * in the file called COPYING. 22 * 23 * Contact Information: 24 * Intel Linux Wireless <linuxwifi@intel.com> 25 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 26 * 27 * BSD LICENSE 28 * 29 * Copyright(c) 2015 - 2017 Intel Deutschland GmbH 30 * Copyright (C) 2018 Intel Corporation 31 * All rights reserved. 32 * 33 * Redistribution and use in source and binary forms, with or without 34 * modification, are permitted provided that the following conditions 35 * are met: 36 * 37 * * Redistributions of source code must retain the above copyright 38 * notice, this list of conditions and the following disclaimer. 39 * * Redistributions in binary form must reproduce the above copyright 40 * notice, this list of conditions and the following disclaimer in 41 * the documentation and/or other materials provided with the 42 * distribution. 43 * * Neither the name Intel Corporation nor the names of its 44 * contributors may be used to endorse or promote products derived 45 * from this software without specific prior written permission. 46 * 47 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 48 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 49 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 50 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 51 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 52 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 53 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 54 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 55 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 56 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 57 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 58 * 59 *****************************************************************************/ 60 #include <net/cfg80211.h> 61 #include <linux/etherdevice.h> 62 #include "mvm.h" 63 #include "constants.h" 64 65 static int 66 iwl_mvm_ftm_responder_cmd(struct iwl_mvm *mvm, 67 struct ieee80211_vif *vif, 68 struct cfg80211_chan_def *chandef) 69 { 70 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 71 struct iwl_tof_responder_config_cmd cmd = { 72 .channel_num = chandef->chan->hw_value, 73 .cmd_valid_fields = 74 cpu_to_le32(IWL_TOF_RESPONDER_CMD_VALID_CHAN_INFO | 75 IWL_TOF_RESPONDER_CMD_VALID_BSSID | 76 IWL_TOF_RESPONDER_CMD_VALID_STA_ID), 77 .sta_id = mvmvif->bcast_sta.sta_id, 78 }; 79 80 lockdep_assert_held(&mvm->mutex); 81 82 switch (chandef->width) { 83 case NL80211_CHAN_WIDTH_20_NOHT: 84 cmd.bandwidth = IWL_TOF_BW_20_LEGACY; 85 break; 86 case NL80211_CHAN_WIDTH_20: 87 cmd.bandwidth = IWL_TOF_BW_20_HT; 88 break; 89 case NL80211_CHAN_WIDTH_40: 90 cmd.bandwidth = IWL_TOF_BW_40; 91 cmd.ctrl_ch_position = iwl_mvm_get_ctrl_pos(chandef); 92 break; 93 case NL80211_CHAN_WIDTH_80: 94 cmd.bandwidth = IWL_TOF_BW_80; 95 cmd.ctrl_ch_position = iwl_mvm_get_ctrl_pos(chandef); 96 break; 97 default: 98 WARN_ON(1); 99 return -EINVAL; 100 } 101 102 memcpy(cmd.bssid, vif->addr, ETH_ALEN); 103 104 return iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(TOF_RESPONDER_CONFIG_CMD, 105 LOCATION_GROUP, 0), 106 0, sizeof(cmd), &cmd); 107 } 108 109 static int 110 iwl_mvm_ftm_responder_dyn_cfg_cmd(struct iwl_mvm *mvm, 111 struct ieee80211_vif *vif, 112 struct ieee80211_ftm_responder_params *params) 113 { 114 struct iwl_tof_responder_dyn_config_cmd cmd = { 115 .lci_len = cpu_to_le32(params->lci_len + 2), 116 .civic_len = cpu_to_le32(params->civicloc_len + 2), 117 }; 118 u8 data[IWL_LCI_CIVIC_IE_MAX_SIZE] = {0}; 119 struct iwl_host_cmd hcmd = { 120 .id = iwl_cmd_id(TOF_RESPONDER_DYN_CONFIG_CMD, 121 LOCATION_GROUP, 0), 122 .data[0] = &cmd, 123 .len[0] = sizeof(cmd), 124 .data[1] = &data, 125 /* .len[1] set later */ 126 /* may not be able to DMA from stack */ 127 .dataflags[1] = IWL_HCMD_DFL_DUP, 128 }; 129 u32 aligned_lci_len = ALIGN(params->lci_len + 2, 4); 130 u32 aligned_civicloc_len = ALIGN(params->civicloc_len + 2, 4); 131 u8 *pos = data; 132 133 lockdep_assert_held(&mvm->mutex); 134 135 if (aligned_lci_len + aligned_civicloc_len > sizeof(data)) { 136 IWL_ERR(mvm, "LCI/civicloc data too big (%zd + %zd)\n", 137 params->lci_len, params->civicloc_len); 138 return -ENOBUFS; 139 } 140 141 pos[0] = WLAN_EID_MEASURE_REPORT; 142 pos[1] = params->lci_len; 143 memcpy(pos + 2, params->lci, params->lci_len); 144 145 pos += aligned_lci_len; 146 pos[0] = WLAN_EID_MEASURE_REPORT; 147 pos[1] = params->civicloc_len; 148 memcpy(pos + 2, params->civicloc, params->civicloc_len); 149 150 hcmd.len[1] = aligned_lci_len + aligned_civicloc_len; 151 152 return iwl_mvm_send_cmd(mvm, &hcmd); 153 } 154 155 int iwl_mvm_ftm_start_responder(struct iwl_mvm *mvm, struct ieee80211_vif *vif) 156 { 157 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 158 struct ieee80211_ftm_responder_params *params; 159 struct ieee80211_chanctx_conf ctx, *pctx; 160 u16 *phy_ctxt_id; 161 struct iwl_mvm_phy_ctxt *phy_ctxt; 162 int ret; 163 164 params = vif->bss_conf.ftmr_params; 165 166 lockdep_assert_held(&mvm->mutex); 167 168 if (WARN_ON_ONCE(!vif->bss_conf.ftm_responder)) 169 return -EINVAL; 170 171 if (vif->p2p || vif->type != NL80211_IFTYPE_AP || 172 !mvmvif->ap_ibss_active) { 173 IWL_ERR(mvm, "Cannot start responder, not in AP mode\n"); 174 return -EIO; 175 } 176 177 rcu_read_lock(); 178 pctx = rcu_dereference(vif->chanctx_conf); 179 /* Copy the ctx to unlock the rcu and send the phy ctxt. We don't care 180 * about changes in the ctx after releasing the lock because the driver 181 * is still protected by the mutex. */ 182 ctx = *pctx; 183 phy_ctxt_id = (u16 *)pctx->drv_priv; 184 rcu_read_unlock(); 185 186 phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id]; 187 ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx.def, 188 ctx.rx_chains_static, 189 ctx.rx_chains_dynamic); 190 if (ret) 191 return ret; 192 193 ret = iwl_mvm_ftm_responder_cmd(mvm, vif, &ctx.def); 194 if (ret) 195 return ret; 196 197 if (params) 198 ret = iwl_mvm_ftm_responder_dyn_cfg_cmd(mvm, vif, params); 199 200 return ret; 201 } 202 203 void iwl_mvm_ftm_restart_responder(struct iwl_mvm *mvm, 204 struct ieee80211_vif *vif) 205 { 206 if (!vif->bss_conf.ftm_responder) 207 return; 208 209 iwl_mvm_ftm_start_responder(mvm, vif); 210 } 211 212 void iwl_mvm_ftm_responder_stats(struct iwl_mvm *mvm, 213 struct iwl_rx_cmd_buffer *rxb) 214 { 215 struct iwl_rx_packet *pkt = rxb_addr(rxb); 216 struct iwl_ftm_responder_stats *resp = (void *)pkt->data; 217 struct cfg80211_ftm_responder_stats *stats = &mvm->ftm_resp_stats; 218 u32 flags = le32_to_cpu(resp->flags); 219 220 if (resp->success_ftm == resp->ftm_per_burst) 221 stats->success_num++; 222 else if (resp->success_ftm >= 2) 223 stats->partial_num++; 224 else 225 stats->failed_num++; 226 227 if ((flags & FTM_RESP_STAT_ASAP_REQ) && 228 (flags & FTM_RESP_STAT_ASAP_RESP)) 229 stats->asap_num++; 230 231 if (flags & FTM_RESP_STAT_NON_ASAP_RESP) 232 stats->non_asap_num++; 233 234 stats->total_duration_ms += le32_to_cpu(resp->duration) / USEC_PER_MSEC; 235 236 if (flags & FTM_RESP_STAT_TRIGGER_UNKNOWN) 237 stats->unknown_triggers_num++; 238 239 if (flags & FTM_RESP_STAT_DUP) 240 stats->reschedule_requests_num++; 241 242 if (flags & FTM_RESP_STAT_NON_ASAP_OUT_WIN) 243 stats->out_of_window_triggers_num++; 244 } 245