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 * Copyright (C) 2019 Intel Corporation 11 * Copyright (C) 2020 Intel Corporation 12 * 13 * This program is free software; you can redistribute it and/or modify 14 * it under the terms of version 2 of the GNU General Public License as 15 * published by the Free Software Foundation. 16 * 17 * This program is distributed in the hope that it will be useful, but 18 * WITHOUT ANY WARRANTY; without even the implied warranty of 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20 * General Public License for more details. 21 * 22 * The full GNU General Public License is included in this distribution 23 * in the file called COPYING. 24 * 25 * Contact Information: 26 * Intel Linux Wireless <linuxwifi@intel.com> 27 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 28 * 29 * BSD LICENSE 30 * 31 * Copyright(c) 2015 - 2017 Intel Deutschland GmbH 32 * Copyright (C) 2018 Intel Corporation 33 * Copyright (C) 2019 Intel Corporation 34 * Copyright (C) 2020 Intel Corporation 35 * All rights reserved. 36 * 37 * Redistribution and use in source and binary forms, with or without 38 * modification, are permitted provided that the following conditions 39 * are met: 40 * 41 * * Redistributions of source code must retain the above copyright 42 * notice, this list of conditions and the following disclaimer. 43 * * Redistributions in binary form must reproduce the above copyright 44 * notice, this list of conditions and the following disclaimer in 45 * the documentation and/or other materials provided with the 46 * distribution. 47 * * Neither the name Intel Corporation nor the names of its 48 * contributors may be used to endorse or promote products derived 49 * from this software without specific prior written permission. 50 * 51 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 52 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 53 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 54 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 55 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 56 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 57 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 58 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 59 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 60 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 61 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 62 * 63 *****************************************************************************/ 64 #include <linux/etherdevice.h> 65 #include <linux/math64.h> 66 #include <net/cfg80211.h> 67 #include "mvm.h" 68 #include "iwl-io.h" 69 #include "iwl-prph.h" 70 #include "constants.h" 71 72 struct iwl_mvm_loc_entry { 73 struct list_head list; 74 u8 addr[ETH_ALEN]; 75 u8 lci_len, civic_len; 76 u8 buf[]; 77 }; 78 79 static void iwl_mvm_ftm_reset(struct iwl_mvm *mvm) 80 { 81 struct iwl_mvm_loc_entry *e, *t; 82 83 mvm->ftm_initiator.req = NULL; 84 mvm->ftm_initiator.req_wdev = NULL; 85 memset(mvm->ftm_initiator.responses, 0, 86 sizeof(mvm->ftm_initiator.responses)); 87 list_for_each_entry_safe(e, t, &mvm->ftm_initiator.loc_list, list) { 88 list_del(&e->list); 89 kfree(e); 90 } 91 } 92 93 void iwl_mvm_ftm_restart(struct iwl_mvm *mvm) 94 { 95 struct cfg80211_pmsr_result result = { 96 .status = NL80211_PMSR_STATUS_FAILURE, 97 .final = 1, 98 .host_time = ktime_get_boottime_ns(), 99 .type = NL80211_PMSR_TYPE_FTM, 100 }; 101 int i; 102 103 lockdep_assert_held(&mvm->mutex); 104 105 if (!mvm->ftm_initiator.req) 106 return; 107 108 for (i = 0; i < mvm->ftm_initiator.req->n_peers; i++) { 109 memcpy(result.addr, mvm->ftm_initiator.req->peers[i].addr, 110 ETH_ALEN); 111 result.ftm.burst_index = mvm->ftm_initiator.responses[i]; 112 113 cfg80211_pmsr_report(mvm->ftm_initiator.req_wdev, 114 mvm->ftm_initiator.req, 115 &result, GFP_KERNEL); 116 } 117 118 cfg80211_pmsr_complete(mvm->ftm_initiator.req_wdev, 119 mvm->ftm_initiator.req, GFP_KERNEL); 120 iwl_mvm_ftm_reset(mvm); 121 } 122 123 static int 124 iwl_ftm_range_request_status_to_err(enum iwl_tof_range_request_status s) 125 { 126 switch (s) { 127 case IWL_TOF_RANGE_REQUEST_STATUS_SUCCESS: 128 return 0; 129 case IWL_TOF_RANGE_REQUEST_STATUS_BUSY: 130 return -EBUSY; 131 default: 132 WARN_ON_ONCE(1); 133 return -EIO; 134 } 135 } 136 137 static void iwl_mvm_ftm_cmd_v5(struct iwl_mvm *mvm, struct ieee80211_vif *vif, 138 struct iwl_tof_range_req_cmd_v5 *cmd, 139 struct cfg80211_pmsr_request *req) 140 { 141 int i; 142 143 cmd->request_id = req->cookie; 144 cmd->num_of_ap = req->n_peers; 145 146 /* use maximum for "no timeout" or bigger than what we can do */ 147 if (!req->timeout || req->timeout > 255 * 100) 148 cmd->req_timeout = 255; 149 else 150 cmd->req_timeout = DIV_ROUND_UP(req->timeout, 100); 151 152 /* 153 * We treat it always as random, since if not we'll 154 * have filled our local address there instead. 155 */ 156 cmd->macaddr_random = 1; 157 memcpy(cmd->macaddr_template, req->mac_addr, ETH_ALEN); 158 for (i = 0; i < ETH_ALEN; i++) 159 cmd->macaddr_mask[i] = ~req->mac_addr_mask[i]; 160 161 if (vif->bss_conf.assoc) 162 memcpy(cmd->range_req_bssid, vif->bss_conf.bssid, ETH_ALEN); 163 else 164 eth_broadcast_addr(cmd->range_req_bssid); 165 } 166 167 static void iwl_mvm_ftm_cmd_common(struct iwl_mvm *mvm, 168 struct ieee80211_vif *vif, 169 struct iwl_tof_range_req_cmd *cmd, 170 struct cfg80211_pmsr_request *req) 171 { 172 int i; 173 174 cmd->initiator_flags = 175 cpu_to_le32(IWL_TOF_INITIATOR_FLAGS_MACADDR_RANDOM | 176 IWL_TOF_INITIATOR_FLAGS_NON_ASAP_SUPPORT); 177 cmd->request_id = req->cookie; 178 cmd->num_of_ap = req->n_peers; 179 180 /* 181 * Use a large value for "no timeout". Don't use the maximum value 182 * because of fw limitations. 183 */ 184 if (req->timeout) 185 cmd->req_timeout_ms = cpu_to_le32(req->timeout); 186 else 187 cmd->req_timeout_ms = cpu_to_le32(0xfffff); 188 189 memcpy(cmd->macaddr_template, req->mac_addr, ETH_ALEN); 190 for (i = 0; i < ETH_ALEN; i++) 191 cmd->macaddr_mask[i] = ~req->mac_addr_mask[i]; 192 193 if (vif->bss_conf.assoc) { 194 memcpy(cmd->range_req_bssid, vif->bss_conf.bssid, ETH_ALEN); 195 196 /* AP's TSF is only relevant if associated */ 197 for (i = 0; i < req->n_peers; i++) { 198 if (req->peers[i].report_ap_tsf) { 199 struct iwl_mvm_vif *mvmvif = 200 iwl_mvm_vif_from_mac80211(vif); 201 202 cmd->tsf_mac_id = cpu_to_le32(mvmvif->id); 203 return; 204 } 205 } 206 } else { 207 eth_broadcast_addr(cmd->range_req_bssid); 208 } 209 210 /* Don't report AP's TSF */ 211 cmd->tsf_mac_id = cpu_to_le32(0xff); 212 } 213 214 static void iwl_mvm_ftm_cmd_v8(struct iwl_mvm *mvm, struct ieee80211_vif *vif, 215 struct iwl_tof_range_req_cmd_v8 *cmd, 216 struct cfg80211_pmsr_request *req) 217 { 218 iwl_mvm_ftm_cmd_common(mvm, vif, (void *)cmd, req); 219 } 220 221 static int 222 iwl_mvm_ftm_target_chandef_v1(struct iwl_mvm *mvm, 223 struct cfg80211_pmsr_request_peer *peer, 224 u8 *channel, u8 *bandwidth, 225 u8 *ctrl_ch_position) 226 { 227 u32 freq = peer->chandef.chan->center_freq; 228 229 *channel = ieee80211_frequency_to_channel(freq); 230 231 switch (peer->chandef.width) { 232 case NL80211_CHAN_WIDTH_20_NOHT: 233 *bandwidth = IWL_TOF_BW_20_LEGACY; 234 break; 235 case NL80211_CHAN_WIDTH_20: 236 *bandwidth = IWL_TOF_BW_20_HT; 237 break; 238 case NL80211_CHAN_WIDTH_40: 239 *bandwidth = IWL_TOF_BW_40; 240 break; 241 case NL80211_CHAN_WIDTH_80: 242 *bandwidth = IWL_TOF_BW_80; 243 break; 244 default: 245 IWL_ERR(mvm, "Unsupported BW in FTM request (%d)\n", 246 peer->chandef.width); 247 return -EINVAL; 248 } 249 250 *ctrl_ch_position = (peer->chandef.width > NL80211_CHAN_WIDTH_20) ? 251 iwl_mvm_get_ctrl_pos(&peer->chandef) : 0; 252 253 return 0; 254 } 255 256 static int 257 iwl_mvm_ftm_target_chandef_v2(struct iwl_mvm *mvm, 258 struct cfg80211_pmsr_request_peer *peer, 259 u8 *channel, u8 *format_bw, 260 u8 *ctrl_ch_position) 261 { 262 u32 freq = peer->chandef.chan->center_freq; 263 264 *channel = ieee80211_frequency_to_channel(freq); 265 266 switch (peer->chandef.width) { 267 case NL80211_CHAN_WIDTH_20_NOHT: 268 *format_bw = IWL_LOCATION_FRAME_FORMAT_LEGACY; 269 *format_bw |= IWL_LOCATION_BW_20MHZ << LOCATION_BW_POS; 270 break; 271 case NL80211_CHAN_WIDTH_20: 272 *format_bw = IWL_LOCATION_FRAME_FORMAT_HT; 273 *format_bw |= IWL_LOCATION_BW_20MHZ << LOCATION_BW_POS; 274 break; 275 case NL80211_CHAN_WIDTH_40: 276 *format_bw = IWL_LOCATION_FRAME_FORMAT_HT; 277 *format_bw |= IWL_LOCATION_BW_40MHZ << LOCATION_BW_POS; 278 break; 279 case NL80211_CHAN_WIDTH_80: 280 *format_bw = IWL_LOCATION_FRAME_FORMAT_VHT; 281 *format_bw |= IWL_LOCATION_BW_80MHZ << LOCATION_BW_POS; 282 break; 283 default: 284 IWL_ERR(mvm, "Unsupported BW in FTM request (%d)\n", 285 peer->chandef.width); 286 return -EINVAL; 287 } 288 289 /* non EDCA based measurement must use HE preamble */ 290 if (peer->ftm.trigger_based || peer->ftm.non_trigger_based) 291 *format_bw |= IWL_LOCATION_FRAME_FORMAT_HE; 292 293 *ctrl_ch_position = (peer->chandef.width > NL80211_CHAN_WIDTH_20) ? 294 iwl_mvm_get_ctrl_pos(&peer->chandef) : 0; 295 296 return 0; 297 } 298 299 static int 300 iwl_mvm_ftm_put_target_v2(struct iwl_mvm *mvm, 301 struct cfg80211_pmsr_request_peer *peer, 302 struct iwl_tof_range_req_ap_entry_v2 *target) 303 { 304 int ret; 305 306 ret = iwl_mvm_ftm_target_chandef_v1(mvm, peer, &target->channel_num, 307 &target->bandwidth, 308 &target->ctrl_ch_position); 309 if (ret) 310 return ret; 311 312 memcpy(target->bssid, peer->addr, ETH_ALEN); 313 target->burst_period = 314 cpu_to_le16(peer->ftm.burst_period); 315 target->samples_per_burst = peer->ftm.ftms_per_burst; 316 target->num_of_bursts = peer->ftm.num_bursts_exp; 317 target->measure_type = 0; /* regular two-sided FTM */ 318 target->retries_per_sample = peer->ftm.ftmr_retries; 319 target->asap_mode = peer->ftm.asap; 320 target->enable_dyn_ack = IWL_MVM_FTM_INITIATOR_DYNACK; 321 322 if (peer->ftm.request_lci) 323 target->location_req |= IWL_TOF_LOC_LCI; 324 if (peer->ftm.request_civicloc) 325 target->location_req |= IWL_TOF_LOC_CIVIC; 326 327 target->algo_type = IWL_MVM_FTM_INITIATOR_ALGO; 328 329 return 0; 330 } 331 332 #define FTM_PUT_FLAG(flag) (target->initiator_ap_flags |= \ 333 cpu_to_le32(IWL_INITIATOR_AP_FLAGS_##flag)) 334 335 static void 336 iwl_mvm_ftm_put_target_common(struct iwl_mvm *mvm, 337 struct cfg80211_pmsr_request_peer *peer, 338 struct iwl_tof_range_req_ap_entry *target) 339 { 340 memcpy(target->bssid, peer->addr, ETH_ALEN); 341 target->burst_period = 342 cpu_to_le16(peer->ftm.burst_period); 343 target->samples_per_burst = peer->ftm.ftms_per_burst; 344 target->num_of_bursts = peer->ftm.num_bursts_exp; 345 target->ftmr_max_retries = peer->ftm.ftmr_retries; 346 target->initiator_ap_flags = cpu_to_le32(0); 347 348 if (peer->ftm.asap) 349 FTM_PUT_FLAG(ASAP); 350 351 if (peer->ftm.request_lci) 352 FTM_PUT_FLAG(LCI_REQUEST); 353 354 if (peer->ftm.request_civicloc) 355 FTM_PUT_FLAG(CIVIC_REQUEST); 356 357 if (IWL_MVM_FTM_INITIATOR_DYNACK) 358 FTM_PUT_FLAG(DYN_ACK); 359 360 if (IWL_MVM_FTM_INITIATOR_ALGO == IWL_TOF_ALGO_TYPE_LINEAR_REG) 361 FTM_PUT_FLAG(ALGO_LR); 362 else if (IWL_MVM_FTM_INITIATOR_ALGO == IWL_TOF_ALGO_TYPE_FFT) 363 FTM_PUT_FLAG(ALGO_FFT); 364 365 if (peer->ftm.trigger_based) 366 FTM_PUT_FLAG(TB); 367 else if (peer->ftm.non_trigger_based) 368 FTM_PUT_FLAG(NON_TB); 369 } 370 371 static int 372 iwl_mvm_ftm_put_target_v3(struct iwl_mvm *mvm, 373 struct cfg80211_pmsr_request_peer *peer, 374 struct iwl_tof_range_req_ap_entry_v3 *target) 375 { 376 int ret; 377 378 ret = iwl_mvm_ftm_target_chandef_v1(mvm, peer, &target->channel_num, 379 &target->bandwidth, 380 &target->ctrl_ch_position); 381 if (ret) 382 return ret; 383 384 /* 385 * Versions 3 and 4 has some common fields, so 386 * iwl_mvm_ftm_put_target_common() can be used for version 7 too. 387 */ 388 iwl_mvm_ftm_put_target_common(mvm, peer, (void *)target); 389 390 return 0; 391 } 392 393 static int 394 iwl_mvm_ftm_put_target_v4(struct iwl_mvm *mvm, 395 struct cfg80211_pmsr_request_peer *peer, 396 struct iwl_tof_range_req_ap_entry_v4 *target) 397 { 398 int ret; 399 400 ret = iwl_mvm_ftm_target_chandef_v2(mvm, peer, &target->channel_num, 401 &target->format_bw, 402 &target->ctrl_ch_position); 403 if (ret) 404 return ret; 405 406 iwl_mvm_ftm_put_target_common(mvm, peer, (void *)target); 407 408 return 0; 409 } 410 411 static int 412 iwl_mvm_ftm_put_target(struct iwl_mvm *mvm, struct ieee80211_vif *vif, 413 struct cfg80211_pmsr_request_peer *peer, 414 struct iwl_tof_range_req_ap_entry *target) 415 { 416 int ret; 417 418 ret = iwl_mvm_ftm_target_chandef_v2(mvm, peer, &target->channel_num, 419 &target->format_bw, 420 &target->ctrl_ch_position); 421 if (ret) 422 return ret; 423 424 iwl_mvm_ftm_put_target_common(mvm, peer, (void *)target); 425 426 if (vif->bss_conf.assoc && 427 !memcmp(peer->addr, vif->bss_conf.bssid, ETH_ALEN)) { 428 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 429 430 target->sta_id = mvmvif->ap_sta_id; 431 } else { 432 target->sta_id = IWL_MVM_INVALID_STA; 433 } 434 435 /* 436 * TODO: Beacon interval is currently unknown, so use the common value 437 * of 100 TUs. 438 */ 439 target->beacon_interval = cpu_to_le16(100); 440 return 0; 441 } 442 443 static int iwl_mvm_ftm_send_cmd(struct iwl_mvm *mvm, struct iwl_host_cmd *hcmd) 444 { 445 u32 status; 446 int err = iwl_mvm_send_cmd_status(mvm, hcmd, &status); 447 448 if (!err && status) { 449 IWL_ERR(mvm, "FTM range request command failure, status: %u\n", 450 status); 451 err = iwl_ftm_range_request_status_to_err(status); 452 } 453 454 return err; 455 } 456 457 static int iwl_mvm_ftm_start_v5(struct iwl_mvm *mvm, struct ieee80211_vif *vif, 458 struct cfg80211_pmsr_request *req) 459 { 460 struct iwl_tof_range_req_cmd_v5 cmd_v5; 461 struct iwl_host_cmd hcmd = { 462 .id = iwl_cmd_id(TOF_RANGE_REQ_CMD, LOCATION_GROUP, 0), 463 .dataflags[0] = IWL_HCMD_DFL_DUP, 464 .data[0] = &cmd_v5, 465 .len[0] = sizeof(cmd_v5), 466 }; 467 u8 i; 468 int err; 469 470 iwl_mvm_ftm_cmd_v5(mvm, vif, &cmd_v5, req); 471 472 for (i = 0; i < cmd_v5.num_of_ap; i++) { 473 struct cfg80211_pmsr_request_peer *peer = &req->peers[i]; 474 475 err = iwl_mvm_ftm_put_target_v2(mvm, peer, &cmd_v5.ap[i]); 476 if (err) 477 return err; 478 } 479 480 return iwl_mvm_ftm_send_cmd(mvm, &hcmd); 481 } 482 483 static int iwl_mvm_ftm_start_v7(struct iwl_mvm *mvm, struct ieee80211_vif *vif, 484 struct cfg80211_pmsr_request *req) 485 { 486 struct iwl_tof_range_req_cmd_v7 cmd_v7; 487 struct iwl_host_cmd hcmd = { 488 .id = iwl_cmd_id(TOF_RANGE_REQ_CMD, LOCATION_GROUP, 0), 489 .dataflags[0] = IWL_HCMD_DFL_DUP, 490 .data[0] = &cmd_v7, 491 .len[0] = sizeof(cmd_v7), 492 }; 493 u8 i; 494 int err; 495 496 /* 497 * Versions 7 and 8 has the same structure except from the responders 498 * list, so iwl_mvm_ftm_cmd() can be used for version 7 too. 499 */ 500 iwl_mvm_ftm_cmd_v8(mvm, vif, (void *)&cmd_v7, req); 501 502 for (i = 0; i < cmd_v7.num_of_ap; i++) { 503 struct cfg80211_pmsr_request_peer *peer = &req->peers[i]; 504 505 err = iwl_mvm_ftm_put_target_v3(mvm, peer, &cmd_v7.ap[i]); 506 if (err) 507 return err; 508 } 509 510 return iwl_mvm_ftm_send_cmd(mvm, &hcmd); 511 } 512 513 static int iwl_mvm_ftm_start_v8(struct iwl_mvm *mvm, struct ieee80211_vif *vif, 514 struct cfg80211_pmsr_request *req) 515 { 516 struct iwl_tof_range_req_cmd_v8 cmd; 517 struct iwl_host_cmd hcmd = { 518 .id = iwl_cmd_id(TOF_RANGE_REQ_CMD, LOCATION_GROUP, 0), 519 .dataflags[0] = IWL_HCMD_DFL_DUP, 520 .data[0] = &cmd, 521 .len[0] = sizeof(cmd), 522 }; 523 u8 i; 524 int err; 525 526 iwl_mvm_ftm_cmd_v8(mvm, vif, (void *)&cmd, req); 527 528 for (i = 0; i < cmd.num_of_ap; i++) { 529 struct cfg80211_pmsr_request_peer *peer = &req->peers[i]; 530 531 err = iwl_mvm_ftm_put_target_v4(mvm, peer, &cmd.ap[i]); 532 if (err) 533 return err; 534 } 535 536 return iwl_mvm_ftm_send_cmd(mvm, &hcmd); 537 } 538 539 static int iwl_mvm_ftm_start_v9(struct iwl_mvm *mvm, struct ieee80211_vif *vif, 540 struct cfg80211_pmsr_request *req) 541 { 542 struct iwl_tof_range_req_cmd cmd; 543 struct iwl_host_cmd hcmd = { 544 .id = iwl_cmd_id(TOF_RANGE_REQ_CMD, LOCATION_GROUP, 0), 545 .dataflags[0] = IWL_HCMD_DFL_DUP, 546 .data[0] = &cmd, 547 .len[0] = sizeof(cmd), 548 }; 549 u8 i; 550 int err; 551 552 iwl_mvm_ftm_cmd_common(mvm, vif, &cmd, req); 553 554 for (i = 0; i < cmd.num_of_ap; i++) { 555 struct cfg80211_pmsr_request_peer *peer = &req->peers[i]; 556 struct iwl_tof_range_req_ap_entry *target = &cmd.ap[i]; 557 558 err = iwl_mvm_ftm_put_target(mvm, vif, peer, target); 559 if (err) 560 return err; 561 } 562 563 return iwl_mvm_ftm_send_cmd(mvm, &hcmd); 564 } 565 566 int iwl_mvm_ftm_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, 567 struct cfg80211_pmsr_request *req) 568 { 569 bool new_api = fw_has_api(&mvm->fw->ucode_capa, 570 IWL_UCODE_TLV_API_FTM_NEW_RANGE_REQ); 571 int err; 572 573 lockdep_assert_held(&mvm->mutex); 574 575 if (mvm->ftm_initiator.req) 576 return -EBUSY; 577 578 if (new_api) { 579 u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, LOCATION_GROUP, 580 TOF_RANGE_REQ_CMD); 581 582 switch (cmd_ver) { 583 case 9: 584 case 10: 585 err = iwl_mvm_ftm_start_v9(mvm, vif, req); 586 break; 587 case 8: 588 err = iwl_mvm_ftm_start_v8(mvm, vif, req); 589 break; 590 default: 591 err = iwl_mvm_ftm_start_v7(mvm, vif, req); 592 break; 593 } 594 } else { 595 err = iwl_mvm_ftm_start_v5(mvm, vif, req); 596 } 597 598 if (!err) { 599 mvm->ftm_initiator.req = req; 600 mvm->ftm_initiator.req_wdev = ieee80211_vif_to_wdev(vif); 601 } 602 603 return err; 604 } 605 606 void iwl_mvm_ftm_abort(struct iwl_mvm *mvm, struct cfg80211_pmsr_request *req) 607 { 608 struct iwl_tof_range_abort_cmd cmd = { 609 .request_id = req->cookie, 610 }; 611 612 lockdep_assert_held(&mvm->mutex); 613 614 if (req != mvm->ftm_initiator.req) 615 return; 616 617 iwl_mvm_ftm_reset(mvm); 618 619 if (iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(TOF_RANGE_ABORT_CMD, 620 LOCATION_GROUP, 0), 621 0, sizeof(cmd), &cmd)) 622 IWL_ERR(mvm, "failed to abort FTM process\n"); 623 } 624 625 static int iwl_mvm_ftm_find_peer(struct cfg80211_pmsr_request *req, 626 const u8 *addr) 627 { 628 int i; 629 630 for (i = 0; i < req->n_peers; i++) { 631 struct cfg80211_pmsr_request_peer *peer = &req->peers[i]; 632 633 if (ether_addr_equal_unaligned(peer->addr, addr)) 634 return i; 635 } 636 637 return -ENOENT; 638 } 639 640 static u64 iwl_mvm_ftm_get_host_time(struct iwl_mvm *mvm, __le32 fw_gp2_ts) 641 { 642 u32 gp2_ts = le32_to_cpu(fw_gp2_ts); 643 u32 curr_gp2, diff; 644 u64 now_from_boot_ns; 645 646 iwl_mvm_get_sync_time(mvm, &curr_gp2, &now_from_boot_ns); 647 648 if (curr_gp2 >= gp2_ts) 649 diff = curr_gp2 - gp2_ts; 650 else 651 diff = curr_gp2 + (U32_MAX - gp2_ts + 1); 652 653 return now_from_boot_ns - (u64)diff * 1000; 654 } 655 656 static void iwl_mvm_ftm_get_lci_civic(struct iwl_mvm *mvm, 657 struct cfg80211_pmsr_result *res) 658 { 659 struct iwl_mvm_loc_entry *entry; 660 661 list_for_each_entry(entry, &mvm->ftm_initiator.loc_list, list) { 662 if (!ether_addr_equal_unaligned(res->addr, entry->addr)) 663 continue; 664 665 if (entry->lci_len) { 666 res->ftm.lci_len = entry->lci_len; 667 res->ftm.lci = entry->buf; 668 } 669 670 if (entry->civic_len) { 671 res->ftm.civicloc_len = entry->civic_len; 672 res->ftm.civicloc = entry->buf + entry->lci_len; 673 } 674 675 /* we found the entry we needed */ 676 break; 677 } 678 } 679 680 static int iwl_mvm_ftm_range_resp_valid(struct iwl_mvm *mvm, u8 request_id, 681 u8 num_of_aps) 682 { 683 lockdep_assert_held(&mvm->mutex); 684 685 if (request_id != (u8)mvm->ftm_initiator.req->cookie) { 686 IWL_ERR(mvm, "Request ID mismatch, got %u, active %u\n", 687 request_id, (u8)mvm->ftm_initiator.req->cookie); 688 return -EINVAL; 689 } 690 691 if (num_of_aps > mvm->ftm_initiator.req->n_peers) { 692 IWL_ERR(mvm, "FTM range response invalid\n"); 693 return -EINVAL; 694 } 695 696 return 0; 697 } 698 699 static void iwl_mvm_debug_range_resp(struct iwl_mvm *mvm, u8 index, 700 struct cfg80211_pmsr_result *res) 701 { 702 s64 rtt_avg = div_s64(res->ftm.rtt_avg * 100, 6666); 703 704 IWL_DEBUG_INFO(mvm, "entry %d\n", index); 705 IWL_DEBUG_INFO(mvm, "\tstatus: %d\n", res->status); 706 IWL_DEBUG_INFO(mvm, "\tBSSID: %pM\n", res->addr); 707 IWL_DEBUG_INFO(mvm, "\thost time: %llu\n", res->host_time); 708 IWL_DEBUG_INFO(mvm, "\tburst index: %hhu\n", res->ftm.burst_index); 709 IWL_DEBUG_INFO(mvm, "\tsuccess num: %u\n", res->ftm.num_ftmr_successes); 710 IWL_DEBUG_INFO(mvm, "\trssi: %d\n", res->ftm.rssi_avg); 711 IWL_DEBUG_INFO(mvm, "\trssi spread: %hhu\n", res->ftm.rssi_spread); 712 IWL_DEBUG_INFO(mvm, "\trtt: %lld\n", res->ftm.rtt_avg); 713 IWL_DEBUG_INFO(mvm, "\trtt var: %llu\n", res->ftm.rtt_variance); 714 IWL_DEBUG_INFO(mvm, "\trtt spread: %llu\n", res->ftm.rtt_spread); 715 IWL_DEBUG_INFO(mvm, "\tdistance: %lld\n", rtt_avg); 716 } 717 718 void iwl_mvm_ftm_range_resp(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) 719 { 720 struct iwl_rx_packet *pkt = rxb_addr(rxb); 721 struct iwl_tof_range_rsp_ntfy_v5 *fw_resp_v5 = (void *)pkt->data; 722 struct iwl_tof_range_rsp_ntfy_v6 *fw_resp_v6 = (void *)pkt->data; 723 struct iwl_tof_range_rsp_ntfy *fw_resp = (void *)pkt->data; 724 int i; 725 bool new_api = fw_has_api(&mvm->fw->ucode_capa, 726 IWL_UCODE_TLV_API_FTM_NEW_RANGE_REQ); 727 u8 num_of_aps, last_in_batch; 728 729 lockdep_assert_held(&mvm->mutex); 730 731 if (!mvm->ftm_initiator.req) { 732 return; 733 } 734 735 if (new_api) { 736 if (iwl_mvm_ftm_range_resp_valid(mvm, fw_resp->request_id, 737 fw_resp->num_of_aps)) 738 return; 739 740 num_of_aps = fw_resp->num_of_aps; 741 last_in_batch = fw_resp->last_report; 742 } else { 743 if (iwl_mvm_ftm_range_resp_valid(mvm, fw_resp_v5->request_id, 744 fw_resp_v5->num_of_aps)) 745 return; 746 747 num_of_aps = fw_resp_v5->num_of_aps; 748 last_in_batch = fw_resp_v5->last_in_batch; 749 } 750 751 IWL_DEBUG_INFO(mvm, "Range response received\n"); 752 IWL_DEBUG_INFO(mvm, "request id: %lld, num of entries: %hhu\n", 753 mvm->ftm_initiator.req->cookie, num_of_aps); 754 755 for (i = 0; i < num_of_aps && i < IWL_MVM_TOF_MAX_APS; i++) { 756 struct cfg80211_pmsr_result result = {}; 757 struct iwl_tof_range_rsp_ap_entry_ntfy *fw_ap; 758 int peer_idx; 759 760 if (new_api) { 761 if (fw_has_api(&mvm->fw->ucode_capa, 762 IWL_UCODE_TLV_API_FTM_RTT_ACCURACY)) 763 fw_ap = &fw_resp->ap[i]; 764 else 765 fw_ap = (void *)&fw_resp_v6->ap[i]; 766 767 result.final = fw_resp->ap[i].last_burst; 768 result.ap_tsf = le32_to_cpu(fw_ap->start_tsf); 769 result.ap_tsf_valid = 1; 770 } else { 771 /* the first part is the same for old and new APIs */ 772 fw_ap = (void *)&fw_resp_v5->ap[i]; 773 /* 774 * FIXME: the firmware needs to report this, we don't 775 * even know the number of bursts the responder picked 776 * (if we asked it to) 777 */ 778 result.final = 0; 779 } 780 781 peer_idx = iwl_mvm_ftm_find_peer(mvm->ftm_initiator.req, 782 fw_ap->bssid); 783 if (peer_idx < 0) { 784 IWL_WARN(mvm, 785 "Unknown address (%pM, target #%d) in FTM response\n", 786 fw_ap->bssid, i); 787 continue; 788 } 789 790 switch (fw_ap->measure_status) { 791 case IWL_TOF_ENTRY_SUCCESS: 792 result.status = NL80211_PMSR_STATUS_SUCCESS; 793 break; 794 case IWL_TOF_ENTRY_TIMING_MEASURE_TIMEOUT: 795 result.status = NL80211_PMSR_STATUS_TIMEOUT; 796 break; 797 case IWL_TOF_ENTRY_NO_RESPONSE: 798 result.status = NL80211_PMSR_STATUS_FAILURE; 799 result.ftm.failure_reason = 800 NL80211_PMSR_FTM_FAILURE_NO_RESPONSE; 801 break; 802 case IWL_TOF_ENTRY_REQUEST_REJECTED: 803 result.status = NL80211_PMSR_STATUS_FAILURE; 804 result.ftm.failure_reason = 805 NL80211_PMSR_FTM_FAILURE_PEER_BUSY; 806 result.ftm.busy_retry_time = fw_ap->refusal_period; 807 break; 808 default: 809 result.status = NL80211_PMSR_STATUS_FAILURE; 810 result.ftm.failure_reason = 811 NL80211_PMSR_FTM_FAILURE_UNSPECIFIED; 812 break; 813 } 814 memcpy(result.addr, fw_ap->bssid, ETH_ALEN); 815 result.host_time = iwl_mvm_ftm_get_host_time(mvm, 816 fw_ap->timestamp); 817 result.type = NL80211_PMSR_TYPE_FTM; 818 result.ftm.burst_index = mvm->ftm_initiator.responses[peer_idx]; 819 mvm->ftm_initiator.responses[peer_idx]++; 820 result.ftm.rssi_avg = fw_ap->rssi; 821 result.ftm.rssi_avg_valid = 1; 822 result.ftm.rssi_spread = fw_ap->rssi_spread; 823 result.ftm.rssi_spread_valid = 1; 824 result.ftm.rtt_avg = (s32)le32_to_cpu(fw_ap->rtt); 825 result.ftm.rtt_avg_valid = 1; 826 result.ftm.rtt_variance = le32_to_cpu(fw_ap->rtt_variance); 827 result.ftm.rtt_variance_valid = 1; 828 result.ftm.rtt_spread = le32_to_cpu(fw_ap->rtt_spread); 829 result.ftm.rtt_spread_valid = 1; 830 831 iwl_mvm_ftm_get_lci_civic(mvm, &result); 832 833 cfg80211_pmsr_report(mvm->ftm_initiator.req_wdev, 834 mvm->ftm_initiator.req, 835 &result, GFP_KERNEL); 836 837 if (fw_has_api(&mvm->fw->ucode_capa, 838 IWL_UCODE_TLV_API_FTM_RTT_ACCURACY)) 839 IWL_DEBUG_INFO(mvm, "RTT confidence: %hhu\n", 840 fw_ap->rttConfidence); 841 842 iwl_mvm_debug_range_resp(mvm, i, &result); 843 } 844 845 if (last_in_batch) { 846 cfg80211_pmsr_complete(mvm->ftm_initiator.req_wdev, 847 mvm->ftm_initiator.req, 848 GFP_KERNEL); 849 iwl_mvm_ftm_reset(mvm); 850 } 851 } 852 853 void iwl_mvm_ftm_lc_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) 854 { 855 struct iwl_rx_packet *pkt = rxb_addr(rxb); 856 const struct ieee80211_mgmt *mgmt = (void *)pkt->data; 857 size_t len = iwl_rx_packet_payload_len(pkt); 858 struct iwl_mvm_loc_entry *entry; 859 const u8 *ies, *lci, *civic, *msr_ie; 860 size_t ies_len, lci_len = 0, civic_len = 0; 861 size_t baselen = IEEE80211_MIN_ACTION_SIZE + 862 sizeof(mgmt->u.action.u.ftm); 863 static const u8 rprt_type_lci = IEEE80211_SPCT_MSR_RPRT_TYPE_LCI; 864 static const u8 rprt_type_civic = IEEE80211_SPCT_MSR_RPRT_TYPE_CIVIC; 865 866 if (len <= baselen) 867 return; 868 869 lockdep_assert_held(&mvm->mutex); 870 871 ies = mgmt->u.action.u.ftm.variable; 872 ies_len = len - baselen; 873 874 msr_ie = cfg80211_find_ie_match(WLAN_EID_MEASURE_REPORT, ies, ies_len, 875 &rprt_type_lci, 1, 4); 876 if (msr_ie) { 877 lci = msr_ie + 2; 878 lci_len = msr_ie[1]; 879 } 880 881 msr_ie = cfg80211_find_ie_match(WLAN_EID_MEASURE_REPORT, ies, ies_len, 882 &rprt_type_civic, 1, 4); 883 if (msr_ie) { 884 civic = msr_ie + 2; 885 civic_len = msr_ie[1]; 886 } 887 888 entry = kmalloc(sizeof(*entry) + lci_len + civic_len, GFP_KERNEL); 889 if (!entry) 890 return; 891 892 memcpy(entry->addr, mgmt->bssid, ETH_ALEN); 893 894 entry->lci_len = lci_len; 895 if (lci_len) 896 memcpy(entry->buf, lci, lci_len); 897 898 entry->civic_len = civic_len; 899 if (civic_len) 900 memcpy(entry->buf + lci_len, civic, civic_len); 901 902 list_add_tail(&entry->list, &mvm->ftm_initiator.loc_list); 903 } 904