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(struct iwl_mvm *mvm, struct ieee80211_vif *vif, 168 struct iwl_tof_range_req_cmd *cmd, 169 struct cfg80211_pmsr_request *req) 170 { 171 int i; 172 173 cmd->initiator_flags = 174 cpu_to_le32(IWL_TOF_INITIATOR_FLAGS_MACADDR_RANDOM | 175 IWL_TOF_INITIATOR_FLAGS_NON_ASAP_SUPPORT); 176 cmd->request_id = req->cookie; 177 cmd->num_of_ap = req->n_peers; 178 179 /* 180 * Use a large value for "no timeout". Don't use the maximum value 181 * because of fw limitations. 182 */ 183 if (req->timeout) 184 cmd->req_timeout_ms = cpu_to_le32(req->timeout); 185 else 186 cmd->req_timeout_ms = cpu_to_le32(0xfffff); 187 188 memcpy(cmd->macaddr_template, req->mac_addr, ETH_ALEN); 189 for (i = 0; i < ETH_ALEN; i++) 190 cmd->macaddr_mask[i] = ~req->mac_addr_mask[i]; 191 192 if (vif->bss_conf.assoc) { 193 memcpy(cmd->range_req_bssid, vif->bss_conf.bssid, ETH_ALEN); 194 195 /* AP's TSF is only relevant if associated */ 196 for (i = 0; i < req->n_peers; i++) { 197 if (req->peers[i].report_ap_tsf) { 198 struct iwl_mvm_vif *mvmvif = 199 iwl_mvm_vif_from_mac80211(vif); 200 201 cmd->tsf_mac_id = cpu_to_le32(mvmvif->id); 202 return; 203 } 204 } 205 } else { 206 eth_broadcast_addr(cmd->range_req_bssid); 207 } 208 209 /* Don't report AP's TSF */ 210 cmd->tsf_mac_id = cpu_to_le32(0xff); 211 } 212 213 static int 214 iwl_mvm_ftm_target_chandef_v1(struct iwl_mvm *mvm, 215 struct cfg80211_pmsr_request_peer *peer, 216 u8 *channel, u8 *bandwidth, 217 u8 *ctrl_ch_position) 218 { 219 u32 freq = peer->chandef.chan->center_freq; 220 221 *channel = ieee80211_frequency_to_channel(freq); 222 223 switch (peer->chandef.width) { 224 case NL80211_CHAN_WIDTH_20_NOHT: 225 *bandwidth = IWL_TOF_BW_20_LEGACY; 226 break; 227 case NL80211_CHAN_WIDTH_20: 228 *bandwidth = IWL_TOF_BW_20_HT; 229 break; 230 case NL80211_CHAN_WIDTH_40: 231 *bandwidth = IWL_TOF_BW_40; 232 break; 233 case NL80211_CHAN_WIDTH_80: 234 *bandwidth = IWL_TOF_BW_80; 235 break; 236 default: 237 IWL_ERR(mvm, "Unsupported BW in FTM request (%d)\n", 238 peer->chandef.width); 239 return -EINVAL; 240 } 241 242 *ctrl_ch_position = (peer->chandef.width > NL80211_CHAN_WIDTH_20) ? 243 iwl_mvm_get_ctrl_pos(&peer->chandef) : 0; 244 245 return 0; 246 } 247 248 static int 249 iwl_mvm_ftm_target_chandef_v2(struct iwl_mvm *mvm, 250 struct cfg80211_pmsr_request_peer *peer, 251 u8 *channel, u8 *format_bw, 252 u8 *ctrl_ch_position) 253 { 254 u32 freq = peer->chandef.chan->center_freq; 255 256 *channel = ieee80211_frequency_to_channel(freq); 257 258 switch (peer->chandef.width) { 259 case NL80211_CHAN_WIDTH_20_NOHT: 260 *format_bw = IWL_LOCATION_FRAME_FORMAT_LEGACY; 261 *format_bw |= IWL_LOCATION_BW_20MHZ << LOCATION_BW_POS; 262 break; 263 case NL80211_CHAN_WIDTH_20: 264 *format_bw = IWL_LOCATION_FRAME_FORMAT_HT; 265 *format_bw |= IWL_LOCATION_BW_20MHZ << LOCATION_BW_POS; 266 break; 267 case NL80211_CHAN_WIDTH_40: 268 *format_bw = IWL_LOCATION_FRAME_FORMAT_HT; 269 *format_bw |= IWL_LOCATION_BW_40MHZ << LOCATION_BW_POS; 270 break; 271 case NL80211_CHAN_WIDTH_80: 272 *format_bw = IWL_LOCATION_FRAME_FORMAT_VHT; 273 *format_bw |= IWL_LOCATION_BW_80MHZ << LOCATION_BW_POS; 274 break; 275 default: 276 IWL_ERR(mvm, "Unsupported BW in FTM request (%d)\n", 277 peer->chandef.width); 278 return -EINVAL; 279 } 280 281 /* non EDCA based measurement must use HE preamble */ 282 if (peer->ftm.trigger_based || peer->ftm.non_trigger_based) 283 *format_bw |= IWL_LOCATION_FRAME_FORMAT_HE; 284 285 *ctrl_ch_position = (peer->chandef.width > NL80211_CHAN_WIDTH_20) ? 286 iwl_mvm_get_ctrl_pos(&peer->chandef) : 0; 287 288 return 0; 289 } 290 291 static int 292 iwl_mvm_ftm_put_target_v2(struct iwl_mvm *mvm, 293 struct cfg80211_pmsr_request_peer *peer, 294 struct iwl_tof_range_req_ap_entry_v2 *target) 295 { 296 int ret; 297 298 ret = iwl_mvm_ftm_target_chandef_v1(mvm, peer, &target->channel_num, 299 &target->bandwidth, 300 &target->ctrl_ch_position); 301 if (ret) 302 return ret; 303 304 memcpy(target->bssid, peer->addr, ETH_ALEN); 305 target->burst_period = 306 cpu_to_le16(peer->ftm.burst_period); 307 target->samples_per_burst = peer->ftm.ftms_per_burst; 308 target->num_of_bursts = peer->ftm.num_bursts_exp; 309 target->measure_type = 0; /* regular two-sided FTM */ 310 target->retries_per_sample = peer->ftm.ftmr_retries; 311 target->asap_mode = peer->ftm.asap; 312 target->enable_dyn_ack = IWL_MVM_FTM_INITIATOR_DYNACK; 313 314 if (peer->ftm.request_lci) 315 target->location_req |= IWL_TOF_LOC_LCI; 316 if (peer->ftm.request_civicloc) 317 target->location_req |= IWL_TOF_LOC_CIVIC; 318 319 target->algo_type = IWL_MVM_FTM_INITIATOR_ALGO; 320 321 return 0; 322 } 323 324 #define FTM_PUT_FLAG(flag) (target->initiator_ap_flags |= \ 325 cpu_to_le32(IWL_INITIATOR_AP_FLAGS_##flag)) 326 327 static void 328 iwl_mvm_ftm_put_target_common(struct iwl_mvm *mvm, 329 struct cfg80211_pmsr_request_peer *peer, 330 struct iwl_tof_range_req_ap_entry *target) 331 { 332 memcpy(target->bssid, peer->addr, ETH_ALEN); 333 target->burst_period = 334 cpu_to_le16(peer->ftm.burst_period); 335 target->samples_per_burst = peer->ftm.ftms_per_burst; 336 target->num_of_bursts = peer->ftm.num_bursts_exp; 337 target->ftmr_max_retries = peer->ftm.ftmr_retries; 338 target->initiator_ap_flags = cpu_to_le32(0); 339 340 if (peer->ftm.asap) 341 FTM_PUT_FLAG(ASAP); 342 343 if (peer->ftm.request_lci) 344 FTM_PUT_FLAG(LCI_REQUEST); 345 346 if (peer->ftm.request_civicloc) 347 FTM_PUT_FLAG(CIVIC_REQUEST); 348 349 if (IWL_MVM_FTM_INITIATOR_DYNACK) 350 FTM_PUT_FLAG(DYN_ACK); 351 352 if (IWL_MVM_FTM_INITIATOR_ALGO == IWL_TOF_ALGO_TYPE_LINEAR_REG) 353 FTM_PUT_FLAG(ALGO_LR); 354 else if (IWL_MVM_FTM_INITIATOR_ALGO == IWL_TOF_ALGO_TYPE_FFT) 355 FTM_PUT_FLAG(ALGO_FFT); 356 357 if (peer->ftm.trigger_based) 358 FTM_PUT_FLAG(TB); 359 else if (peer->ftm.non_trigger_based) 360 FTM_PUT_FLAG(NON_TB); 361 } 362 363 static int 364 iwl_mvm_ftm_put_target_v3(struct iwl_mvm *mvm, 365 struct cfg80211_pmsr_request_peer *peer, 366 struct iwl_tof_range_req_ap_entry_v3 *target) 367 { 368 int ret; 369 370 ret = iwl_mvm_ftm_target_chandef_v1(mvm, peer, &target->channel_num, 371 &target->bandwidth, 372 &target->ctrl_ch_position); 373 if (ret) 374 return ret; 375 376 /* 377 * Versions 3 and 4 has some common fields, so 378 * iwl_mvm_ftm_put_target_common() can be used for version 7 too. 379 */ 380 iwl_mvm_ftm_put_target_common(mvm, peer, (void *)target); 381 382 return 0; 383 } 384 385 static int iwl_mvm_ftm_put_target_v4(struct iwl_mvm *mvm, 386 struct cfg80211_pmsr_request_peer *peer, 387 struct iwl_tof_range_req_ap_entry *target) 388 { 389 int ret; 390 391 ret = iwl_mvm_ftm_target_chandef_v2(mvm, peer, &target->channel_num, 392 &target->format_bw, 393 &target->ctrl_ch_position); 394 if (ret) 395 return ret; 396 397 iwl_mvm_ftm_put_target_common(mvm, peer, target); 398 399 return 0; 400 } 401 402 static int iwl_mvm_ftm_send_cmd(struct iwl_mvm *mvm, struct iwl_host_cmd *hcmd) 403 { 404 u32 status; 405 int err = iwl_mvm_send_cmd_status(mvm, hcmd, &status); 406 407 if (!err && status) { 408 IWL_ERR(mvm, "FTM range request command failure, status: %u\n", 409 status); 410 err = iwl_ftm_range_request_status_to_err(status); 411 } 412 413 return err; 414 } 415 416 static int iwl_mvm_ftm_start_v5(struct iwl_mvm *mvm, struct ieee80211_vif *vif, 417 struct cfg80211_pmsr_request *req) 418 { 419 struct iwl_tof_range_req_cmd_v5 cmd_v5; 420 struct iwl_host_cmd hcmd = { 421 .id = iwl_cmd_id(TOF_RANGE_REQ_CMD, LOCATION_GROUP, 0), 422 .dataflags[0] = IWL_HCMD_DFL_DUP, 423 .data[0] = &cmd_v5, 424 .len[0] = sizeof(cmd_v5), 425 }; 426 u8 i; 427 int err; 428 429 iwl_mvm_ftm_cmd_v5(mvm, vif, &cmd_v5, req); 430 431 for (i = 0; i < cmd_v5.num_of_ap; i++) { 432 struct cfg80211_pmsr_request_peer *peer = &req->peers[i]; 433 434 err = iwl_mvm_ftm_put_target_v2(mvm, peer, &cmd_v5.ap[i]); 435 if (err) 436 return err; 437 } 438 439 return iwl_mvm_ftm_send_cmd(mvm, &hcmd); 440 } 441 442 static int iwl_mvm_ftm_start_v7(struct iwl_mvm *mvm, struct ieee80211_vif *vif, 443 struct cfg80211_pmsr_request *req) 444 { 445 struct iwl_tof_range_req_cmd_v7 cmd_v7; 446 struct iwl_host_cmd hcmd = { 447 .id = iwl_cmd_id(TOF_RANGE_REQ_CMD, LOCATION_GROUP, 0), 448 .dataflags[0] = IWL_HCMD_DFL_DUP, 449 .data[0] = &cmd_v7, 450 .len[0] = sizeof(cmd_v7), 451 }; 452 u8 i; 453 int err; 454 455 /* 456 * Versions 7 and 8 has the same structure except from the responders 457 * list, so iwl_mvm_ftm_cmd() can be used for version 7 too. 458 */ 459 iwl_mvm_ftm_cmd(mvm, vif, (void *)&cmd_v7, req); 460 461 for (i = 0; i < cmd_v7.num_of_ap; i++) { 462 struct cfg80211_pmsr_request_peer *peer = &req->peers[i]; 463 464 err = iwl_mvm_ftm_put_target_v3(mvm, peer, &cmd_v7.ap[i]); 465 if (err) 466 return err; 467 } 468 469 return iwl_mvm_ftm_send_cmd(mvm, &hcmd); 470 } 471 472 static int iwl_mvm_ftm_start_v8(struct iwl_mvm *mvm, struct ieee80211_vif *vif, 473 struct cfg80211_pmsr_request *req) 474 { 475 struct iwl_tof_range_req_cmd cmd; 476 struct iwl_host_cmd hcmd = { 477 .id = iwl_cmd_id(TOF_RANGE_REQ_CMD, LOCATION_GROUP, 0), 478 .dataflags[0] = IWL_HCMD_DFL_DUP, 479 .data[0] = &cmd, 480 .len[0] = sizeof(cmd), 481 }; 482 u8 i; 483 int err; 484 485 iwl_mvm_ftm_cmd(mvm, vif, &cmd, req); 486 487 for (i = 0; i < cmd.num_of_ap; i++) { 488 struct cfg80211_pmsr_request_peer *peer = &req->peers[i]; 489 490 err = iwl_mvm_ftm_put_target_v4(mvm, peer, &cmd.ap[i]); 491 if (err) 492 return err; 493 } 494 495 return iwl_mvm_ftm_send_cmd(mvm, &hcmd); 496 } 497 498 int iwl_mvm_ftm_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, 499 struct cfg80211_pmsr_request *req) 500 { 501 bool new_api = fw_has_api(&mvm->fw->ucode_capa, 502 IWL_UCODE_TLV_API_FTM_NEW_RANGE_REQ); 503 int err; 504 505 lockdep_assert_held(&mvm->mutex); 506 507 if (mvm->ftm_initiator.req) 508 return -EBUSY; 509 510 if (new_api) { 511 u8 cmd_ver = iwl_mvm_lookup_cmd_ver(mvm->fw, LOCATION_GROUP, 512 TOF_RANGE_REQ_CMD); 513 514 if (cmd_ver == 8) 515 err = iwl_mvm_ftm_start_v8(mvm, vif, req); 516 else 517 err = iwl_mvm_ftm_start_v7(mvm, vif, req); 518 519 } else { 520 err = iwl_mvm_ftm_start_v5(mvm, vif, req); 521 } 522 523 if (!err) { 524 mvm->ftm_initiator.req = req; 525 mvm->ftm_initiator.req_wdev = ieee80211_vif_to_wdev(vif); 526 } 527 528 return err; 529 } 530 531 void iwl_mvm_ftm_abort(struct iwl_mvm *mvm, struct cfg80211_pmsr_request *req) 532 { 533 struct iwl_tof_range_abort_cmd cmd = { 534 .request_id = req->cookie, 535 }; 536 537 lockdep_assert_held(&mvm->mutex); 538 539 if (req != mvm->ftm_initiator.req) 540 return; 541 542 iwl_mvm_ftm_reset(mvm); 543 544 if (iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(TOF_RANGE_ABORT_CMD, 545 LOCATION_GROUP, 0), 546 0, sizeof(cmd), &cmd)) 547 IWL_ERR(mvm, "failed to abort FTM process\n"); 548 } 549 550 static int iwl_mvm_ftm_find_peer(struct cfg80211_pmsr_request *req, 551 const u8 *addr) 552 { 553 int i; 554 555 for (i = 0; i < req->n_peers; i++) { 556 struct cfg80211_pmsr_request_peer *peer = &req->peers[i]; 557 558 if (ether_addr_equal_unaligned(peer->addr, addr)) 559 return i; 560 } 561 562 return -ENOENT; 563 } 564 565 static u64 iwl_mvm_ftm_get_host_time(struct iwl_mvm *mvm, __le32 fw_gp2_ts) 566 { 567 u32 gp2_ts = le32_to_cpu(fw_gp2_ts); 568 u32 curr_gp2, diff; 569 u64 now_from_boot_ns; 570 571 iwl_mvm_get_sync_time(mvm, &curr_gp2, &now_from_boot_ns); 572 573 if (curr_gp2 >= gp2_ts) 574 diff = curr_gp2 - gp2_ts; 575 else 576 diff = curr_gp2 + (U32_MAX - gp2_ts + 1); 577 578 return now_from_boot_ns - (u64)diff * 1000; 579 } 580 581 static void iwl_mvm_ftm_get_lci_civic(struct iwl_mvm *mvm, 582 struct cfg80211_pmsr_result *res) 583 { 584 struct iwl_mvm_loc_entry *entry; 585 586 list_for_each_entry(entry, &mvm->ftm_initiator.loc_list, list) { 587 if (!ether_addr_equal_unaligned(res->addr, entry->addr)) 588 continue; 589 590 if (entry->lci_len) { 591 res->ftm.lci_len = entry->lci_len; 592 res->ftm.lci = entry->buf; 593 } 594 595 if (entry->civic_len) { 596 res->ftm.civicloc_len = entry->civic_len; 597 res->ftm.civicloc = entry->buf + entry->lci_len; 598 } 599 600 /* we found the entry we needed */ 601 break; 602 } 603 } 604 605 static int iwl_mvm_ftm_range_resp_valid(struct iwl_mvm *mvm, u8 request_id, 606 u8 num_of_aps) 607 { 608 lockdep_assert_held(&mvm->mutex); 609 610 if (request_id != (u8)mvm->ftm_initiator.req->cookie) { 611 IWL_ERR(mvm, "Request ID mismatch, got %u, active %u\n", 612 request_id, (u8)mvm->ftm_initiator.req->cookie); 613 return -EINVAL; 614 } 615 616 if (num_of_aps > mvm->ftm_initiator.req->n_peers) { 617 IWL_ERR(mvm, "FTM range response invalid\n"); 618 return -EINVAL; 619 } 620 621 return 0; 622 } 623 624 static void iwl_mvm_debug_range_resp(struct iwl_mvm *mvm, u8 index, 625 struct cfg80211_pmsr_result *res) 626 { 627 s64 rtt_avg = div_s64(res->ftm.rtt_avg * 100, 6666); 628 629 IWL_DEBUG_INFO(mvm, "entry %d\n", index); 630 IWL_DEBUG_INFO(mvm, "\tstatus: %d\n", res->status); 631 IWL_DEBUG_INFO(mvm, "\tBSSID: %pM\n", res->addr); 632 IWL_DEBUG_INFO(mvm, "\thost time: %llu\n", res->host_time); 633 IWL_DEBUG_INFO(mvm, "\tburst index: %hhu\n", res->ftm.burst_index); 634 IWL_DEBUG_INFO(mvm, "\tsuccess num: %u\n", res->ftm.num_ftmr_successes); 635 IWL_DEBUG_INFO(mvm, "\trssi: %d\n", res->ftm.rssi_avg); 636 IWL_DEBUG_INFO(mvm, "\trssi spread: %hhu\n", res->ftm.rssi_spread); 637 IWL_DEBUG_INFO(mvm, "\trtt: %lld\n", res->ftm.rtt_avg); 638 IWL_DEBUG_INFO(mvm, "\trtt var: %llu\n", res->ftm.rtt_variance); 639 IWL_DEBUG_INFO(mvm, "\trtt spread: %llu\n", res->ftm.rtt_spread); 640 IWL_DEBUG_INFO(mvm, "\tdistance: %lld\n", rtt_avg); 641 } 642 643 void iwl_mvm_ftm_range_resp(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) 644 { 645 struct iwl_rx_packet *pkt = rxb_addr(rxb); 646 struct iwl_tof_range_rsp_ntfy_v5 *fw_resp_v5 = (void *)pkt->data; 647 struct iwl_tof_range_rsp_ntfy_v6 *fw_resp_v6 = (void *)pkt->data; 648 struct iwl_tof_range_rsp_ntfy *fw_resp = (void *)pkt->data; 649 int i; 650 bool new_api = fw_has_api(&mvm->fw->ucode_capa, 651 IWL_UCODE_TLV_API_FTM_NEW_RANGE_REQ); 652 u8 num_of_aps, last_in_batch; 653 654 lockdep_assert_held(&mvm->mutex); 655 656 if (!mvm->ftm_initiator.req) { 657 return; 658 } 659 660 if (new_api) { 661 if (iwl_mvm_ftm_range_resp_valid(mvm, fw_resp->request_id, 662 fw_resp->num_of_aps)) 663 return; 664 665 num_of_aps = fw_resp->num_of_aps; 666 last_in_batch = fw_resp->last_report; 667 } else { 668 if (iwl_mvm_ftm_range_resp_valid(mvm, fw_resp_v5->request_id, 669 fw_resp_v5->num_of_aps)) 670 return; 671 672 num_of_aps = fw_resp_v5->num_of_aps; 673 last_in_batch = fw_resp_v5->last_in_batch; 674 } 675 676 IWL_DEBUG_INFO(mvm, "Range response received\n"); 677 IWL_DEBUG_INFO(mvm, "request id: %lld, num of entries: %hhu\n", 678 mvm->ftm_initiator.req->cookie, num_of_aps); 679 680 for (i = 0; i < num_of_aps && i < IWL_MVM_TOF_MAX_APS; i++) { 681 struct cfg80211_pmsr_result result = {}; 682 struct iwl_tof_range_rsp_ap_entry_ntfy *fw_ap; 683 int peer_idx; 684 685 if (new_api) { 686 if (fw_has_api(&mvm->fw->ucode_capa, 687 IWL_UCODE_TLV_API_FTM_RTT_ACCURACY)) 688 fw_ap = &fw_resp->ap[i]; 689 else 690 fw_ap = (void *)&fw_resp_v6->ap[i]; 691 692 result.final = fw_resp->ap[i].last_burst; 693 result.ap_tsf = le32_to_cpu(fw_ap->start_tsf); 694 result.ap_tsf_valid = 1; 695 } else { 696 /* the first part is the same for old and new APIs */ 697 fw_ap = (void *)&fw_resp_v5->ap[i]; 698 /* 699 * FIXME: the firmware needs to report this, we don't 700 * even know the number of bursts the responder picked 701 * (if we asked it to) 702 */ 703 result.final = 0; 704 } 705 706 peer_idx = iwl_mvm_ftm_find_peer(mvm->ftm_initiator.req, 707 fw_ap->bssid); 708 if (peer_idx < 0) { 709 IWL_WARN(mvm, 710 "Unknown address (%pM, target #%d) in FTM response\n", 711 fw_ap->bssid, i); 712 continue; 713 } 714 715 switch (fw_ap->measure_status) { 716 case IWL_TOF_ENTRY_SUCCESS: 717 result.status = NL80211_PMSR_STATUS_SUCCESS; 718 break; 719 case IWL_TOF_ENTRY_TIMING_MEASURE_TIMEOUT: 720 result.status = NL80211_PMSR_STATUS_TIMEOUT; 721 break; 722 case IWL_TOF_ENTRY_NO_RESPONSE: 723 result.status = NL80211_PMSR_STATUS_FAILURE; 724 result.ftm.failure_reason = 725 NL80211_PMSR_FTM_FAILURE_NO_RESPONSE; 726 break; 727 case IWL_TOF_ENTRY_REQUEST_REJECTED: 728 result.status = NL80211_PMSR_STATUS_FAILURE; 729 result.ftm.failure_reason = 730 NL80211_PMSR_FTM_FAILURE_PEER_BUSY; 731 result.ftm.busy_retry_time = fw_ap->refusal_period; 732 break; 733 default: 734 result.status = NL80211_PMSR_STATUS_FAILURE; 735 result.ftm.failure_reason = 736 NL80211_PMSR_FTM_FAILURE_UNSPECIFIED; 737 break; 738 } 739 memcpy(result.addr, fw_ap->bssid, ETH_ALEN); 740 result.host_time = iwl_mvm_ftm_get_host_time(mvm, 741 fw_ap->timestamp); 742 result.type = NL80211_PMSR_TYPE_FTM; 743 result.ftm.burst_index = mvm->ftm_initiator.responses[peer_idx]; 744 mvm->ftm_initiator.responses[peer_idx]++; 745 result.ftm.rssi_avg = fw_ap->rssi; 746 result.ftm.rssi_avg_valid = 1; 747 result.ftm.rssi_spread = fw_ap->rssi_spread; 748 result.ftm.rssi_spread_valid = 1; 749 result.ftm.rtt_avg = (s32)le32_to_cpu(fw_ap->rtt); 750 result.ftm.rtt_avg_valid = 1; 751 result.ftm.rtt_variance = le32_to_cpu(fw_ap->rtt_variance); 752 result.ftm.rtt_variance_valid = 1; 753 result.ftm.rtt_spread = le32_to_cpu(fw_ap->rtt_spread); 754 result.ftm.rtt_spread_valid = 1; 755 756 iwl_mvm_ftm_get_lci_civic(mvm, &result); 757 758 cfg80211_pmsr_report(mvm->ftm_initiator.req_wdev, 759 mvm->ftm_initiator.req, 760 &result, GFP_KERNEL); 761 762 if (fw_has_api(&mvm->fw->ucode_capa, 763 IWL_UCODE_TLV_API_FTM_RTT_ACCURACY)) 764 IWL_DEBUG_INFO(mvm, "RTT confidence: %hhu\n", 765 fw_ap->rttConfidence); 766 767 iwl_mvm_debug_range_resp(mvm, i, &result); 768 } 769 770 if (last_in_batch) { 771 cfg80211_pmsr_complete(mvm->ftm_initiator.req_wdev, 772 mvm->ftm_initiator.req, 773 GFP_KERNEL); 774 iwl_mvm_ftm_reset(mvm); 775 } 776 } 777 778 void iwl_mvm_ftm_lc_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) 779 { 780 struct iwl_rx_packet *pkt = rxb_addr(rxb); 781 const struct ieee80211_mgmt *mgmt = (void *)pkt->data; 782 size_t len = iwl_rx_packet_payload_len(pkt); 783 struct iwl_mvm_loc_entry *entry; 784 const u8 *ies, *lci, *civic, *msr_ie; 785 size_t ies_len, lci_len = 0, civic_len = 0; 786 size_t baselen = IEEE80211_MIN_ACTION_SIZE + 787 sizeof(mgmt->u.action.u.ftm); 788 static const u8 rprt_type_lci = IEEE80211_SPCT_MSR_RPRT_TYPE_LCI; 789 static const u8 rprt_type_civic = IEEE80211_SPCT_MSR_RPRT_TYPE_CIVIC; 790 791 if (len <= baselen) 792 return; 793 794 lockdep_assert_held(&mvm->mutex); 795 796 ies = mgmt->u.action.u.ftm.variable; 797 ies_len = len - baselen; 798 799 msr_ie = cfg80211_find_ie_match(WLAN_EID_MEASURE_REPORT, ies, ies_len, 800 &rprt_type_lci, 1, 4); 801 if (msr_ie) { 802 lci = msr_ie + 2; 803 lci_len = msr_ie[1]; 804 } 805 806 msr_ie = cfg80211_find_ie_match(WLAN_EID_MEASURE_REPORT, ies, ies_len, 807 &rprt_type_civic, 1, 4); 808 if (msr_ie) { 809 civic = msr_ie + 2; 810 civic_len = msr_ie[1]; 811 } 812 813 entry = kmalloc(sizeof(*entry) + lci_len + civic_len, GFP_KERNEL); 814 if (!entry) 815 return; 816 817 memcpy(entry->addr, mgmt->bssid, ETH_ALEN); 818 819 entry->lci_len = lci_len; 820 if (lci_len) 821 memcpy(entry->buf, lci, lci_len); 822 823 entry->civic_len = civic_len; 824 if (civic_len) 825 memcpy(entry->buf + lci_len, civic, civic_len); 826 827 list_add_tail(&entry->list, &mvm->ftm_initiator.loc_list); 828 } 829