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 - 2020 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 - 2020 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 struct iwl_mvm_pasn_sta { 66 struct list_head list; 67 struct iwl_mvm_int_sta int_sta; 68 u8 addr[ETH_ALEN]; 69 }; 70 71 struct iwl_mvm_pasn_hltk_data { 72 u8 *addr; 73 u8 cipher; 74 u8 *hltk; 75 }; 76 77 static int iwl_mvm_ftm_responder_set_bw_v1(struct cfg80211_chan_def *chandef, 78 u8 *bw, u8 *ctrl_ch_position) 79 { 80 switch (chandef->width) { 81 case NL80211_CHAN_WIDTH_20_NOHT: 82 *bw = IWL_TOF_BW_20_LEGACY; 83 break; 84 case NL80211_CHAN_WIDTH_20: 85 *bw = IWL_TOF_BW_20_HT; 86 break; 87 case NL80211_CHAN_WIDTH_40: 88 *bw = IWL_TOF_BW_40; 89 *ctrl_ch_position = iwl_mvm_get_ctrl_pos(chandef); 90 break; 91 case NL80211_CHAN_WIDTH_80: 92 *bw = IWL_TOF_BW_80; 93 *ctrl_ch_position = iwl_mvm_get_ctrl_pos(chandef); 94 break; 95 default: 96 return -ENOTSUPP; 97 } 98 99 return 0; 100 } 101 102 static int iwl_mvm_ftm_responder_set_bw_v2(struct cfg80211_chan_def *chandef, 103 u8 *format_bw, 104 u8 *ctrl_ch_position) 105 { 106 switch (chandef->width) { 107 case NL80211_CHAN_WIDTH_20_NOHT: 108 *format_bw = IWL_LOCATION_FRAME_FORMAT_LEGACY; 109 *format_bw |= IWL_LOCATION_BW_20MHZ << LOCATION_BW_POS; 110 break; 111 case NL80211_CHAN_WIDTH_20: 112 *format_bw = IWL_LOCATION_FRAME_FORMAT_HT; 113 *format_bw |= IWL_LOCATION_BW_20MHZ << LOCATION_BW_POS; 114 break; 115 case NL80211_CHAN_WIDTH_40: 116 *format_bw = IWL_LOCATION_FRAME_FORMAT_HT; 117 *format_bw |= IWL_LOCATION_BW_40MHZ << LOCATION_BW_POS; 118 *ctrl_ch_position = iwl_mvm_get_ctrl_pos(chandef); 119 break; 120 case NL80211_CHAN_WIDTH_80: 121 *format_bw = IWL_LOCATION_FRAME_FORMAT_VHT; 122 *format_bw |= IWL_LOCATION_BW_80MHZ << LOCATION_BW_POS; 123 *ctrl_ch_position = iwl_mvm_get_ctrl_pos(chandef); 124 break; 125 default: 126 return -ENOTSUPP; 127 } 128 129 return 0; 130 } 131 132 static int 133 iwl_mvm_ftm_responder_cmd(struct iwl_mvm *mvm, 134 struct ieee80211_vif *vif, 135 struct cfg80211_chan_def *chandef) 136 { 137 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 138 /* 139 * The command structure is the same for versions 6 and 7, (only the 140 * field interpretation is different), so the same struct can be use 141 * for all cases. 142 */ 143 struct iwl_tof_responder_config_cmd cmd = { 144 .channel_num = chandef->chan->hw_value, 145 .cmd_valid_fields = 146 cpu_to_le32(IWL_TOF_RESPONDER_CMD_VALID_CHAN_INFO | 147 IWL_TOF_RESPONDER_CMD_VALID_BSSID | 148 IWL_TOF_RESPONDER_CMD_VALID_STA_ID), 149 .sta_id = mvmvif->bcast_sta.sta_id, 150 }; 151 u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, LOCATION_GROUP, 152 TOF_RESPONDER_CONFIG_CMD, 6); 153 int err; 154 155 lockdep_assert_held(&mvm->mutex); 156 157 if (cmd_ver == 7) 158 err = iwl_mvm_ftm_responder_set_bw_v2(chandef, &cmd.format_bw, 159 &cmd.ctrl_ch_position); 160 else 161 err = iwl_mvm_ftm_responder_set_bw_v1(chandef, &cmd.format_bw, 162 &cmd.ctrl_ch_position); 163 164 if (err) { 165 IWL_ERR(mvm, "Failed to set responder bandwidth\n"); 166 return err; 167 } 168 169 memcpy(cmd.bssid, vif->addr, ETH_ALEN); 170 171 return iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(TOF_RESPONDER_CONFIG_CMD, 172 LOCATION_GROUP, 0), 173 0, sizeof(cmd), &cmd); 174 } 175 176 static int 177 iwl_mvm_ftm_responder_dyn_cfg_v2(struct iwl_mvm *mvm, 178 struct ieee80211_vif *vif, 179 struct ieee80211_ftm_responder_params *params) 180 { 181 struct iwl_tof_responder_dyn_config_cmd_v2 cmd = { 182 .lci_len = cpu_to_le32(params->lci_len + 2), 183 .civic_len = cpu_to_le32(params->civicloc_len + 2), 184 }; 185 u8 data[IWL_LCI_CIVIC_IE_MAX_SIZE] = {0}; 186 struct iwl_host_cmd hcmd = { 187 .id = iwl_cmd_id(TOF_RESPONDER_DYN_CONFIG_CMD, 188 LOCATION_GROUP, 0), 189 .data[0] = &cmd, 190 .len[0] = sizeof(cmd), 191 .data[1] = &data, 192 /* .len[1] set later */ 193 /* may not be able to DMA from stack */ 194 .dataflags[1] = IWL_HCMD_DFL_DUP, 195 }; 196 u32 aligned_lci_len = ALIGN(params->lci_len + 2, 4); 197 u32 aligned_civicloc_len = ALIGN(params->civicloc_len + 2, 4); 198 u8 *pos = data; 199 200 lockdep_assert_held(&mvm->mutex); 201 202 if (aligned_lci_len + aligned_civicloc_len > sizeof(data)) { 203 IWL_ERR(mvm, "LCI/civicloc data too big (%zd + %zd)\n", 204 params->lci_len, params->civicloc_len); 205 return -ENOBUFS; 206 } 207 208 pos[0] = WLAN_EID_MEASURE_REPORT; 209 pos[1] = params->lci_len; 210 memcpy(pos + 2, params->lci, params->lci_len); 211 212 pos += aligned_lci_len; 213 pos[0] = WLAN_EID_MEASURE_REPORT; 214 pos[1] = params->civicloc_len; 215 memcpy(pos + 2, params->civicloc, params->civicloc_len); 216 217 hcmd.len[1] = aligned_lci_len + aligned_civicloc_len; 218 219 return iwl_mvm_send_cmd(mvm, &hcmd); 220 } 221 222 static int 223 iwl_mvm_ftm_responder_dyn_cfg_v3(struct iwl_mvm *mvm, 224 struct ieee80211_vif *vif, 225 struct ieee80211_ftm_responder_params *params, 226 struct iwl_mvm_pasn_hltk_data *hltk_data) 227 { 228 struct iwl_tof_responder_dyn_config_cmd cmd; 229 struct iwl_host_cmd hcmd = { 230 .id = iwl_cmd_id(TOF_RESPONDER_DYN_CONFIG_CMD, 231 LOCATION_GROUP, 0), 232 .data[0] = &cmd, 233 .len[0] = sizeof(cmd), 234 /* may not be able to DMA from stack */ 235 .dataflags[0] = IWL_HCMD_DFL_DUP, 236 }; 237 238 lockdep_assert_held(&mvm->mutex); 239 240 cmd.valid_flags = 0; 241 242 if (params) { 243 if (params->lci_len + 2 > sizeof(cmd.lci_buf) || 244 params->civicloc_len + 2 > sizeof(cmd.civic_buf)) { 245 IWL_ERR(mvm, 246 "LCI/civic data too big (lci=%zd, civic=%zd)\n", 247 params->lci_len, params->civicloc_len); 248 return -ENOBUFS; 249 } 250 251 cmd.lci_buf[0] = WLAN_EID_MEASURE_REPORT; 252 cmd.lci_buf[1] = params->lci_len; 253 memcpy(cmd.lci_buf + 2, params->lci, params->lci_len); 254 cmd.lci_len = params->lci_len + 2; 255 256 cmd.civic_buf[0] = WLAN_EID_MEASURE_REPORT; 257 cmd.civic_buf[1] = params->civicloc_len; 258 memcpy(cmd.civic_buf + 2, params->civicloc, 259 params->civicloc_len); 260 cmd.civic_len = params->civicloc_len + 2; 261 262 cmd.valid_flags |= IWL_RESPONDER_DYN_CFG_VALID_LCI | 263 IWL_RESPONDER_DYN_CFG_VALID_CIVIC; 264 } 265 266 if (hltk_data) { 267 if (hltk_data->cipher > IWL_LOCATION_CIPHER_GCMP_256) { 268 IWL_ERR(mvm, "invalid cipher: %u\n", 269 hltk_data->cipher); 270 return -EINVAL; 271 } 272 273 cmd.cipher = hltk_data->cipher; 274 memcpy(cmd.addr, hltk_data->addr, sizeof(cmd.addr)); 275 memcpy(cmd.hltk_buf, hltk_data->hltk, sizeof(cmd.hltk_buf)); 276 cmd.valid_flags |= IWL_RESPONDER_DYN_CFG_VALID_PASN_STA; 277 } 278 279 return iwl_mvm_send_cmd(mvm, &hcmd); 280 } 281 282 static int 283 iwl_mvm_ftm_responder_dyn_cfg_cmd(struct iwl_mvm *mvm, 284 struct ieee80211_vif *vif, 285 struct ieee80211_ftm_responder_params *params) 286 { 287 int ret; 288 u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, LOCATION_GROUP, 289 TOF_RESPONDER_DYN_CONFIG_CMD, 2); 290 291 switch (cmd_ver) { 292 case 2: 293 ret = iwl_mvm_ftm_responder_dyn_cfg_v2(mvm, vif, 294 params); 295 break; 296 case 3: 297 ret = iwl_mvm_ftm_responder_dyn_cfg_v3(mvm, vif, 298 params, NULL); 299 break; 300 default: 301 IWL_ERR(mvm, "Unsupported DYN_CONFIG_CMD version %u\n", 302 cmd_ver); 303 ret = -ENOTSUPP; 304 } 305 306 return ret; 307 } 308 309 static void iwl_mvm_resp_del_pasn_sta(struct iwl_mvm *mvm, 310 struct ieee80211_vif *vif, 311 struct iwl_mvm_pasn_sta *sta) 312 { 313 list_del(&sta->list); 314 iwl_mvm_rm_sta_id(mvm, vif, sta->int_sta.sta_id); 315 iwl_mvm_dealloc_int_sta(mvm, &sta->int_sta); 316 kfree(sta); 317 } 318 319 int iwl_mvm_ftm_respoder_add_pasn_sta(struct iwl_mvm *mvm, 320 struct ieee80211_vif *vif, 321 u8 *addr, u32 cipher, u8 *tk, u32 tk_len, 322 u8 *hltk, u32 hltk_len) 323 { 324 int ret; 325 struct iwl_mvm_pasn_sta *sta = NULL; 326 struct iwl_mvm_pasn_hltk_data hltk_data = { 327 .addr = addr, 328 .hltk = hltk, 329 }; 330 u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, LOCATION_GROUP, 331 TOF_RESPONDER_DYN_CONFIG_CMD, 2); 332 333 lockdep_assert_held(&mvm->mutex); 334 335 if (cmd_ver < 3) { 336 IWL_ERR(mvm, "Adding PASN station not supported by FW\n"); 337 return -ENOTSUPP; 338 } 339 340 hltk_data.cipher = iwl_mvm_cipher_to_location_cipher(cipher); 341 if (hltk_data.cipher == IWL_LOCATION_CIPHER_INVALID) { 342 IWL_ERR(mvm, "invalid cipher: %u\n", cipher); 343 return -EINVAL; 344 } 345 346 if (tk && tk_len) { 347 sta = kzalloc(sizeof(*sta), GFP_KERNEL); 348 if (!sta) 349 return -ENOBUFS; 350 351 ret = iwl_mvm_add_pasn_sta(mvm, vif, &sta->int_sta, addr, 352 cipher, tk, tk_len); 353 if (ret) { 354 kfree(sta); 355 return ret; 356 } 357 358 memcpy(sta->addr, addr, ETH_ALEN); 359 list_add_tail(&sta->list, &mvm->resp_pasn_list); 360 } 361 362 ret = iwl_mvm_ftm_responder_dyn_cfg_v3(mvm, vif, NULL, &hltk_data); 363 if (ret && sta) 364 iwl_mvm_resp_del_pasn_sta(mvm, vif, sta); 365 366 return ret; 367 } 368 369 int iwl_mvm_ftm_resp_remove_pasn_sta(struct iwl_mvm *mvm, 370 struct ieee80211_vif *vif, u8 *addr) 371 { 372 struct iwl_mvm_pasn_sta *sta, *prev; 373 374 lockdep_assert_held(&mvm->mutex); 375 376 list_for_each_entry_safe(sta, prev, &mvm->resp_pasn_list, list) { 377 if (!memcmp(sta->addr, addr, ETH_ALEN)) { 378 iwl_mvm_resp_del_pasn_sta(mvm, vif, sta); 379 return 0; 380 } 381 } 382 383 IWL_ERR(mvm, "FTM: PASN station %pM not found\n", addr); 384 return -EINVAL; 385 } 386 387 int iwl_mvm_ftm_start_responder(struct iwl_mvm *mvm, struct ieee80211_vif *vif) 388 { 389 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 390 struct ieee80211_ftm_responder_params *params; 391 struct ieee80211_chanctx_conf ctx, *pctx; 392 u16 *phy_ctxt_id; 393 struct iwl_mvm_phy_ctxt *phy_ctxt; 394 int ret; 395 396 params = vif->bss_conf.ftmr_params; 397 398 lockdep_assert_held(&mvm->mutex); 399 400 if (WARN_ON_ONCE(!vif->bss_conf.ftm_responder)) 401 return -EINVAL; 402 403 if (vif->p2p || vif->type != NL80211_IFTYPE_AP || 404 !mvmvif->ap_ibss_active) { 405 IWL_ERR(mvm, "Cannot start responder, not in AP mode\n"); 406 return -EIO; 407 } 408 409 rcu_read_lock(); 410 pctx = rcu_dereference(vif->chanctx_conf); 411 /* Copy the ctx to unlock the rcu and send the phy ctxt. We don't care 412 * about changes in the ctx after releasing the lock because the driver 413 * is still protected by the mutex. */ 414 ctx = *pctx; 415 phy_ctxt_id = (u16 *)pctx->drv_priv; 416 rcu_read_unlock(); 417 418 phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id]; 419 ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx.def, 420 ctx.rx_chains_static, 421 ctx.rx_chains_dynamic); 422 if (ret) 423 return ret; 424 425 ret = iwl_mvm_ftm_responder_cmd(mvm, vif, &ctx.def); 426 if (ret) 427 return ret; 428 429 if (params) 430 ret = iwl_mvm_ftm_responder_dyn_cfg_cmd(mvm, vif, params); 431 432 return ret; 433 } 434 435 void iwl_mvm_ftm_responder_clear(struct iwl_mvm *mvm, 436 struct ieee80211_vif *vif) 437 { 438 struct iwl_mvm_pasn_sta *sta, *prev; 439 440 lockdep_assert_held(&mvm->mutex); 441 442 list_for_each_entry_safe(sta, prev, &mvm->resp_pasn_list, list) 443 iwl_mvm_resp_del_pasn_sta(mvm, vif, sta); 444 } 445 446 void iwl_mvm_ftm_restart_responder(struct iwl_mvm *mvm, 447 struct ieee80211_vif *vif) 448 { 449 if (!vif->bss_conf.ftm_responder) 450 return; 451 452 iwl_mvm_ftm_responder_clear(mvm, vif); 453 iwl_mvm_ftm_start_responder(mvm, vif); 454 } 455 456 void iwl_mvm_ftm_responder_stats(struct iwl_mvm *mvm, 457 struct iwl_rx_cmd_buffer *rxb) 458 { 459 struct iwl_rx_packet *pkt = rxb_addr(rxb); 460 struct iwl_ftm_responder_stats *resp = (void *)pkt->data; 461 struct cfg80211_ftm_responder_stats *stats = &mvm->ftm_resp_stats; 462 u32 flags = le32_to_cpu(resp->flags); 463 464 if (resp->success_ftm == resp->ftm_per_burst) 465 stats->success_num++; 466 else if (resp->success_ftm >= 2) 467 stats->partial_num++; 468 else 469 stats->failed_num++; 470 471 if ((flags & FTM_RESP_STAT_ASAP_REQ) && 472 (flags & FTM_RESP_STAT_ASAP_RESP)) 473 stats->asap_num++; 474 475 if (flags & FTM_RESP_STAT_NON_ASAP_RESP) 476 stats->non_asap_num++; 477 478 stats->total_duration_ms += le32_to_cpu(resp->duration) / USEC_PER_MSEC; 479 480 if (flags & FTM_RESP_STAT_TRIGGER_UNKNOWN) 481 stats->unknown_triggers_num++; 482 483 if (flags & FTM_RESP_STAT_DUP) 484 stats->reschedule_requests_num++; 485 486 if (flags & FTM_RESP_STAT_NON_ASAP_OUT_WIN) 487 stats->out_of_window_triggers_num++; 488 } 489