root/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. iwl_mvm_ftm_reset
  2. iwl_mvm_ftm_restart
  3. iwl_ftm_range_request_status_to_err
  4. iwl_mvm_ftm_cmd_v5
  5. iwl_mvm_ftm_cmd
  6. iwl_mvm_ftm_target_chandef
  7. iwl_mvm_ftm_put_target_v2
  8. iwl_mvm_ftm_put_target
  9. iwl_mvm_ftm_start
  10. iwl_mvm_ftm_abort
  11. iwl_mvm_ftm_find_peer
  12. iwl_mvm_ftm_get_host_time
  13. iwl_mvm_ftm_get_lci_civic
  14. iwl_mvm_ftm_range_resp_valid
  15. iwl_mvm_debug_range_resp
  16. iwl_mvm_ftm_range_resp
  17. iwl_mvm_ftm_lc_notif

   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 iwl_mvm_ftm_target_chandef(struct iwl_mvm *mvm,
 214                                       struct cfg80211_pmsr_request_peer *peer,
 215                                       u8 *channel, u8 *bandwidth,
 216                                       u8 *ctrl_ch_position)
 217 {
 218         u32 freq = peer->chandef.chan->center_freq;
 219 
 220         *channel = ieee80211_frequency_to_channel(freq);
 221 
 222         switch (peer->chandef.width) {
 223         case NL80211_CHAN_WIDTH_20_NOHT:
 224                 *bandwidth = IWL_TOF_BW_20_LEGACY;
 225                 break;
 226         case NL80211_CHAN_WIDTH_20:
 227                 *bandwidth = IWL_TOF_BW_20_HT;
 228                 break;
 229         case NL80211_CHAN_WIDTH_40:
 230                 *bandwidth = IWL_TOF_BW_40;
 231                 break;
 232         case NL80211_CHAN_WIDTH_80:
 233                 *bandwidth = IWL_TOF_BW_80;
 234                 break;
 235         default:
 236                 IWL_ERR(mvm, "Unsupported BW in FTM request (%d)\n",
 237                         peer->chandef.width);
 238                 return -EINVAL;
 239         }
 240 
 241         *ctrl_ch_position = (peer->chandef.width > NL80211_CHAN_WIDTH_20) ?
 242                 iwl_mvm_get_ctrl_pos(&peer->chandef) : 0;
 243 
 244         return 0;
 245 }
 246 
 247 static int
 248 iwl_mvm_ftm_put_target_v2(struct iwl_mvm *mvm,
 249                           struct cfg80211_pmsr_request_peer *peer,
 250                           struct iwl_tof_range_req_ap_entry_v2 *target)
 251 {
 252         int ret;
 253 
 254         ret = iwl_mvm_ftm_target_chandef(mvm, peer, &target->channel_num,
 255                                          &target->bandwidth,
 256                                          &target->ctrl_ch_position);
 257         if (ret)
 258                 return ret;
 259 
 260         memcpy(target->bssid, peer->addr, ETH_ALEN);
 261         target->burst_period =
 262                 cpu_to_le16(peer->ftm.burst_period);
 263         target->samples_per_burst = peer->ftm.ftms_per_burst;
 264         target->num_of_bursts = peer->ftm.num_bursts_exp;
 265         target->measure_type = 0; /* regular two-sided FTM */
 266         target->retries_per_sample = peer->ftm.ftmr_retries;
 267         target->asap_mode = peer->ftm.asap;
 268         target->enable_dyn_ack = IWL_MVM_FTM_INITIATOR_DYNACK;
 269 
 270         if (peer->ftm.request_lci)
 271                 target->location_req |= IWL_TOF_LOC_LCI;
 272         if (peer->ftm.request_civicloc)
 273                 target->location_req |= IWL_TOF_LOC_CIVIC;
 274 
 275         target->algo_type = IWL_MVM_FTM_INITIATOR_ALGO;
 276 
 277         return 0;
 278 }
 279 
 280 #define FTM_PUT_FLAG(flag)      (target->initiator_ap_flags |= \
 281                                  cpu_to_le32(IWL_INITIATOR_AP_FLAGS_##flag))
 282 
 283 static int iwl_mvm_ftm_put_target(struct iwl_mvm *mvm,
 284                                   struct cfg80211_pmsr_request_peer *peer,
 285                                   struct iwl_tof_range_req_ap_entry *target)
 286 {
 287         int ret;
 288 
 289         ret = iwl_mvm_ftm_target_chandef(mvm, peer, &target->channel_num,
 290                                          &target->bandwidth,
 291                                          &target->ctrl_ch_position);
 292         if (ret)
 293                 return ret;
 294 
 295         memcpy(target->bssid, peer->addr, ETH_ALEN);
 296         target->burst_period =
 297                 cpu_to_le16(peer->ftm.burst_period);
 298         target->samples_per_burst = peer->ftm.ftms_per_burst;
 299         target->num_of_bursts = peer->ftm.num_bursts_exp;
 300         target->ftmr_max_retries = peer->ftm.ftmr_retries;
 301         target->initiator_ap_flags = cpu_to_le32(0);
 302 
 303         if (peer->ftm.asap)
 304                 FTM_PUT_FLAG(ASAP);
 305 
 306         if (peer->ftm.request_lci)
 307                 FTM_PUT_FLAG(LCI_REQUEST);
 308 
 309         if (peer->ftm.request_civicloc)
 310                 FTM_PUT_FLAG(CIVIC_REQUEST);
 311 
 312         if (IWL_MVM_FTM_INITIATOR_DYNACK)
 313                 FTM_PUT_FLAG(DYN_ACK);
 314 
 315         if (IWL_MVM_FTM_INITIATOR_ALGO == IWL_TOF_ALGO_TYPE_LINEAR_REG)
 316                 FTM_PUT_FLAG(ALGO_LR);
 317         else if (IWL_MVM_FTM_INITIATOR_ALGO == IWL_TOF_ALGO_TYPE_FFT)
 318                 FTM_PUT_FLAG(ALGO_FFT);
 319 
 320         return 0;
 321 }
 322 
 323 int iwl_mvm_ftm_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
 324                       struct cfg80211_pmsr_request *req)
 325 {
 326         struct iwl_tof_range_req_cmd_v5 cmd_v5;
 327         struct iwl_tof_range_req_cmd cmd;
 328         bool new_api = fw_has_api(&mvm->fw->ucode_capa,
 329                                   IWL_UCODE_TLV_API_FTM_NEW_RANGE_REQ);
 330         u8 num_of_ap;
 331         struct iwl_host_cmd hcmd = {
 332                 .id = iwl_cmd_id(TOF_RANGE_REQ_CMD, LOCATION_GROUP, 0),
 333                 .dataflags[0] = IWL_HCMD_DFL_DUP,
 334         };
 335         u32 status = 0;
 336         int err, i;
 337 
 338         lockdep_assert_held(&mvm->mutex);
 339 
 340         if (mvm->ftm_initiator.req)
 341                 return -EBUSY;
 342 
 343         if (new_api) {
 344                 iwl_mvm_ftm_cmd(mvm, vif, &cmd, req);
 345                 hcmd.data[0] = &cmd;
 346                 hcmd.len[0] = sizeof(cmd);
 347                 num_of_ap = cmd.num_of_ap;
 348         } else {
 349                 iwl_mvm_ftm_cmd_v5(mvm, vif, &cmd_v5, req);
 350                 hcmd.data[0] = &cmd_v5;
 351                 hcmd.len[0] = sizeof(cmd_v5);
 352                 num_of_ap = cmd_v5.num_of_ap;
 353         }
 354 
 355         for (i = 0; i < num_of_ap; i++) {
 356                 struct cfg80211_pmsr_request_peer *peer = &req->peers[i];
 357 
 358                 if (new_api)
 359                         err = iwl_mvm_ftm_put_target(mvm, peer, &cmd.ap[i]);
 360                 else
 361                         err = iwl_mvm_ftm_put_target_v2(mvm, peer,
 362                                                         &cmd_v5.ap[i]);
 363 
 364                 if (err)
 365                         return err;
 366         }
 367 
 368         err = iwl_mvm_send_cmd_status(mvm, &hcmd, &status);
 369         if (!err && status) {
 370                 IWL_ERR(mvm, "FTM range request command failure, status: %u\n",
 371                         status);
 372                 err = iwl_ftm_range_request_status_to_err(status);
 373         }
 374 
 375         if (!err) {
 376                 mvm->ftm_initiator.req = req;
 377                 mvm->ftm_initiator.req_wdev = ieee80211_vif_to_wdev(vif);
 378         }
 379 
 380         return err;
 381 }
 382 
 383 void iwl_mvm_ftm_abort(struct iwl_mvm *mvm, struct cfg80211_pmsr_request *req)
 384 {
 385         struct iwl_tof_range_abort_cmd cmd = {
 386                 .request_id = req->cookie,
 387         };
 388 
 389         lockdep_assert_held(&mvm->mutex);
 390 
 391         if (req != mvm->ftm_initiator.req)
 392                 return;
 393 
 394         iwl_mvm_ftm_reset(mvm);
 395 
 396         if (iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(TOF_RANGE_ABORT_CMD,
 397                                                  LOCATION_GROUP, 0),
 398                                  0, sizeof(cmd), &cmd))
 399                 IWL_ERR(mvm, "failed to abort FTM process\n");
 400 }
 401 
 402 static int iwl_mvm_ftm_find_peer(struct cfg80211_pmsr_request *req,
 403                                  const u8 *addr)
 404 {
 405         int i;
 406 
 407         for (i = 0; i < req->n_peers; i++) {
 408                 struct cfg80211_pmsr_request_peer *peer = &req->peers[i];
 409 
 410                 if (ether_addr_equal_unaligned(peer->addr, addr))
 411                         return i;
 412         }
 413 
 414         return -ENOENT;
 415 }
 416 
 417 static u64 iwl_mvm_ftm_get_host_time(struct iwl_mvm *mvm, __le32 fw_gp2_ts)
 418 {
 419         u32 gp2_ts = le32_to_cpu(fw_gp2_ts);
 420         u32 curr_gp2, diff;
 421         u64 now_from_boot_ns;
 422 
 423         iwl_mvm_get_sync_time(mvm, &curr_gp2, &now_from_boot_ns);
 424 
 425         if (curr_gp2 >= gp2_ts)
 426                 diff = curr_gp2 - gp2_ts;
 427         else
 428                 diff = curr_gp2 + (U32_MAX - gp2_ts + 1);
 429 
 430         return now_from_boot_ns - (u64)diff * 1000;
 431 }
 432 
 433 static void iwl_mvm_ftm_get_lci_civic(struct iwl_mvm *mvm,
 434                                       struct cfg80211_pmsr_result *res)
 435 {
 436         struct iwl_mvm_loc_entry *entry;
 437 
 438         list_for_each_entry(entry, &mvm->ftm_initiator.loc_list, list) {
 439                 if (!ether_addr_equal_unaligned(res->addr, entry->addr))
 440                         continue;
 441 
 442                 if (entry->lci_len) {
 443                         res->ftm.lci_len = entry->lci_len;
 444                         res->ftm.lci = entry->buf;
 445                 }
 446 
 447                 if (entry->civic_len) {
 448                         res->ftm.civicloc_len = entry->civic_len;
 449                         res->ftm.civicloc = entry->buf + entry->lci_len;
 450                 }
 451 
 452                 /* we found the entry we needed */
 453                 break;
 454         }
 455 }
 456 
 457 static int iwl_mvm_ftm_range_resp_valid(struct iwl_mvm *mvm, u8 request_id,
 458                                         u8 num_of_aps)
 459 {
 460         lockdep_assert_held(&mvm->mutex);
 461 
 462         if (request_id != (u8)mvm->ftm_initiator.req->cookie) {
 463                 IWL_ERR(mvm, "Request ID mismatch, got %u, active %u\n",
 464                         request_id, (u8)mvm->ftm_initiator.req->cookie);
 465                 return -EINVAL;
 466         }
 467 
 468         if (num_of_aps > mvm->ftm_initiator.req->n_peers) {
 469                 IWL_ERR(mvm, "FTM range response invalid\n");
 470                 return -EINVAL;
 471         }
 472 
 473         return 0;
 474 }
 475 
 476 static void iwl_mvm_debug_range_resp(struct iwl_mvm *mvm, u8 index,
 477                                      struct cfg80211_pmsr_result *res)
 478 {
 479         s64 rtt_avg = div_s64(res->ftm.rtt_avg * 100, 6666);
 480 
 481         IWL_DEBUG_INFO(mvm, "entry %d\n", index);
 482         IWL_DEBUG_INFO(mvm, "\tstatus: %d\n", res->status);
 483         IWL_DEBUG_INFO(mvm, "\tBSSID: %pM\n", res->addr);
 484         IWL_DEBUG_INFO(mvm, "\thost time: %llu\n", res->host_time);
 485         IWL_DEBUG_INFO(mvm, "\tburst index: %hhu\n", res->ftm.burst_index);
 486         IWL_DEBUG_INFO(mvm, "\tsuccess num: %u\n", res->ftm.num_ftmr_successes);
 487         IWL_DEBUG_INFO(mvm, "\trssi: %d\n", res->ftm.rssi_avg);
 488         IWL_DEBUG_INFO(mvm, "\trssi spread: %hhu\n", res->ftm.rssi_spread);
 489         IWL_DEBUG_INFO(mvm, "\trtt: %lld\n", res->ftm.rtt_avg);
 490         IWL_DEBUG_INFO(mvm, "\trtt var: %llu\n", res->ftm.rtt_variance);
 491         IWL_DEBUG_INFO(mvm, "\trtt spread: %llu\n", res->ftm.rtt_spread);
 492         IWL_DEBUG_INFO(mvm, "\tdistance: %lld\n", rtt_avg);
 493 }
 494 
 495 void iwl_mvm_ftm_range_resp(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
 496 {
 497         struct iwl_rx_packet *pkt = rxb_addr(rxb);
 498         struct iwl_tof_range_rsp_ntfy_v5 *fw_resp_v5 = (void *)pkt->data;
 499         struct iwl_tof_range_rsp_ntfy_v6 *fw_resp_v6 = (void *)pkt->data;
 500         struct iwl_tof_range_rsp_ntfy *fw_resp = (void *)pkt->data;
 501         int i;
 502         bool new_api = fw_has_api(&mvm->fw->ucode_capa,
 503                                   IWL_UCODE_TLV_API_FTM_NEW_RANGE_REQ);
 504         u8 num_of_aps, last_in_batch;
 505 
 506         lockdep_assert_held(&mvm->mutex);
 507 
 508         if (!mvm->ftm_initiator.req) {
 509                 return;
 510         }
 511 
 512         if (new_api) {
 513                 if (iwl_mvm_ftm_range_resp_valid(mvm, fw_resp->request_id,
 514                                                  fw_resp->num_of_aps))
 515                         return;
 516 
 517                 num_of_aps = fw_resp->num_of_aps;
 518                 last_in_batch = fw_resp->last_report;
 519         } else {
 520                 if (iwl_mvm_ftm_range_resp_valid(mvm, fw_resp_v5->request_id,
 521                                                  fw_resp_v5->num_of_aps))
 522                         return;
 523 
 524                 num_of_aps = fw_resp_v5->num_of_aps;
 525                 last_in_batch = fw_resp_v5->last_in_batch;
 526         }
 527 
 528         IWL_DEBUG_INFO(mvm, "Range response received\n");
 529         IWL_DEBUG_INFO(mvm, "request id: %lld, num of entries: %hhu\n",
 530                        mvm->ftm_initiator.req->cookie, num_of_aps);
 531 
 532         for (i = 0; i < num_of_aps && i < IWL_MVM_TOF_MAX_APS; i++) {
 533                 struct cfg80211_pmsr_result result = {};
 534                 struct iwl_tof_range_rsp_ap_entry_ntfy *fw_ap;
 535                 int peer_idx;
 536 
 537                 if (new_api) {
 538                         if (fw_has_api(&mvm->fw->ucode_capa,
 539                                        IWL_UCODE_TLV_API_FTM_RTT_ACCURACY))
 540                                 fw_ap = &fw_resp->ap[i];
 541                         else
 542                                 fw_ap = (void *)&fw_resp_v6->ap[i];
 543 
 544                         result.final = fw_resp->ap[i].last_burst;
 545                         result.ap_tsf = le32_to_cpu(fw_ap->start_tsf);
 546                         result.ap_tsf_valid = 1;
 547                 } else {
 548                         /* the first part is the same for old and new APIs */
 549                         fw_ap = (void *)&fw_resp_v5->ap[i];
 550                         /*
 551                          * FIXME: the firmware needs to report this, we don't
 552                          * even know the number of bursts the responder picked
 553                          * (if we asked it to)
 554                          */
 555                         result.final = 0;
 556                 }
 557 
 558                 peer_idx = iwl_mvm_ftm_find_peer(mvm->ftm_initiator.req,
 559                                                  fw_ap->bssid);
 560                 if (peer_idx < 0) {
 561                         IWL_WARN(mvm,
 562                                  "Unknown address (%pM, target #%d) in FTM response\n",
 563                                  fw_ap->bssid, i);
 564                         continue;
 565                 }
 566 
 567                 switch (fw_ap->measure_status) {
 568                 case IWL_TOF_ENTRY_SUCCESS:
 569                         result.status = NL80211_PMSR_STATUS_SUCCESS;
 570                         break;
 571                 case IWL_TOF_ENTRY_TIMING_MEASURE_TIMEOUT:
 572                         result.status = NL80211_PMSR_STATUS_TIMEOUT;
 573                         break;
 574                 case IWL_TOF_ENTRY_NO_RESPONSE:
 575                         result.status = NL80211_PMSR_STATUS_FAILURE;
 576                         result.ftm.failure_reason =
 577                                 NL80211_PMSR_FTM_FAILURE_NO_RESPONSE;
 578                         break;
 579                 case IWL_TOF_ENTRY_REQUEST_REJECTED:
 580                         result.status = NL80211_PMSR_STATUS_FAILURE;
 581                         result.ftm.failure_reason =
 582                                 NL80211_PMSR_FTM_FAILURE_PEER_BUSY;
 583                         result.ftm.busy_retry_time = fw_ap->refusal_period;
 584                         break;
 585                 default:
 586                         result.status = NL80211_PMSR_STATUS_FAILURE;
 587                         result.ftm.failure_reason =
 588                                 NL80211_PMSR_FTM_FAILURE_UNSPECIFIED;
 589                         break;
 590                 }
 591                 memcpy(result.addr, fw_ap->bssid, ETH_ALEN);
 592                 result.host_time = iwl_mvm_ftm_get_host_time(mvm,
 593                                                              fw_ap->timestamp);
 594                 result.type = NL80211_PMSR_TYPE_FTM;
 595                 result.ftm.burst_index = mvm->ftm_initiator.responses[peer_idx];
 596                 mvm->ftm_initiator.responses[peer_idx]++;
 597                 result.ftm.rssi_avg = fw_ap->rssi;
 598                 result.ftm.rssi_avg_valid = 1;
 599                 result.ftm.rssi_spread = fw_ap->rssi_spread;
 600                 result.ftm.rssi_spread_valid = 1;
 601                 result.ftm.rtt_avg = (s32)le32_to_cpu(fw_ap->rtt);
 602                 result.ftm.rtt_avg_valid = 1;
 603                 result.ftm.rtt_variance = le32_to_cpu(fw_ap->rtt_variance);
 604                 result.ftm.rtt_variance_valid = 1;
 605                 result.ftm.rtt_spread = le32_to_cpu(fw_ap->rtt_spread);
 606                 result.ftm.rtt_spread_valid = 1;
 607 
 608                 iwl_mvm_ftm_get_lci_civic(mvm, &result);
 609 
 610                 cfg80211_pmsr_report(mvm->ftm_initiator.req_wdev,
 611                                      mvm->ftm_initiator.req,
 612                                      &result, GFP_KERNEL);
 613 
 614                 if (fw_has_api(&mvm->fw->ucode_capa,
 615                                IWL_UCODE_TLV_API_FTM_RTT_ACCURACY))
 616                         IWL_DEBUG_INFO(mvm, "RTT confidence: %hhu\n",
 617                                        fw_ap->rttConfidence);
 618 
 619                 iwl_mvm_debug_range_resp(mvm, i, &result);
 620         }
 621 
 622         if (last_in_batch) {
 623                 cfg80211_pmsr_complete(mvm->ftm_initiator.req_wdev,
 624                                        mvm->ftm_initiator.req,
 625                                        GFP_KERNEL);
 626                 iwl_mvm_ftm_reset(mvm);
 627         }
 628 }
 629 
 630 void iwl_mvm_ftm_lc_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
 631 {
 632         struct iwl_rx_packet *pkt = rxb_addr(rxb);
 633         const struct ieee80211_mgmt *mgmt = (void *)pkt->data;
 634         size_t len = iwl_rx_packet_payload_len(pkt);
 635         struct iwl_mvm_loc_entry *entry;
 636         const u8 *ies, *lci, *civic, *msr_ie;
 637         size_t ies_len, lci_len = 0, civic_len = 0;
 638         size_t baselen = IEEE80211_MIN_ACTION_SIZE +
 639                          sizeof(mgmt->u.action.u.ftm);
 640         static const u8 rprt_type_lci = IEEE80211_SPCT_MSR_RPRT_TYPE_LCI;
 641         static const u8 rprt_type_civic = IEEE80211_SPCT_MSR_RPRT_TYPE_CIVIC;
 642 
 643         if (len <= baselen)
 644                 return;
 645 
 646         lockdep_assert_held(&mvm->mutex);
 647 
 648         ies = mgmt->u.action.u.ftm.variable;
 649         ies_len = len - baselen;
 650 
 651         msr_ie = cfg80211_find_ie_match(WLAN_EID_MEASURE_REPORT, ies, ies_len,
 652                                         &rprt_type_lci, 1, 4);
 653         if (msr_ie) {
 654                 lci = msr_ie + 2;
 655                 lci_len = msr_ie[1];
 656         }
 657 
 658         msr_ie = cfg80211_find_ie_match(WLAN_EID_MEASURE_REPORT, ies, ies_len,
 659                                         &rprt_type_civic, 1, 4);
 660         if (msr_ie) {
 661                 civic = msr_ie + 2;
 662                 civic_len = msr_ie[1];
 663         }
 664 
 665         entry = kmalloc(sizeof(*entry) + lci_len + civic_len, GFP_KERNEL);
 666         if (!entry)
 667                 return;
 668 
 669         memcpy(entry->addr, mgmt->bssid, ETH_ALEN);
 670 
 671         entry->lci_len = lci_len;
 672         if (lci_len)
 673                 memcpy(entry->buf, lci, lci_len);
 674 
 675         entry->civic_len = civic_len;
 676         if (civic_len)
 677                 memcpy(entry->buf + lci_len, civic, civic_len);
 678 
 679         list_add_tail(&entry->list, &mvm->ftm_initiator.loc_list);
 680 }

/* [<][>][^][v][top][bottom][index][help] */