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