Linux Audio

Check our new training course

Yocto distribution development and maintenance

Need a Yocto distribution for your embedded project?
Loading...
v6.8
   1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
   2/*
   3 * Copyright (C) 2015-2017 Intel Deutschland GmbH
   4 * Copyright (C) 2018-2022 Intel Corporation
   5 */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
   6#include <linux/etherdevice.h>
   7#include <linux/math64.h>
   8#include <net/cfg80211.h>
   9#include "mvm.h"
  10#include "iwl-io.h"
  11#include "iwl-prph.h"
  12#include "constants.h"
  13
  14struct iwl_mvm_loc_entry {
  15	struct list_head list;
  16	u8 addr[ETH_ALEN];
  17	u8 lci_len, civic_len;
  18	u8 buf[];
  19};
  20
  21struct iwl_mvm_smooth_entry {
  22	struct list_head list;
  23	u8 addr[ETH_ALEN];
  24	s64 rtt_avg;
  25	u64 host_time;
  26};
  27
  28enum iwl_mvm_pasn_flags {
  29	IWL_MVM_PASN_FLAG_HAS_HLTK = BIT(0),
  30};
  31
  32struct iwl_mvm_ftm_pasn_entry {
  33	struct list_head list;
  34	u8 addr[ETH_ALEN];
  35	u8 hltk[HLTK_11AZ_LEN];
  36	u8 tk[TK_11AZ_LEN];
  37	u8 cipher;
  38	u8 tx_pn[IEEE80211_CCMP_PN_LEN];
  39	u8 rx_pn[IEEE80211_CCMP_PN_LEN];
  40	u32 flags;
  41};
  42
  43int iwl_mvm_ftm_add_pasn_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
  44			     u8 *addr, u32 cipher, u8 *tk, u32 tk_len,
  45			     u8 *hltk, u32 hltk_len)
  46{
  47	struct iwl_mvm_ftm_pasn_entry *pasn = kzalloc(sizeof(*pasn),
  48						      GFP_KERNEL);
  49	u32 expected_tk_len;
  50
  51	lockdep_assert_held(&mvm->mutex);
  52
  53	if (!pasn)
  54		return -ENOBUFS;
  55
  56	pasn->cipher = iwl_mvm_cipher_to_location_cipher(cipher);
  57
  58	switch (pasn->cipher) {
  59	case IWL_LOCATION_CIPHER_CCMP_128:
  60	case IWL_LOCATION_CIPHER_GCMP_128:
  61		expected_tk_len = WLAN_KEY_LEN_CCMP;
  62		break;
  63	case IWL_LOCATION_CIPHER_GCMP_256:
  64		expected_tk_len = WLAN_KEY_LEN_GCMP_256;
  65		break;
  66	default:
  67		goto out;
  68	}
  69
  70	/*
  71	 * If associated to this AP and already have security context,
  72	 * the TK is already configured for this station, so it
  73	 * shouldn't be set again here.
  74	 */
  75	if (vif->cfg.assoc) {
  76		struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
  77		struct ieee80211_bss_conf *link_conf;
  78		unsigned int link_id;
  79		struct ieee80211_sta *sta;
  80		u8 sta_id;
  81
  82		rcu_read_lock();
  83		for_each_vif_active_link(vif, link_conf, link_id) {
  84			if (memcmp(addr, link_conf->bssid, ETH_ALEN))
  85				continue;
  86
  87			sta_id = mvmvif->link[link_id]->ap_sta_id;
  88			sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
  89			if (!IS_ERR_OR_NULL(sta) && sta->mfp)
  90				expected_tk_len = 0;
  91			break;
  92		}
  93		rcu_read_unlock();
  94	}
  95
  96	if (tk_len != expected_tk_len ||
  97	    (hltk_len && hltk_len != sizeof(pasn->hltk))) {
  98		IWL_ERR(mvm, "Invalid key length: tk_len=%u hltk_len=%u\n",
  99			tk_len, hltk_len);
 100		goto out;
 101	}
 102
 103	if (!expected_tk_len && !hltk_len) {
 104		IWL_ERR(mvm, "TK and HLTK not set\n");
 105		goto out;
 106	}
 107
 108	memcpy(pasn->addr, addr, sizeof(pasn->addr));
 109
 110	if (hltk_len) {
 111		memcpy(pasn->hltk, hltk, sizeof(pasn->hltk));
 112		pasn->flags |= IWL_MVM_PASN_FLAG_HAS_HLTK;
 113	}
 114
 115	if (tk && tk_len)
 116		memcpy(pasn->tk, tk, sizeof(pasn->tk));
 117
 118	list_add_tail(&pasn->list, &mvm->ftm_initiator.pasn_list);
 119	return 0;
 120out:
 121	kfree(pasn);
 122	return -EINVAL;
 123}
 124
 125void iwl_mvm_ftm_remove_pasn_sta(struct iwl_mvm *mvm, u8 *addr)
 126{
 127	struct iwl_mvm_ftm_pasn_entry *entry, *prev;
 128
 129	lockdep_assert_held(&mvm->mutex);
 130
 131	list_for_each_entry_safe(entry, prev, &mvm->ftm_initiator.pasn_list,
 132				 list) {
 133		if (memcmp(entry->addr, addr, sizeof(entry->addr)))
 134			continue;
 135
 136		list_del(&entry->list);
 137		kfree(entry);
 138		return;
 139	}
 140}
 141
 142static void iwl_mvm_ftm_reset(struct iwl_mvm *mvm)
 143{
 144	struct iwl_mvm_loc_entry *e, *t;
 145
 146	mvm->ftm_initiator.req = NULL;
 147	mvm->ftm_initiator.req_wdev = NULL;
 148	memset(mvm->ftm_initiator.responses, 0,
 149	       sizeof(mvm->ftm_initiator.responses));
 150
 151	list_for_each_entry_safe(e, t, &mvm->ftm_initiator.loc_list, list) {
 152		list_del(&e->list);
 153		kfree(e);
 154	}
 155}
 156
 157void iwl_mvm_ftm_restart(struct iwl_mvm *mvm)
 158{
 159	struct cfg80211_pmsr_result result = {
 160		.status = NL80211_PMSR_STATUS_FAILURE,
 161		.final = 1,
 162		.host_time = ktime_get_boottime_ns(),
 163		.type = NL80211_PMSR_TYPE_FTM,
 164	};
 165	int i;
 166
 167	lockdep_assert_held(&mvm->mutex);
 168
 169	if (!mvm->ftm_initiator.req)
 170		return;
 171
 172	for (i = 0; i < mvm->ftm_initiator.req->n_peers; i++) {
 173		memcpy(result.addr, mvm->ftm_initiator.req->peers[i].addr,
 174		       ETH_ALEN);
 175		result.ftm.burst_index = mvm->ftm_initiator.responses[i];
 176
 177		cfg80211_pmsr_report(mvm->ftm_initiator.req_wdev,
 178				     mvm->ftm_initiator.req,
 179				     &result, GFP_KERNEL);
 180	}
 181
 182	cfg80211_pmsr_complete(mvm->ftm_initiator.req_wdev,
 183			       mvm->ftm_initiator.req, GFP_KERNEL);
 184	iwl_mvm_ftm_reset(mvm);
 185}
 186
 187void iwl_mvm_ftm_initiator_smooth_config(struct iwl_mvm *mvm)
 188{
 189	INIT_LIST_HEAD(&mvm->ftm_initiator.smooth.resp);
 190
 191	IWL_DEBUG_INFO(mvm,
 192		       "enable=%u, alpha=%u, age_jiffies=%u, thresh=(%u:%u)\n",
 193			IWL_MVM_FTM_INITIATOR_ENABLE_SMOOTH,
 194			IWL_MVM_FTM_INITIATOR_SMOOTH_ALPHA,
 195			IWL_MVM_FTM_INITIATOR_SMOOTH_AGE_SEC * HZ,
 196			IWL_MVM_FTM_INITIATOR_SMOOTH_OVERSHOOT,
 197			IWL_MVM_FTM_INITIATOR_SMOOTH_UNDERSHOOT);
 198}
 199
 200void iwl_mvm_ftm_initiator_smooth_stop(struct iwl_mvm *mvm)
 201{
 202	struct iwl_mvm_smooth_entry *se, *st;
 203
 204	list_for_each_entry_safe(se, st, &mvm->ftm_initiator.smooth.resp,
 205				 list) {
 206		list_del(&se->list);
 207		kfree(se);
 208	}
 209}
 210
 211static int
 212iwl_ftm_range_request_status_to_err(enum iwl_tof_range_request_status s)
 213{
 214	switch (s) {
 215	case IWL_TOF_RANGE_REQUEST_STATUS_SUCCESS:
 216		return 0;
 217	case IWL_TOF_RANGE_REQUEST_STATUS_BUSY:
 218		return -EBUSY;
 219	default:
 220		WARN_ON_ONCE(1);
 221		return -EIO;
 222	}
 223}
 224
 225static void iwl_mvm_ftm_cmd_v5(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
 226			       struct iwl_tof_range_req_cmd_v5 *cmd,
 227			       struct cfg80211_pmsr_request *req)
 228{
 229	int i;
 230
 231	cmd->request_id = req->cookie;
 232	cmd->num_of_ap = req->n_peers;
 233
 234	/* use maximum for "no timeout" or bigger than what we can do */
 235	if (!req->timeout || req->timeout > 255 * 100)
 236		cmd->req_timeout = 255;
 237	else
 238		cmd->req_timeout = DIV_ROUND_UP(req->timeout, 100);
 239
 240	/*
 241	 * We treat it always as random, since if not we'll
 242	 * have filled our local address there instead.
 243	 */
 244	cmd->macaddr_random = 1;
 245	memcpy(cmd->macaddr_template, req->mac_addr, ETH_ALEN);
 246	for (i = 0; i < ETH_ALEN; i++)
 247		cmd->macaddr_mask[i] = ~req->mac_addr_mask[i];
 248
 249	if (vif->cfg.assoc)
 250		memcpy(cmd->range_req_bssid, vif->bss_conf.bssid, ETH_ALEN);
 251	else
 252		eth_broadcast_addr(cmd->range_req_bssid);
 253}
 254
 255static void iwl_mvm_ftm_cmd_common(struct iwl_mvm *mvm,
 256				   struct ieee80211_vif *vif,
 257				   struct iwl_tof_range_req_cmd_v9 *cmd,
 258				   struct cfg80211_pmsr_request *req)
 259{
 260	int i;
 261
 262	cmd->initiator_flags =
 263		cpu_to_le32(IWL_TOF_INITIATOR_FLAGS_MACADDR_RANDOM |
 264			    IWL_TOF_INITIATOR_FLAGS_NON_ASAP_SUPPORT);
 265	cmd->request_id = req->cookie;
 266	cmd->num_of_ap = req->n_peers;
 267
 268	/*
 269	 * Use a large value for "no timeout". Don't use the maximum value
 270	 * because of fw limitations.
 271	 */
 272	if (req->timeout)
 273		cmd->req_timeout_ms = cpu_to_le32(req->timeout);
 274	else
 275		cmd->req_timeout_ms = cpu_to_le32(0xfffff);
 276
 277	memcpy(cmd->macaddr_template, req->mac_addr, ETH_ALEN);
 278	for (i = 0; i < ETH_ALEN; i++)
 279		cmd->macaddr_mask[i] = ~req->mac_addr_mask[i];
 280
 281	if (vif->cfg.assoc) {
 282		memcpy(cmd->range_req_bssid, vif->bss_conf.bssid, ETH_ALEN);
 283
 284		/* AP's TSF is only relevant if associated */
 285		for (i = 0; i < req->n_peers; i++) {
 286			if (req->peers[i].report_ap_tsf) {
 287				struct iwl_mvm_vif *mvmvif =
 288					iwl_mvm_vif_from_mac80211(vif);
 289
 290				cmd->tsf_mac_id = cpu_to_le32(mvmvif->id);
 291				return;
 292			}
 293		}
 294	} else {
 295		eth_broadcast_addr(cmd->range_req_bssid);
 296	}
 297
 298	/* Don't report AP's TSF */
 299	cmd->tsf_mac_id = cpu_to_le32(0xff);
 300}
 301
 302static void iwl_mvm_ftm_cmd_v8(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
 303			       struct iwl_tof_range_req_cmd_v8 *cmd,
 304			       struct cfg80211_pmsr_request *req)
 305{
 306	iwl_mvm_ftm_cmd_common(mvm, vif, (void *)cmd, req);
 307}
 308
 309static int
 310iwl_mvm_ftm_target_chandef_v1(struct iwl_mvm *mvm,
 311			      struct cfg80211_pmsr_request_peer *peer,
 312			      u8 *channel, u8 *bandwidth,
 313			      u8 *ctrl_ch_position)
 314{
 315	u32 freq = peer->chandef.chan->center_freq;
 316
 317	*channel = ieee80211_frequency_to_channel(freq);
 318
 319	switch (peer->chandef.width) {
 320	case NL80211_CHAN_WIDTH_20_NOHT:
 321		*bandwidth = IWL_TOF_BW_20_LEGACY;
 322		break;
 323	case NL80211_CHAN_WIDTH_20:
 324		*bandwidth = IWL_TOF_BW_20_HT;
 325		break;
 326	case NL80211_CHAN_WIDTH_40:
 327		*bandwidth = IWL_TOF_BW_40;
 328		break;
 329	case NL80211_CHAN_WIDTH_80:
 330		*bandwidth = IWL_TOF_BW_80;
 331		break;
 332	default:
 333		IWL_ERR(mvm, "Unsupported BW in FTM request (%d)\n",
 334			peer->chandef.width);
 335		return -EINVAL;
 336	}
 337
 338	*ctrl_ch_position = (peer->chandef.width > NL80211_CHAN_WIDTH_20) ?
 339		iwl_mvm_get_ctrl_pos(&peer->chandef) : 0;
 340
 341	return 0;
 342}
 343
 344static int
 345iwl_mvm_ftm_target_chandef_v2(struct iwl_mvm *mvm,
 346			      struct cfg80211_pmsr_request_peer *peer,
 347			      u8 *channel, u8 *format_bw,
 348			      u8 *ctrl_ch_position)
 349{
 350	u32 freq = peer->chandef.chan->center_freq;
 351	u8 cmd_ver;
 352
 353	*channel = ieee80211_frequency_to_channel(freq);
 354
 355	switch (peer->chandef.width) {
 356	case NL80211_CHAN_WIDTH_20_NOHT:
 357		*format_bw = IWL_LOCATION_FRAME_FORMAT_LEGACY;
 358		*format_bw |= IWL_LOCATION_BW_20MHZ << LOCATION_BW_POS;
 359		break;
 360	case NL80211_CHAN_WIDTH_20:
 361		*format_bw = IWL_LOCATION_FRAME_FORMAT_HT;
 362		*format_bw |= IWL_LOCATION_BW_20MHZ << LOCATION_BW_POS;
 363		break;
 364	case NL80211_CHAN_WIDTH_40:
 365		*format_bw = IWL_LOCATION_FRAME_FORMAT_HT;
 366		*format_bw |= IWL_LOCATION_BW_40MHZ << LOCATION_BW_POS;
 367		break;
 368	case NL80211_CHAN_WIDTH_80:
 369		*format_bw = IWL_LOCATION_FRAME_FORMAT_VHT;
 370		*format_bw |= IWL_LOCATION_BW_80MHZ << LOCATION_BW_POS;
 371		break;
 372	case NL80211_CHAN_WIDTH_160:
 373		cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw,
 374						WIDE_ID(LOCATION_GROUP, TOF_RANGE_REQ_CMD),
 375						IWL_FW_CMD_VER_UNKNOWN);
 376
 377		if (cmd_ver >= 13) {
 378			*format_bw = IWL_LOCATION_FRAME_FORMAT_HE;
 379			*format_bw |= IWL_LOCATION_BW_160MHZ << LOCATION_BW_POS;
 380			break;
 381		}
 382		fallthrough;
 383	default:
 384		IWL_ERR(mvm, "Unsupported BW in FTM request (%d)\n",
 385			peer->chandef.width);
 386		return -EINVAL;
 387	}
 388
 389	/* non EDCA based measurement must use HE preamble */
 390	if (peer->ftm.trigger_based || peer->ftm.non_trigger_based)
 391		*format_bw |= IWL_LOCATION_FRAME_FORMAT_HE;
 392
 393	*ctrl_ch_position = (peer->chandef.width > NL80211_CHAN_WIDTH_20) ?
 394		iwl_mvm_get_ctrl_pos(&peer->chandef) : 0;
 395
 396	return 0;
 397}
 398
 399static int
 400iwl_mvm_ftm_put_target_v2(struct iwl_mvm *mvm,
 401			  struct cfg80211_pmsr_request_peer *peer,
 402			  struct iwl_tof_range_req_ap_entry_v2 *target)
 403{
 404	int ret;
 405
 406	ret = iwl_mvm_ftm_target_chandef_v1(mvm, peer, &target->channel_num,
 407					    &target->bandwidth,
 408					    &target->ctrl_ch_position);
 409	if (ret)
 410		return ret;
 411
 412	memcpy(target->bssid, peer->addr, ETH_ALEN);
 413	target->burst_period =
 414		cpu_to_le16(peer->ftm.burst_period);
 415	target->samples_per_burst = peer->ftm.ftms_per_burst;
 416	target->num_of_bursts = peer->ftm.num_bursts_exp;
 417	target->measure_type = 0; /* regular two-sided FTM */
 418	target->retries_per_sample = peer->ftm.ftmr_retries;
 419	target->asap_mode = peer->ftm.asap;
 420	target->enable_dyn_ack = IWL_MVM_FTM_INITIATOR_DYNACK;
 421
 422	if (peer->ftm.request_lci)
 423		target->location_req |= IWL_TOF_LOC_LCI;
 424	if (peer->ftm.request_civicloc)
 425		target->location_req |= IWL_TOF_LOC_CIVIC;
 426
 427	target->algo_type = IWL_MVM_FTM_INITIATOR_ALGO;
 428
 429	return 0;
 430}
 431
 432#define FTM_PUT_FLAG(flag)	(target->initiator_ap_flags |= \
 433				 cpu_to_le32(IWL_INITIATOR_AP_FLAGS_##flag))
 434
 435static void
 436iwl_mvm_ftm_put_target_common(struct iwl_mvm *mvm,
 437			      struct cfg80211_pmsr_request_peer *peer,
 438			      struct iwl_tof_range_req_ap_entry_v6 *target)
 439{
 
 
 
 
 
 
 
 
 440	memcpy(target->bssid, peer->addr, ETH_ALEN);
 441	target->burst_period =
 442		cpu_to_le16(peer->ftm.burst_period);
 443	target->samples_per_burst = peer->ftm.ftms_per_burst;
 444	target->num_of_bursts = peer->ftm.num_bursts_exp;
 445	target->ftmr_max_retries = peer->ftm.ftmr_retries;
 446	target->initiator_ap_flags = cpu_to_le32(0);
 447
 448	if (peer->ftm.asap)
 449		FTM_PUT_FLAG(ASAP);
 450
 451	if (peer->ftm.request_lci)
 452		FTM_PUT_FLAG(LCI_REQUEST);
 453
 454	if (peer->ftm.request_civicloc)
 455		FTM_PUT_FLAG(CIVIC_REQUEST);
 456
 457	if (IWL_MVM_FTM_INITIATOR_DYNACK)
 458		FTM_PUT_FLAG(DYN_ACK);
 459
 460	if (IWL_MVM_FTM_INITIATOR_ALGO == IWL_TOF_ALGO_TYPE_LINEAR_REG)
 461		FTM_PUT_FLAG(ALGO_LR);
 462	else if (IWL_MVM_FTM_INITIATOR_ALGO == IWL_TOF_ALGO_TYPE_FFT)
 463		FTM_PUT_FLAG(ALGO_FFT);
 464
 465	if (peer->ftm.trigger_based)
 466		FTM_PUT_FLAG(TB);
 467	else if (peer->ftm.non_trigger_based)
 468		FTM_PUT_FLAG(NON_TB);
 469
 470	if ((peer->ftm.trigger_based || peer->ftm.non_trigger_based) &&
 471	    peer->ftm.lmr_feedback)
 472		FTM_PUT_FLAG(LMR_FEEDBACK);
 473}
 474
 475static int
 476iwl_mvm_ftm_put_target_v3(struct iwl_mvm *mvm,
 477			  struct cfg80211_pmsr_request_peer *peer,
 478			  struct iwl_tof_range_req_ap_entry_v3 *target)
 479{
 480	int ret;
 481
 482	ret = iwl_mvm_ftm_target_chandef_v1(mvm, peer, &target->channel_num,
 483					    &target->bandwidth,
 484					    &target->ctrl_ch_position);
 485	if (ret)
 486		return ret;
 487
 488	/*
 489	 * Versions 3 and 4 has some common fields, so
 490	 * iwl_mvm_ftm_put_target_common() can be used for version 7 too.
 491	 */
 492	iwl_mvm_ftm_put_target_common(mvm, peer, (void *)target);
 493
 494	return 0;
 495}
 496
 497static int
 498iwl_mvm_ftm_put_target_v4(struct iwl_mvm *mvm,
 499			  struct cfg80211_pmsr_request_peer *peer,
 500			  struct iwl_tof_range_req_ap_entry_v4 *target)
 501{
 502	int ret;
 503
 504	ret = iwl_mvm_ftm_target_chandef_v2(mvm, peer, &target->channel_num,
 505					    &target->format_bw,
 506					    &target->ctrl_ch_position);
 507	if (ret)
 508		return ret;
 509
 510	iwl_mvm_ftm_put_target_common(mvm, peer, (void *)target);
 511
 512	return 0;
 513}
 514
 515static int
 516iwl_mvm_ftm_put_target(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
 517		       struct cfg80211_pmsr_request_peer *peer,
 518		       struct iwl_tof_range_req_ap_entry_v6 *target)
 519{
 520	int ret;
 521
 522	ret = iwl_mvm_ftm_target_chandef_v2(mvm, peer, &target->channel_num,
 523					    &target->format_bw,
 524					    &target->ctrl_ch_position);
 525	if (ret)
 526		return ret;
 527
 528	iwl_mvm_ftm_put_target_common(mvm, peer, target);
 529
 530	if (vif->cfg.assoc) {
 531		struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 532		struct ieee80211_sta *sta;
 533		struct ieee80211_bss_conf *link_conf;
 534		unsigned int link_id;
 535
 536		rcu_read_lock();
 537		for_each_vif_active_link(vif, link_conf, link_id) {
 538			if (memcmp(peer->addr, link_conf->bssid, ETH_ALEN))
 539				continue;
 540
 541			target->sta_id = mvmvif->link[link_id]->ap_sta_id;
 542			sta = rcu_dereference(mvm->fw_id_to_mac_id[target->sta_id]);
 543			if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta))) {
 544				rcu_read_unlock();
 545				return PTR_ERR_OR_ZERO(sta);
 546			}
 547
 548			if (sta->mfp && (peer->ftm.trigger_based ||
 549					 peer->ftm.non_trigger_based))
 550				FTM_PUT_FLAG(PMF);
 551			break;
 552		}
 553		rcu_read_unlock();
 554	} else {
 555		target->sta_id = IWL_MVM_INVALID_STA;
 556	}
 557
 558	/*
 559	 * TODO: Beacon interval is currently unknown, so use the common value
 560	 * of 100 TUs.
 561	 */
 562	target->beacon_interval = cpu_to_le16(100);
 563	return 0;
 564}
 565
 566static int iwl_mvm_ftm_send_cmd(struct iwl_mvm *mvm, struct iwl_host_cmd *hcmd)
 567{
 568	u32 status;
 569	int err = iwl_mvm_send_cmd_status(mvm, hcmd, &status);
 570
 571	if (!err && status) {
 572		IWL_ERR(mvm, "FTM range request command failure, status: %u\n",
 573			status);
 574		err = iwl_ftm_range_request_status_to_err(status);
 575	}
 576
 577	return err;
 578}
 579
 580static int iwl_mvm_ftm_start_v5(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
 581				struct cfg80211_pmsr_request *req)
 582{
 583	struct iwl_tof_range_req_cmd_v5 cmd_v5;
 
 
 
 
 584	struct iwl_host_cmd hcmd = {
 585		.id = WIDE_ID(LOCATION_GROUP, TOF_RANGE_REQ_CMD),
 586		.dataflags[0] = IWL_HCMD_DFL_DUP,
 587		.data[0] = &cmd_v5,
 588		.len[0] = sizeof(cmd_v5),
 589	};
 590	u8 i;
 591	int err;
 592
 593	iwl_mvm_ftm_cmd_v5(mvm, vif, &cmd_v5, req);
 594
 595	for (i = 0; i < cmd_v5.num_of_ap; i++) {
 596		struct cfg80211_pmsr_request_peer *peer = &req->peers[i];
 597
 598		err = iwl_mvm_ftm_put_target_v2(mvm, peer, &cmd_v5.ap[i]);
 599		if (err)
 600			return err;
 601	}
 602
 603	return iwl_mvm_ftm_send_cmd(mvm, &hcmd);
 604}
 605
 606static int iwl_mvm_ftm_start_v7(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
 607				struct cfg80211_pmsr_request *req)
 608{
 609	struct iwl_tof_range_req_cmd_v7 cmd_v7;
 610	struct iwl_host_cmd hcmd = {
 611		.id = WIDE_ID(LOCATION_GROUP, TOF_RANGE_REQ_CMD),
 612		.dataflags[0] = IWL_HCMD_DFL_DUP,
 613		.data[0] = &cmd_v7,
 614		.len[0] = sizeof(cmd_v7),
 615	};
 616	u8 i;
 617	int err;
 618
 619	/*
 620	 * Versions 7 and 8 has the same structure except from the responders
 621	 * list, so iwl_mvm_ftm_cmd() can be used for version 7 too.
 622	 */
 623	iwl_mvm_ftm_cmd_v8(mvm, vif, (void *)&cmd_v7, req);
 624
 625	for (i = 0; i < cmd_v7.num_of_ap; i++) {
 626		struct cfg80211_pmsr_request_peer *peer = &req->peers[i];
 627
 628		err = iwl_mvm_ftm_put_target_v3(mvm, peer, &cmd_v7.ap[i]);
 629		if (err)
 630			return err;
 631	}
 632
 633	return iwl_mvm_ftm_send_cmd(mvm, &hcmd);
 634}
 635
 636static int iwl_mvm_ftm_start_v8(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
 637				struct cfg80211_pmsr_request *req)
 638{
 639	struct iwl_tof_range_req_cmd_v8 cmd;
 640	struct iwl_host_cmd hcmd = {
 641		.id = WIDE_ID(LOCATION_GROUP, TOF_RANGE_REQ_CMD),
 642		.dataflags[0] = IWL_HCMD_DFL_DUP,
 643		.data[0] = &cmd,
 644		.len[0] = sizeof(cmd),
 645	};
 646	u8 i;
 647	int err;
 648
 649	iwl_mvm_ftm_cmd_v8(mvm, vif, (void *)&cmd, req);
 650
 651	for (i = 0; i < cmd.num_of_ap; i++) {
 652		struct cfg80211_pmsr_request_peer *peer = &req->peers[i];
 653
 654		err = iwl_mvm_ftm_put_target_v4(mvm, peer, &cmd.ap[i]);
 655		if (err)
 656			return err;
 657	}
 658
 659	return iwl_mvm_ftm_send_cmd(mvm, &hcmd);
 660}
 661
 662static int iwl_mvm_ftm_start_v9(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
 663				struct cfg80211_pmsr_request *req)
 664{
 665	struct iwl_tof_range_req_cmd_v9 cmd;
 666	struct iwl_host_cmd hcmd = {
 667		.id = WIDE_ID(LOCATION_GROUP, TOF_RANGE_REQ_CMD),
 668		.dataflags[0] = IWL_HCMD_DFL_DUP,
 669		.data[0] = &cmd,
 670		.len[0] = sizeof(cmd),
 671	};
 672	u8 i;
 673	int err;
 674
 675	iwl_mvm_ftm_cmd_common(mvm, vif, &cmd, req);
 676
 677	for (i = 0; i < cmd.num_of_ap; i++) {
 678		struct cfg80211_pmsr_request_peer *peer = &req->peers[i];
 679		struct iwl_tof_range_req_ap_entry_v6 *target = &cmd.ap[i];
 680
 681		err = iwl_mvm_ftm_put_target(mvm, vif, peer, target);
 682		if (err)
 683			return err;
 684	}
 685
 686	return iwl_mvm_ftm_send_cmd(mvm, &hcmd);
 687}
 688
 689static void iter(struct ieee80211_hw *hw,
 690		 struct ieee80211_vif *vif,
 691		 struct ieee80211_sta *sta,
 692		 struct ieee80211_key_conf *key,
 693		 void *data)
 694{
 695	struct iwl_tof_range_req_ap_entry_v6 *target = data;
 696
 697	if (!sta || memcmp(sta->addr, target->bssid, ETH_ALEN))
 698		return;
 699
 700	WARN_ON(!sta->mfp);
 701
 702	if (WARN_ON(key->keylen > sizeof(target->tk)))
 703		return;
 704
 705	memcpy(target->tk, key->key, key->keylen);
 706	target->cipher = iwl_mvm_cipher_to_location_cipher(key->cipher);
 707	WARN_ON(target->cipher == IWL_LOCATION_CIPHER_INVALID);
 708}
 709
 710static void
 711iwl_mvm_ftm_set_secured_ranging(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
 712				struct iwl_tof_range_req_ap_entry_v7 *target)
 713{
 714	struct iwl_mvm_ftm_pasn_entry *entry;
 715	u32 flags = le32_to_cpu(target->initiator_ap_flags);
 716
 717	if (!(flags & (IWL_INITIATOR_AP_FLAGS_NON_TB |
 718		       IWL_INITIATOR_AP_FLAGS_TB)))
 719		return;
 720
 721	lockdep_assert_held(&mvm->mutex);
 722
 723	list_for_each_entry(entry, &mvm->ftm_initiator.pasn_list, list) {
 724		if (memcmp(entry->addr, target->bssid, sizeof(entry->addr)))
 725			continue;
 726
 727		target->cipher = entry->cipher;
 728
 729		if (entry->flags & IWL_MVM_PASN_FLAG_HAS_HLTK)
 730			memcpy(target->hltk, entry->hltk, sizeof(target->hltk));
 731		else
 732			memset(target->hltk, 0, sizeof(target->hltk));
 733
 734		if (vif->cfg.assoc &&
 735		    !memcmp(vif->bss_conf.bssid, target->bssid,
 736			    sizeof(target->bssid)))
 737			ieee80211_iter_keys(mvm->hw, vif, iter, target);
 738		else
 739			memcpy(target->tk, entry->tk, sizeof(target->tk));
 740
 741		memcpy(target->rx_pn, entry->rx_pn, sizeof(target->rx_pn));
 742		memcpy(target->tx_pn, entry->tx_pn, sizeof(target->tx_pn));
 743
 744		target->initiator_ap_flags |=
 745			cpu_to_le32(IWL_INITIATOR_AP_FLAGS_SECURED);
 746		return;
 747	}
 748}
 749
 750static int
 751iwl_mvm_ftm_put_target_v7(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
 752			  struct cfg80211_pmsr_request_peer *peer,
 753			  struct iwl_tof_range_req_ap_entry_v7 *target)
 754{
 755	int err = iwl_mvm_ftm_put_target(mvm, vif, peer, (void *)target);
 756	if (err)
 757		return err;
 758
 759	iwl_mvm_ftm_set_secured_ranging(mvm, vif, target);
 760	return err;
 761}
 762
 763static int iwl_mvm_ftm_start_v11(struct iwl_mvm *mvm,
 764				 struct ieee80211_vif *vif,
 765				 struct cfg80211_pmsr_request *req)
 766{
 767	struct iwl_tof_range_req_cmd_v11 cmd;
 768	struct iwl_host_cmd hcmd = {
 769		.id = WIDE_ID(LOCATION_GROUP, TOF_RANGE_REQ_CMD),
 770		.dataflags[0] = IWL_HCMD_DFL_DUP,
 771		.data[0] = &cmd,
 772		.len[0] = sizeof(cmd),
 773	};
 774	u8 i;
 775	int err;
 776
 777	iwl_mvm_ftm_cmd_common(mvm, vif, (void *)&cmd, req);
 778
 779	for (i = 0; i < cmd.num_of_ap; i++) {
 780		struct cfg80211_pmsr_request_peer *peer = &req->peers[i];
 781		struct iwl_tof_range_req_ap_entry_v7 *target = &cmd.ap[i];
 782
 783		err = iwl_mvm_ftm_put_target_v7(mvm, vif, peer, target);
 784		if (err)
 785			return err;
 786	}
 787
 788	return iwl_mvm_ftm_send_cmd(mvm, &hcmd);
 789}
 790
 791static void
 792iwl_mvm_ftm_set_ndp_params(struct iwl_mvm *mvm,
 793			   struct iwl_tof_range_req_ap_entry_v8 *target)
 794{
 795	/* Only 2 STS are supported on Tx */
 796	u32 i2r_max_sts = IWL_MVM_FTM_I2R_MAX_STS > 1 ? 1 :
 797		IWL_MVM_FTM_I2R_MAX_STS;
 798
 799	target->r2i_ndp_params = IWL_MVM_FTM_R2I_MAX_REP |
 800		(IWL_MVM_FTM_R2I_MAX_STS << IWL_LOCATION_MAX_STS_POS);
 801	target->i2r_ndp_params = IWL_MVM_FTM_I2R_MAX_REP |
 802		(i2r_max_sts << IWL_LOCATION_MAX_STS_POS);
 803	target->r2i_max_total_ltf = IWL_MVM_FTM_R2I_MAX_TOTAL_LTF;
 804	target->i2r_max_total_ltf = IWL_MVM_FTM_I2R_MAX_TOTAL_LTF;
 805}
 806
 807static int
 808iwl_mvm_ftm_put_target_v8(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
 809			  struct cfg80211_pmsr_request_peer *peer,
 810			  struct iwl_tof_range_req_ap_entry_v8 *target)
 811{
 812	u32 flags;
 813	int ret = iwl_mvm_ftm_put_target_v7(mvm, vif, peer, (void *)target);
 814
 815	if (ret)
 816		return ret;
 817
 818	iwl_mvm_ftm_set_ndp_params(mvm, target);
 819
 820	/*
 821	 * If secure LTF is turned off, replace the flag with PMF only
 822	 */
 823	flags = le32_to_cpu(target->initiator_ap_flags);
 824	if ((flags & IWL_INITIATOR_AP_FLAGS_SECURED) &&
 825	    !IWL_MVM_FTM_INITIATOR_SECURE_LTF) {
 826		flags &= ~IWL_INITIATOR_AP_FLAGS_SECURED;
 827		flags |= IWL_INITIATOR_AP_FLAGS_PMF;
 828		target->initiator_ap_flags = cpu_to_le32(flags);
 
 829	}
 830
 831	return 0;
 832}
 833
 834static int iwl_mvm_ftm_start_v12(struct iwl_mvm *mvm,
 835				 struct ieee80211_vif *vif,
 836				 struct cfg80211_pmsr_request *req)
 837{
 838	struct iwl_tof_range_req_cmd_v12 cmd;
 839	struct iwl_host_cmd hcmd = {
 840		.id = WIDE_ID(LOCATION_GROUP, TOF_RANGE_REQ_CMD),
 841		.dataflags[0] = IWL_HCMD_DFL_DUP,
 842		.data[0] = &cmd,
 843		.len[0] = sizeof(cmd),
 844	};
 845	u8 i;
 846	int err;
 847
 848	iwl_mvm_ftm_cmd_common(mvm, vif, (void *)&cmd, req);
 849
 850	for (i = 0; i < cmd.num_of_ap; i++) {
 851		struct cfg80211_pmsr_request_peer *peer = &req->peers[i];
 852		struct iwl_tof_range_req_ap_entry_v8 *target = &cmd.ap[i];
 853
 854		err = iwl_mvm_ftm_put_target_v8(mvm, vif, peer, target);
 855		if (err)
 856			return err;
 857	}
 858
 859	return iwl_mvm_ftm_send_cmd(mvm, &hcmd);
 860}
 861
 862static int iwl_mvm_ftm_start_v13(struct iwl_mvm *mvm,
 863				 struct ieee80211_vif *vif,
 864				 struct cfg80211_pmsr_request *req)
 865{
 866	struct iwl_tof_range_req_cmd_v13 cmd;
 867	struct iwl_host_cmd hcmd = {
 868		.id = WIDE_ID(LOCATION_GROUP, TOF_RANGE_REQ_CMD),
 869		.dataflags[0] = IWL_HCMD_DFL_DUP,
 870		.data[0] = &cmd,
 871		.len[0] = sizeof(cmd),
 872	};
 873	u8 i;
 874	int err;
 875
 876	iwl_mvm_ftm_cmd_common(mvm, vif, (void *)&cmd, req);
 877
 878	for (i = 0; i < cmd.num_of_ap; i++) {
 879		struct cfg80211_pmsr_request_peer *peer = &req->peers[i];
 880		struct iwl_tof_range_req_ap_entry_v9 *target = &cmd.ap[i];
 881
 882		err = iwl_mvm_ftm_put_target_v8(mvm, vif, peer, (void *)target);
 883		if (err)
 884			return err;
 885
 886		if (peer->ftm.trigger_based || peer->ftm.non_trigger_based)
 887			target->bss_color = peer->ftm.bss_color;
 888
 889		if (peer->ftm.non_trigger_based) {
 890			target->min_time_between_msr =
 891				cpu_to_le16(IWL_MVM_FTM_NON_TB_MIN_TIME_BETWEEN_MSR);
 892			target->burst_period =
 893				cpu_to_le16(IWL_MVM_FTM_NON_TB_MAX_TIME_BETWEEN_MSR);
 894		} else {
 895			target->min_time_between_msr = cpu_to_le16(0);
 896		}
 897
 898		target->band =
 899			iwl_mvm_phy_band_from_nl80211(peer->chandef.chan->band);
 900	}
 901
 902	return iwl_mvm_ftm_send_cmd(mvm, &hcmd);
 903}
 904
 905int iwl_mvm_ftm_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
 906		      struct cfg80211_pmsr_request *req)
 907{
 908	bool new_api = fw_has_api(&mvm->fw->ucode_capa,
 909				  IWL_UCODE_TLV_API_FTM_NEW_RANGE_REQ);
 910	int err;
 911
 912	lockdep_assert_held(&mvm->mutex);
 913
 914	if (mvm->ftm_initiator.req)
 915		return -EBUSY;
 916
 917	if (new_api) {
 918		u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw,
 919						   WIDE_ID(LOCATION_GROUP, TOF_RANGE_REQ_CMD),
 920						   IWL_FW_CMD_VER_UNKNOWN);
 921
 922		switch (cmd_ver) {
 923		case 13:
 924			err = iwl_mvm_ftm_start_v13(mvm, vif, req);
 925			break;
 926		case 12:
 927			err = iwl_mvm_ftm_start_v12(mvm, vif, req);
 928			break;
 929		case 11:
 930			err = iwl_mvm_ftm_start_v11(mvm, vif, req);
 931			break;
 932		case 9:
 933		case 10:
 934			err = iwl_mvm_ftm_start_v9(mvm, vif, req);
 935			break;
 936		case 8:
 937			err = iwl_mvm_ftm_start_v8(mvm, vif, req);
 938			break;
 939		default:
 940			err = iwl_mvm_ftm_start_v7(mvm, vif, req);
 941			break;
 942		}
 943	} else {
 944		err = iwl_mvm_ftm_start_v5(mvm, vif, req);
 945	}
 946
 947	if (!err) {
 948		mvm->ftm_initiator.req = req;
 949		mvm->ftm_initiator.req_wdev = ieee80211_vif_to_wdev(vif);
 950	}
 951
 952	return err;
 953}
 954
 955void iwl_mvm_ftm_abort(struct iwl_mvm *mvm, struct cfg80211_pmsr_request *req)
 956{
 957	struct iwl_tof_range_abort_cmd cmd = {
 958		.request_id = req->cookie,
 959	};
 960
 961	lockdep_assert_held(&mvm->mutex);
 962
 963	if (req != mvm->ftm_initiator.req)
 964		return;
 965
 966	iwl_mvm_ftm_reset(mvm);
 967
 968	if (iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(LOCATION_GROUP, TOF_RANGE_ABORT_CMD),
 969				 0, sizeof(cmd), &cmd))
 970		IWL_ERR(mvm, "failed to abort FTM process\n");
 971}
 972
 973static int iwl_mvm_ftm_find_peer(struct cfg80211_pmsr_request *req,
 974				 const u8 *addr)
 975{
 976	int i;
 977
 978	for (i = 0; i < req->n_peers; i++) {
 979		struct cfg80211_pmsr_request_peer *peer = &req->peers[i];
 980
 981		if (ether_addr_equal_unaligned(peer->addr, addr))
 982			return i;
 983	}
 984
 985	return -ENOENT;
 986}
 987
 988static u64 iwl_mvm_ftm_get_host_time(struct iwl_mvm *mvm, __le32 fw_gp2_ts)
 989{
 990	u32 gp2_ts = le32_to_cpu(fw_gp2_ts);
 991	u32 curr_gp2, diff;
 992	u64 now_from_boot_ns;
 993
 994	iwl_mvm_get_sync_time(mvm, CLOCK_BOOTTIME, &curr_gp2,
 995			      &now_from_boot_ns, NULL);
 996
 997	if (curr_gp2 >= gp2_ts)
 998		diff = curr_gp2 - gp2_ts;
 999	else
1000		diff = curr_gp2 + (U32_MAX - gp2_ts + 1);
1001
1002	return now_from_boot_ns - (u64)diff * 1000;
1003}
1004
1005static void iwl_mvm_ftm_get_lci_civic(struct iwl_mvm *mvm,
1006				      struct cfg80211_pmsr_result *res)
1007{
1008	struct iwl_mvm_loc_entry *entry;
1009
1010	list_for_each_entry(entry, &mvm->ftm_initiator.loc_list, list) {
1011		if (!ether_addr_equal_unaligned(res->addr, entry->addr))
1012			continue;
1013
1014		if (entry->lci_len) {
1015			res->ftm.lci_len = entry->lci_len;
1016			res->ftm.lci = entry->buf;
1017		}
1018
1019		if (entry->civic_len) {
1020			res->ftm.civicloc_len = entry->civic_len;
1021			res->ftm.civicloc = entry->buf + entry->lci_len;
1022		}
1023
1024		/* we found the entry we needed */
1025		break;
1026	}
1027}
1028
1029static int iwl_mvm_ftm_range_resp_valid(struct iwl_mvm *mvm, u8 request_id,
1030					u8 num_of_aps)
1031{
1032	lockdep_assert_held(&mvm->mutex);
1033
1034	if (request_id != (u8)mvm->ftm_initiator.req->cookie) {
1035		IWL_ERR(mvm, "Request ID mismatch, got %u, active %u\n",
1036			request_id, (u8)mvm->ftm_initiator.req->cookie);
1037		return -EINVAL;
1038	}
1039
1040	if (num_of_aps > mvm->ftm_initiator.req->n_peers) {
1041		IWL_ERR(mvm, "FTM range response invalid\n");
1042		return -EINVAL;
1043	}
1044
1045	return 0;
1046}
1047
1048static void iwl_mvm_ftm_rtt_smoothing(struct iwl_mvm *mvm,
1049				      struct cfg80211_pmsr_result *res)
1050{
1051	struct iwl_mvm_smooth_entry *resp = NULL, *iter;
1052	s64 rtt_avg, rtt = res->ftm.rtt_avg;
1053	u32 undershoot, overshoot;
1054	u8 alpha;
1055
1056	if (!IWL_MVM_FTM_INITIATOR_ENABLE_SMOOTH)
1057		return;
1058
1059	WARN_ON(rtt < 0);
1060
1061	if (res->status != NL80211_PMSR_STATUS_SUCCESS) {
1062		IWL_DEBUG_INFO(mvm,
1063			       ": %pM: ignore failed measurement. Status=%u\n",
1064			       res->addr, res->status);
1065		return;
1066	}
1067
1068	list_for_each_entry(iter, &mvm->ftm_initiator.smooth.resp, list) {
1069		if (!memcmp(res->addr, iter->addr, ETH_ALEN)) {
1070			resp = iter;
1071			break;
1072		}
1073	}
1074
1075	if (!resp) {
1076		resp = kzalloc(sizeof(*resp), GFP_KERNEL);
1077		if (!resp)
1078			return;
1079
1080		memcpy(resp->addr, res->addr, ETH_ALEN);
1081		list_add_tail(&resp->list, &mvm->ftm_initiator.smooth.resp);
1082
1083		resp->rtt_avg = rtt;
1084
1085		IWL_DEBUG_INFO(mvm, "new: %pM: rtt_avg=%lld\n",
1086			       resp->addr, resp->rtt_avg);
1087		goto update_time;
1088	}
1089
1090	if (res->host_time - resp->host_time >
1091	    IWL_MVM_FTM_INITIATOR_SMOOTH_AGE_SEC * 1000000000) {
1092		resp->rtt_avg = rtt;
1093
1094		IWL_DEBUG_INFO(mvm, "expired: %pM: rtt_avg=%lld\n",
1095			       resp->addr, resp->rtt_avg);
1096		goto update_time;
1097	}
1098
1099	/* Smooth the results based on the tracked RTT average */
1100	undershoot = IWL_MVM_FTM_INITIATOR_SMOOTH_UNDERSHOOT;
1101	overshoot = IWL_MVM_FTM_INITIATOR_SMOOTH_OVERSHOOT;
1102	alpha = IWL_MVM_FTM_INITIATOR_SMOOTH_ALPHA;
1103
1104	rtt_avg = div_s64(alpha * rtt + (100 - alpha) * resp->rtt_avg, 100);
1105
1106	IWL_DEBUG_INFO(mvm,
1107		       "%pM: prev rtt_avg=%lld, new rtt_avg=%lld, rtt=%lld\n",
1108		       resp->addr, resp->rtt_avg, rtt_avg, rtt);
1109
1110	/*
1111	 * update the responder's average RTT results regardless of
1112	 * the under/over shoot logic below
1113	 */
1114	resp->rtt_avg = rtt_avg;
1115
1116	/* smooth the results */
1117	if (rtt_avg > rtt && (rtt_avg - rtt) > undershoot) {
1118		res->ftm.rtt_avg = rtt_avg;
1119
1120		IWL_DEBUG_INFO(mvm,
1121			       "undershoot: val=%lld\n",
1122			       (rtt_avg - rtt));
1123	} else if (rtt_avg < rtt && (rtt - rtt_avg) >
1124		   overshoot) {
1125		res->ftm.rtt_avg = rtt_avg;
1126		IWL_DEBUG_INFO(mvm,
1127			       "overshoot: val=%lld\n",
1128			       (rtt - rtt_avg));
1129	}
1130
1131update_time:
1132	resp->host_time = res->host_time;
1133}
1134
1135static void iwl_mvm_debug_range_resp(struct iwl_mvm *mvm, u8 index,
1136				     struct cfg80211_pmsr_result *res)
1137{
1138	s64 rtt_avg = div_s64(res->ftm.rtt_avg * 100, 6666);
1139
1140	IWL_DEBUG_INFO(mvm, "entry %d\n", index);
1141	IWL_DEBUG_INFO(mvm, "\tstatus: %d\n", res->status);
1142	IWL_DEBUG_INFO(mvm, "\tBSSID: %pM\n", res->addr);
1143	IWL_DEBUG_INFO(mvm, "\thost time: %llu\n", res->host_time);
1144	IWL_DEBUG_INFO(mvm, "\tburst index: %d\n", res->ftm.burst_index);
1145	IWL_DEBUG_INFO(mvm, "\tsuccess num: %u\n", res->ftm.num_ftmr_successes);
1146	IWL_DEBUG_INFO(mvm, "\trssi: %d\n", res->ftm.rssi_avg);
1147	IWL_DEBUG_INFO(mvm, "\trssi spread: %d\n", res->ftm.rssi_spread);
1148	IWL_DEBUG_INFO(mvm, "\trtt: %lld\n", res->ftm.rtt_avg);
1149	IWL_DEBUG_INFO(mvm, "\trtt var: %llu\n", res->ftm.rtt_variance);
1150	IWL_DEBUG_INFO(mvm, "\trtt spread: %llu\n", res->ftm.rtt_spread);
1151	IWL_DEBUG_INFO(mvm, "\tdistance: %lld\n", rtt_avg);
1152}
1153
1154static void
1155iwl_mvm_ftm_pasn_update_pn(struct iwl_mvm *mvm,
1156			   struct iwl_tof_range_rsp_ap_entry_ntfy_v6 *fw_ap)
1157{
1158	struct iwl_mvm_ftm_pasn_entry *entry;
1159
1160	lockdep_assert_held(&mvm->mutex);
1161
1162	list_for_each_entry(entry, &mvm->ftm_initiator.pasn_list, list) {
1163		if (memcmp(fw_ap->bssid, entry->addr, sizeof(entry->addr)))
1164			continue;
1165
1166		memcpy(entry->rx_pn, fw_ap->rx_pn, sizeof(entry->rx_pn));
1167		memcpy(entry->tx_pn, fw_ap->tx_pn, sizeof(entry->tx_pn));
1168		return;
1169	}
1170}
1171
1172static u8 iwl_mvm_ftm_get_range_resp_ver(struct iwl_mvm *mvm)
1173{
1174	if (!fw_has_api(&mvm->fw->ucode_capa,
1175			IWL_UCODE_TLV_API_FTM_NEW_RANGE_REQ))
1176		return 5;
1177
1178	/* Starting from version 8, the FW advertises the version */
1179	if (mvm->cmd_ver.range_resp >= 8)
1180		return mvm->cmd_ver.range_resp;
1181	else if (fw_has_api(&mvm->fw->ucode_capa,
1182			    IWL_UCODE_TLV_API_FTM_RTT_ACCURACY))
1183		return 7;
1184
1185	/* The first version of the new range request API */
1186	return 6;
1187}
1188
1189static bool iwl_mvm_ftm_resp_size_validation(u8 ver, unsigned int pkt_len)
1190{
1191	switch (ver) {
1192	case 9:
1193	case 8:
1194		return pkt_len == sizeof(struct iwl_tof_range_rsp_ntfy_v8);
1195	case 7:
1196		return pkt_len == sizeof(struct iwl_tof_range_rsp_ntfy_v7);
1197	case 6:
1198		return pkt_len == sizeof(struct iwl_tof_range_rsp_ntfy_v6);
1199	case 5:
1200		return pkt_len == sizeof(struct iwl_tof_range_rsp_ntfy_v5);
1201	default:
1202		WARN_ONCE(1, "FTM: unsupported range response version %u", ver);
1203		return false;
1204	}
1205}
1206
1207void iwl_mvm_ftm_range_resp(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
1208{
1209	struct iwl_rx_packet *pkt = rxb_addr(rxb);
1210	unsigned int pkt_len = iwl_rx_packet_payload_len(pkt);
1211	struct iwl_tof_range_rsp_ntfy_v5 *fw_resp_v5 = (void *)pkt->data;
1212	struct iwl_tof_range_rsp_ntfy_v6 *fw_resp_v6 = (void *)pkt->data;
1213	struct iwl_tof_range_rsp_ntfy_v7 *fw_resp_v7 = (void *)pkt->data;
1214	struct iwl_tof_range_rsp_ntfy_v8 *fw_resp_v8 = (void *)pkt->data;
1215	int i;
1216	bool new_api = fw_has_api(&mvm->fw->ucode_capa,
1217				  IWL_UCODE_TLV_API_FTM_NEW_RANGE_REQ);
1218	u8 num_of_aps, last_in_batch;
1219	u8 notif_ver = iwl_mvm_ftm_get_range_resp_ver(mvm);
1220
1221	lockdep_assert_held(&mvm->mutex);
1222
1223	if (!mvm->ftm_initiator.req) {
 
1224		return;
1225	}
1226
1227	if (unlikely(!iwl_mvm_ftm_resp_size_validation(notif_ver, pkt_len)))
1228		return;
1229
1230	if (new_api) {
1231		if (iwl_mvm_ftm_range_resp_valid(mvm, fw_resp_v8->request_id,
1232						 fw_resp_v8->num_of_aps))
1233			return;
1234
1235		num_of_aps = fw_resp_v8->num_of_aps;
1236		last_in_batch = fw_resp_v8->last_report;
1237	} else {
1238		if (iwl_mvm_ftm_range_resp_valid(mvm, fw_resp_v5->request_id,
1239						 fw_resp_v5->num_of_aps))
1240			return;
1241
1242		num_of_aps = fw_resp_v5->num_of_aps;
1243		last_in_batch = fw_resp_v5->last_in_batch;
1244	}
1245
1246	IWL_DEBUG_INFO(mvm, "Range response received\n");
1247	IWL_DEBUG_INFO(mvm, "request id: %lld, num of entries: %u\n",
1248		       mvm->ftm_initiator.req->cookie, num_of_aps);
1249
1250	for (i = 0; i < num_of_aps && i < IWL_MVM_TOF_MAX_APS; i++) {
1251		struct cfg80211_pmsr_result result = {};
1252		struct iwl_tof_range_rsp_ap_entry_ntfy_v6 *fw_ap;
1253		int peer_idx;
1254
1255		if (new_api) {
1256			if (notif_ver >= 8) {
1257				fw_ap = &fw_resp_v8->ap[i];
1258				iwl_mvm_ftm_pasn_update_pn(mvm, fw_ap);
1259			} else if (notif_ver == 7) {
1260				fw_ap = (void *)&fw_resp_v7->ap[i];
1261			} else {
1262				fw_ap = (void *)&fw_resp_v6->ap[i];
1263			}
1264
1265			result.final = fw_ap->last_burst;
1266			result.ap_tsf = le32_to_cpu(fw_ap->start_tsf);
1267			result.ap_tsf_valid = 1;
1268		} else {
1269			/* the first part is the same for old and new APIs */
1270			fw_ap = (void *)&fw_resp_v5->ap[i];
1271			/*
1272			 * FIXME: the firmware needs to report this, we don't
1273			 * even know the number of bursts the responder picked
1274			 * (if we asked it to)
1275			 */
1276			result.final = 0;
1277		}
1278
1279		peer_idx = iwl_mvm_ftm_find_peer(mvm->ftm_initiator.req,
1280						 fw_ap->bssid);
1281		if (peer_idx < 0) {
1282			IWL_WARN(mvm,
1283				 "Unknown address (%pM, target #%d) in FTM response\n",
1284				 fw_ap->bssid, i);
1285			continue;
1286		}
1287
1288		switch (fw_ap->measure_status) {
1289		case IWL_TOF_ENTRY_SUCCESS:
1290			result.status = NL80211_PMSR_STATUS_SUCCESS;
1291			break;
1292		case IWL_TOF_ENTRY_TIMING_MEASURE_TIMEOUT:
1293			result.status = NL80211_PMSR_STATUS_TIMEOUT;
1294			break;
1295		case IWL_TOF_ENTRY_NO_RESPONSE:
1296			result.status = NL80211_PMSR_STATUS_FAILURE;
1297			result.ftm.failure_reason =
1298				NL80211_PMSR_FTM_FAILURE_NO_RESPONSE;
1299			break;
1300		case IWL_TOF_ENTRY_REQUEST_REJECTED:
1301			result.status = NL80211_PMSR_STATUS_FAILURE;
1302			result.ftm.failure_reason =
1303				NL80211_PMSR_FTM_FAILURE_PEER_BUSY;
1304			result.ftm.busy_retry_time = fw_ap->refusal_period;
1305			break;
1306		default:
1307			result.status = NL80211_PMSR_STATUS_FAILURE;
1308			result.ftm.failure_reason =
1309				NL80211_PMSR_FTM_FAILURE_UNSPECIFIED;
1310			break;
1311		}
1312		memcpy(result.addr, fw_ap->bssid, ETH_ALEN);
1313		result.host_time = iwl_mvm_ftm_get_host_time(mvm,
1314							     fw_ap->timestamp);
1315		result.type = NL80211_PMSR_TYPE_FTM;
1316		result.ftm.burst_index = mvm->ftm_initiator.responses[peer_idx];
1317		mvm->ftm_initiator.responses[peer_idx]++;
1318		result.ftm.rssi_avg = fw_ap->rssi;
1319		result.ftm.rssi_avg_valid = 1;
1320		result.ftm.rssi_spread = fw_ap->rssi_spread;
1321		result.ftm.rssi_spread_valid = 1;
1322		result.ftm.rtt_avg = (s32)le32_to_cpu(fw_ap->rtt);
1323		result.ftm.rtt_avg_valid = 1;
1324		result.ftm.rtt_variance = le32_to_cpu(fw_ap->rtt_variance);
1325		result.ftm.rtt_variance_valid = 1;
1326		result.ftm.rtt_spread = le32_to_cpu(fw_ap->rtt_spread);
1327		result.ftm.rtt_spread_valid = 1;
1328
1329		iwl_mvm_ftm_get_lci_civic(mvm, &result);
1330
1331		iwl_mvm_ftm_rtt_smoothing(mvm, &result);
1332
1333		cfg80211_pmsr_report(mvm->ftm_initiator.req_wdev,
1334				     mvm->ftm_initiator.req,
1335				     &result, GFP_KERNEL);
1336
1337		if (fw_has_api(&mvm->fw->ucode_capa,
1338			       IWL_UCODE_TLV_API_FTM_RTT_ACCURACY))
1339			IWL_DEBUG_INFO(mvm, "RTT confidence: %u\n",
1340				       fw_ap->rttConfidence);
1341
1342		iwl_mvm_debug_range_resp(mvm, i, &result);
1343	}
1344
1345	if (last_in_batch) {
1346		cfg80211_pmsr_complete(mvm->ftm_initiator.req_wdev,
1347				       mvm->ftm_initiator.req,
1348				       GFP_KERNEL);
1349		iwl_mvm_ftm_reset(mvm);
1350	}
1351}
1352
1353void iwl_mvm_ftm_lc_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
1354{
1355	struct iwl_rx_packet *pkt = rxb_addr(rxb);
1356	const struct ieee80211_mgmt *mgmt = (void *)pkt->data;
1357	size_t len = iwl_rx_packet_payload_len(pkt);
1358	struct iwl_mvm_loc_entry *entry;
1359	const u8 *ies, *lci, *civic, *msr_ie;
1360	size_t ies_len, lci_len = 0, civic_len = 0;
1361	size_t baselen = IEEE80211_MIN_ACTION_SIZE +
1362			 sizeof(mgmt->u.action.u.ftm);
1363	static const u8 rprt_type_lci = IEEE80211_SPCT_MSR_RPRT_TYPE_LCI;
1364	static const u8 rprt_type_civic = IEEE80211_SPCT_MSR_RPRT_TYPE_CIVIC;
1365
1366	if (len <= baselen)
1367		return;
1368
1369	lockdep_assert_held(&mvm->mutex);
1370
1371	ies = mgmt->u.action.u.ftm.variable;
1372	ies_len = len - baselen;
1373
1374	msr_ie = cfg80211_find_ie_match(WLAN_EID_MEASURE_REPORT, ies, ies_len,
1375					&rprt_type_lci, 1, 4);
1376	if (msr_ie) {
1377		lci = msr_ie + 2;
1378		lci_len = msr_ie[1];
1379	}
1380
1381	msr_ie = cfg80211_find_ie_match(WLAN_EID_MEASURE_REPORT, ies, ies_len,
1382					&rprt_type_civic, 1, 4);
1383	if (msr_ie) {
1384		civic = msr_ie + 2;
1385		civic_len = msr_ie[1];
1386	}
1387
1388	entry = kmalloc(sizeof(*entry) + lci_len + civic_len, GFP_KERNEL);
1389	if (!entry)
1390		return;
1391
1392	memcpy(entry->addr, mgmt->bssid, ETH_ALEN);
1393
1394	entry->lci_len = lci_len;
1395	if (lci_len)
1396		memcpy(entry->buf, lci, lci_len);
1397
1398	entry->civic_len = civic_len;
1399	if (civic_len)
1400		memcpy(entry->buf + lci_len, civic, civic_len);
1401
1402	list_add_tail(&entry->list, &mvm->ftm_initiator.loc_list);
1403}
v5.4
  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 *
 12 * This program is free software; you can redistribute it and/or modify
 13 * it under the terms of version 2 of the GNU General Public License as
 14 * published by the Free Software Foundation.
 15 *
 16 * This program is distributed in the hope that it will be useful, but
 17 * WITHOUT ANY WARRANTY; without even the implied warranty of
 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 19 * General Public License for more details.
 20 *
 21 * The full GNU General Public License is included in this distribution
 22 * in the file called COPYING.
 23 *
 24 * Contact Information:
 25 * Intel Linux Wireless <linuxwifi@intel.com>
 26 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 27 *
 28 * BSD LICENSE
 29 *
 30 * Copyright(c) 2015 - 2017 Intel Deutschland GmbH
 31 * Copyright (C) 2018 Intel Corporation
 32 * Copyright (C) 2019 Intel Corporation
 33 * All rights reserved.
 34 *
 35 * Redistribution and use in source and binary forms, with or without
 36 * modification, are permitted provided that the following conditions
 37 * are met:
 38 *
 39 *  * Redistributions of source code must retain the above copyright
 40 *    notice, this list of conditions and the following disclaimer.
 41 *  * Redistributions in binary form must reproduce the above copyright
 42 *    notice, this list of conditions and the following disclaimer in
 43 *    the documentation and/or other materials provided with the
 44 *    distribution.
 45 *  * Neither the name Intel Corporation nor the names of its
 46 *    contributors may be used to endorse or promote products derived
 47 *    from this software without specific prior written permission.
 48 *
 49 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 50 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 51 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 52 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 53 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 54 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 55 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 56 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 57 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 58 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 59 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 60 *
 61 *****************************************************************************/
 62#include <linux/etherdevice.h>
 63#include <linux/math64.h>
 64#include <net/cfg80211.h>
 65#include "mvm.h"
 66#include "iwl-io.h"
 67#include "iwl-prph.h"
 68#include "constants.h"
 69
 70struct iwl_mvm_loc_entry {
 71	struct list_head list;
 72	u8 addr[ETH_ALEN];
 73	u8 lci_len, civic_len;
 74	u8 buf[];
 75};
 76
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 77static void iwl_mvm_ftm_reset(struct iwl_mvm *mvm)
 78{
 79	struct iwl_mvm_loc_entry *e, *t;
 80
 81	mvm->ftm_initiator.req = NULL;
 82	mvm->ftm_initiator.req_wdev = NULL;
 83	memset(mvm->ftm_initiator.responses, 0,
 84	       sizeof(mvm->ftm_initiator.responses));
 
 85	list_for_each_entry_safe(e, t, &mvm->ftm_initiator.loc_list, list) {
 86		list_del(&e->list);
 87		kfree(e);
 88	}
 89}
 90
 91void iwl_mvm_ftm_restart(struct iwl_mvm *mvm)
 92{
 93	struct cfg80211_pmsr_result result = {
 94		.status = NL80211_PMSR_STATUS_FAILURE,
 95		.final = 1,
 96		.host_time = ktime_get_boottime_ns(),
 97		.type = NL80211_PMSR_TYPE_FTM,
 98	};
 99	int i;
100
101	lockdep_assert_held(&mvm->mutex);
102
103	if (!mvm->ftm_initiator.req)
104		return;
105
106	for (i = 0; i < mvm->ftm_initiator.req->n_peers; i++) {
107		memcpy(result.addr, mvm->ftm_initiator.req->peers[i].addr,
108		       ETH_ALEN);
109		result.ftm.burst_index = mvm->ftm_initiator.responses[i];
110
111		cfg80211_pmsr_report(mvm->ftm_initiator.req_wdev,
112				     mvm->ftm_initiator.req,
113				     &result, GFP_KERNEL);
114	}
115
116	cfg80211_pmsr_complete(mvm->ftm_initiator.req_wdev,
117			       mvm->ftm_initiator.req, GFP_KERNEL);
118	iwl_mvm_ftm_reset(mvm);
119}
120
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
121static int
122iwl_ftm_range_request_status_to_err(enum iwl_tof_range_request_status s)
123{
124	switch (s) {
125	case IWL_TOF_RANGE_REQUEST_STATUS_SUCCESS:
126		return 0;
127	case IWL_TOF_RANGE_REQUEST_STATUS_BUSY:
128		return -EBUSY;
129	default:
130		WARN_ON_ONCE(1);
131		return -EIO;
132	}
133}
134
135static void iwl_mvm_ftm_cmd_v5(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
136			       struct iwl_tof_range_req_cmd_v5 *cmd,
137			       struct cfg80211_pmsr_request *req)
138{
139	int i;
140
141	cmd->request_id = req->cookie;
142	cmd->num_of_ap = req->n_peers;
143
144	/* use maximum for "no timeout" or bigger than what we can do */
145	if (!req->timeout || req->timeout > 255 * 100)
146		cmd->req_timeout = 255;
147	else
148		cmd->req_timeout = DIV_ROUND_UP(req->timeout, 100);
149
150	/*
151	 * We treat it always as random, since if not we'll
152	 * have filled our local address there instead.
153	 */
154	cmd->macaddr_random = 1;
155	memcpy(cmd->macaddr_template, req->mac_addr, ETH_ALEN);
156	for (i = 0; i < ETH_ALEN; i++)
157		cmd->macaddr_mask[i] = ~req->mac_addr_mask[i];
158
159	if (vif->bss_conf.assoc)
160		memcpy(cmd->range_req_bssid, vif->bss_conf.bssid, ETH_ALEN);
161	else
162		eth_broadcast_addr(cmd->range_req_bssid);
163}
164
165static void iwl_mvm_ftm_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
166			    struct iwl_tof_range_req_cmd *cmd,
167			    struct cfg80211_pmsr_request *req)
 
168{
169	int i;
170
171	cmd->initiator_flags =
172		cpu_to_le32(IWL_TOF_INITIATOR_FLAGS_MACADDR_RANDOM |
173			    IWL_TOF_INITIATOR_FLAGS_NON_ASAP_SUPPORT);
174	cmd->request_id = req->cookie;
175	cmd->num_of_ap = req->n_peers;
176
177	/*
178	 * Use a large value for "no timeout". Don't use the maximum value
179	 * because of fw limitations.
180	 */
181	if (req->timeout)
182		cmd->req_timeout_ms = cpu_to_le32(req->timeout);
183	else
184		cmd->req_timeout_ms = cpu_to_le32(0xfffff);
185
186	memcpy(cmd->macaddr_template, req->mac_addr, ETH_ALEN);
187	for (i = 0; i < ETH_ALEN; i++)
188		cmd->macaddr_mask[i] = ~req->mac_addr_mask[i];
189
190	if (vif->bss_conf.assoc) {
191		memcpy(cmd->range_req_bssid, vif->bss_conf.bssid, ETH_ALEN);
192
193		/* AP's TSF is only relevant if associated */
194		for (i = 0; i < req->n_peers; i++) {
195			if (req->peers[i].report_ap_tsf) {
196				struct iwl_mvm_vif *mvmvif =
197					iwl_mvm_vif_from_mac80211(vif);
198
199				cmd->tsf_mac_id = cpu_to_le32(mvmvif->id);
200				return;
201			}
202		}
203	} else {
204		eth_broadcast_addr(cmd->range_req_bssid);
205	}
206
207	/* Don't report AP's TSF */
208	cmd->tsf_mac_id = cpu_to_le32(0xff);
209}
210
211static int iwl_mvm_ftm_target_chandef(struct iwl_mvm *mvm,
212				      struct cfg80211_pmsr_request_peer *peer,
213				      u8 *channel, u8 *bandwidth,
214				      u8 *ctrl_ch_position)
 
 
 
 
 
 
 
 
215{
216	u32 freq = peer->chandef.chan->center_freq;
217
218	*channel = ieee80211_frequency_to_channel(freq);
219
220	switch (peer->chandef.width) {
221	case NL80211_CHAN_WIDTH_20_NOHT:
222		*bandwidth = IWL_TOF_BW_20_LEGACY;
223		break;
224	case NL80211_CHAN_WIDTH_20:
225		*bandwidth = IWL_TOF_BW_20_HT;
226		break;
227	case NL80211_CHAN_WIDTH_40:
228		*bandwidth = IWL_TOF_BW_40;
229		break;
230	case NL80211_CHAN_WIDTH_80:
231		*bandwidth = IWL_TOF_BW_80;
232		break;
233	default:
234		IWL_ERR(mvm, "Unsupported BW in FTM request (%d)\n",
235			peer->chandef.width);
236		return -EINVAL;
237	}
238
239	*ctrl_ch_position = (peer->chandef.width > NL80211_CHAN_WIDTH_20) ?
240		iwl_mvm_get_ctrl_pos(&peer->chandef) : 0;
241
242	return 0;
243}
244
245static int
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
246iwl_mvm_ftm_put_target_v2(struct iwl_mvm *mvm,
247			  struct cfg80211_pmsr_request_peer *peer,
248			  struct iwl_tof_range_req_ap_entry_v2 *target)
249{
250	int ret;
251
252	ret = iwl_mvm_ftm_target_chandef(mvm, peer, &target->channel_num,
253					 &target->bandwidth,
254					 &target->ctrl_ch_position);
255	if (ret)
256		return ret;
257
258	memcpy(target->bssid, peer->addr, ETH_ALEN);
259	target->burst_period =
260		cpu_to_le16(peer->ftm.burst_period);
261	target->samples_per_burst = peer->ftm.ftms_per_burst;
262	target->num_of_bursts = peer->ftm.num_bursts_exp;
263	target->measure_type = 0; /* regular two-sided FTM */
264	target->retries_per_sample = peer->ftm.ftmr_retries;
265	target->asap_mode = peer->ftm.asap;
266	target->enable_dyn_ack = IWL_MVM_FTM_INITIATOR_DYNACK;
267
268	if (peer->ftm.request_lci)
269		target->location_req |= IWL_TOF_LOC_LCI;
270	if (peer->ftm.request_civicloc)
271		target->location_req |= IWL_TOF_LOC_CIVIC;
272
273	target->algo_type = IWL_MVM_FTM_INITIATOR_ALGO;
274
275	return 0;
276}
277
278#define FTM_PUT_FLAG(flag)	(target->initiator_ap_flags |= \
279				 cpu_to_le32(IWL_INITIATOR_AP_FLAGS_##flag))
280
281static int iwl_mvm_ftm_put_target(struct iwl_mvm *mvm,
282				  struct cfg80211_pmsr_request_peer *peer,
283				  struct iwl_tof_range_req_ap_entry *target)
 
284{
285	int ret;
286
287	ret = iwl_mvm_ftm_target_chandef(mvm, peer, &target->channel_num,
288					 &target->bandwidth,
289					 &target->ctrl_ch_position);
290	if (ret)
291		return ret;
292
293	memcpy(target->bssid, peer->addr, ETH_ALEN);
294	target->burst_period =
295		cpu_to_le16(peer->ftm.burst_period);
296	target->samples_per_burst = peer->ftm.ftms_per_burst;
297	target->num_of_bursts = peer->ftm.num_bursts_exp;
298	target->ftmr_max_retries = peer->ftm.ftmr_retries;
299	target->initiator_ap_flags = cpu_to_le32(0);
300
301	if (peer->ftm.asap)
302		FTM_PUT_FLAG(ASAP);
303
304	if (peer->ftm.request_lci)
305		FTM_PUT_FLAG(LCI_REQUEST);
306
307	if (peer->ftm.request_civicloc)
308		FTM_PUT_FLAG(CIVIC_REQUEST);
309
310	if (IWL_MVM_FTM_INITIATOR_DYNACK)
311		FTM_PUT_FLAG(DYN_ACK);
312
313	if (IWL_MVM_FTM_INITIATOR_ALGO == IWL_TOF_ALGO_TYPE_LINEAR_REG)
314		FTM_PUT_FLAG(ALGO_LR);
315	else if (IWL_MVM_FTM_INITIATOR_ALGO == IWL_TOF_ALGO_TYPE_FFT)
316		FTM_PUT_FLAG(ALGO_FFT);
317
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
318	return 0;
319}
320
321int iwl_mvm_ftm_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
322		      struct cfg80211_pmsr_request *req)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
323{
324	struct iwl_tof_range_req_cmd_v5 cmd_v5;
325	struct iwl_tof_range_req_cmd cmd;
326	bool new_api = fw_has_api(&mvm->fw->ucode_capa,
327				  IWL_UCODE_TLV_API_FTM_NEW_RANGE_REQ);
328	u8 num_of_ap;
329	struct iwl_host_cmd hcmd = {
330		.id = iwl_cmd_id(TOF_RANGE_REQ_CMD, LOCATION_GROUP, 0),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
331		.dataflags[0] = IWL_HCMD_DFL_DUP,
 
 
332	};
333	u32 status = 0;
334	int err, i;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
335
336	lockdep_assert_held(&mvm->mutex);
337
338	if (mvm->ftm_initiator.req)
339		return -EBUSY;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
340
341	if (new_api) {
342		iwl_mvm_ftm_cmd(mvm, vif, &cmd, req);
343		hcmd.data[0] = &cmd;
344		hcmd.len[0] = sizeof(cmd);
345		num_of_ap = cmd.num_of_ap;
346	} else {
347		iwl_mvm_ftm_cmd_v5(mvm, vif, &cmd_v5, req);
348		hcmd.data[0] = &cmd_v5;
349		hcmd.len[0] = sizeof(cmd_v5);
350		num_of_ap = cmd_v5.num_of_ap;
351	}
352
353	for (i = 0; i < num_of_ap; i++) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
354		struct cfg80211_pmsr_request_peer *peer = &req->peers[i];
 
 
 
 
 
 
355
356		if (new_api)
357			err = iwl_mvm_ftm_put_target(mvm, peer, &cmd.ap[i]);
358		else
359			err = iwl_mvm_ftm_put_target_v2(mvm, peer,
360							&cmd_v5.ap[i]);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
361
 
362		if (err)
363			return err;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
364	}
365
366	err = iwl_mvm_send_cmd_status(mvm, &hcmd, &status);
367	if (!err && status) {
368		IWL_ERR(mvm, "FTM range request command failure, status: %u\n",
369			status);
370		err = iwl_ftm_range_request_status_to_err(status);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
371	}
372
373	if (!err) {
374		mvm->ftm_initiator.req = req;
375		mvm->ftm_initiator.req_wdev = ieee80211_vif_to_wdev(vif);
376	}
377
378	return err;
379}
380
381void iwl_mvm_ftm_abort(struct iwl_mvm *mvm, struct cfg80211_pmsr_request *req)
382{
383	struct iwl_tof_range_abort_cmd cmd = {
384		.request_id = req->cookie,
385	};
386
387	lockdep_assert_held(&mvm->mutex);
388
389	if (req != mvm->ftm_initiator.req)
390		return;
391
392	if (iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(TOF_RANGE_ABORT_CMD,
393						 LOCATION_GROUP, 0),
 
394				 0, sizeof(cmd), &cmd))
395		IWL_ERR(mvm, "failed to abort FTM process\n");
396}
397
398static int iwl_mvm_ftm_find_peer(struct cfg80211_pmsr_request *req,
399				 const u8 *addr)
400{
401	int i;
402
403	for (i = 0; i < req->n_peers; i++) {
404		struct cfg80211_pmsr_request_peer *peer = &req->peers[i];
405
406		if (ether_addr_equal_unaligned(peer->addr, addr))
407			return i;
408	}
409
410	return -ENOENT;
411}
412
413static u64 iwl_mvm_ftm_get_host_time(struct iwl_mvm *mvm, __le32 fw_gp2_ts)
414{
415	u32 gp2_ts = le32_to_cpu(fw_gp2_ts);
416	u32 curr_gp2, diff;
417	u64 now_from_boot_ns;
418
419	iwl_mvm_get_sync_time(mvm, &curr_gp2, &now_from_boot_ns);
 
420
421	if (curr_gp2 >= gp2_ts)
422		diff = curr_gp2 - gp2_ts;
423	else
424		diff = curr_gp2 + (U32_MAX - gp2_ts + 1);
425
426	return now_from_boot_ns - (u64)diff * 1000;
427}
428
429static void iwl_mvm_ftm_get_lci_civic(struct iwl_mvm *mvm,
430				      struct cfg80211_pmsr_result *res)
431{
432	struct iwl_mvm_loc_entry *entry;
433
434	list_for_each_entry(entry, &mvm->ftm_initiator.loc_list, list) {
435		if (!ether_addr_equal_unaligned(res->addr, entry->addr))
436			continue;
437
438		if (entry->lci_len) {
439			res->ftm.lci_len = entry->lci_len;
440			res->ftm.lci = entry->buf;
441		}
442
443		if (entry->civic_len) {
444			res->ftm.civicloc_len = entry->civic_len;
445			res->ftm.civicloc = entry->buf + entry->lci_len;
446		}
447
448		/* we found the entry we needed */
449		break;
450	}
451}
452
453static int iwl_mvm_ftm_range_resp_valid(struct iwl_mvm *mvm, u8 request_id,
454					u8 num_of_aps)
455{
456	lockdep_assert_held(&mvm->mutex);
457
458	if (request_id != (u8)mvm->ftm_initiator.req->cookie) {
459		IWL_ERR(mvm, "Request ID mismatch, got %u, active %u\n",
460			request_id, (u8)mvm->ftm_initiator.req->cookie);
461		return -EINVAL;
462	}
463
464	if (num_of_aps > mvm->ftm_initiator.req->n_peers) {
465		IWL_ERR(mvm, "FTM range response invalid\n");
466		return -EINVAL;
467	}
468
469	return 0;
470}
471
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
472static void iwl_mvm_debug_range_resp(struct iwl_mvm *mvm, u8 index,
473				     struct cfg80211_pmsr_result *res)
474{
475	s64 rtt_avg = div_s64(res->ftm.rtt_avg * 100, 6666);
476
477	IWL_DEBUG_INFO(mvm, "entry %d\n", index);
478	IWL_DEBUG_INFO(mvm, "\tstatus: %d\n", res->status);
479	IWL_DEBUG_INFO(mvm, "\tBSSID: %pM\n", res->addr);
480	IWL_DEBUG_INFO(mvm, "\thost time: %llu\n", res->host_time);
481	IWL_DEBUG_INFO(mvm, "\tburst index: %hhu\n", res->ftm.burst_index);
482	IWL_DEBUG_INFO(mvm, "\tsuccess num: %u\n", res->ftm.num_ftmr_successes);
483	IWL_DEBUG_INFO(mvm, "\trssi: %d\n", res->ftm.rssi_avg);
484	IWL_DEBUG_INFO(mvm, "\trssi spread: %hhu\n", res->ftm.rssi_spread);
485	IWL_DEBUG_INFO(mvm, "\trtt: %lld\n", res->ftm.rtt_avg);
486	IWL_DEBUG_INFO(mvm, "\trtt var: %llu\n", res->ftm.rtt_variance);
487	IWL_DEBUG_INFO(mvm, "\trtt spread: %llu\n", res->ftm.rtt_spread);
488	IWL_DEBUG_INFO(mvm, "\tdistance: %lld\n", rtt_avg);
489}
490
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
491void iwl_mvm_ftm_range_resp(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
492{
493	struct iwl_rx_packet *pkt = rxb_addr(rxb);
 
494	struct iwl_tof_range_rsp_ntfy_v5 *fw_resp_v5 = (void *)pkt->data;
495	struct iwl_tof_range_rsp_ntfy_v6 *fw_resp_v6 = (void *)pkt->data;
496	struct iwl_tof_range_rsp_ntfy *fw_resp = (void *)pkt->data;
 
497	int i;
498	bool new_api = fw_has_api(&mvm->fw->ucode_capa,
499				  IWL_UCODE_TLV_API_FTM_NEW_RANGE_REQ);
500	u8 num_of_aps, last_in_batch;
 
501
502	lockdep_assert_held(&mvm->mutex);
503
504	if (!mvm->ftm_initiator.req) {
505		IWL_ERR(mvm, "Got FTM response but have no request?\n");
506		return;
507	}
508
 
 
 
509	if (new_api) {
510		if (iwl_mvm_ftm_range_resp_valid(mvm, fw_resp->request_id,
511						 fw_resp->num_of_aps))
512			return;
513
514		num_of_aps = fw_resp->num_of_aps;
515		last_in_batch = fw_resp->last_report;
516	} else {
517		if (iwl_mvm_ftm_range_resp_valid(mvm, fw_resp_v5->request_id,
518						 fw_resp_v5->num_of_aps))
519			return;
520
521		num_of_aps = fw_resp_v5->num_of_aps;
522		last_in_batch = fw_resp_v5->last_in_batch;
523	}
524
525	IWL_DEBUG_INFO(mvm, "Range response received\n");
526	IWL_DEBUG_INFO(mvm, "request id: %lld, num of entries: %hhu\n",
527		       mvm->ftm_initiator.req->cookie, num_of_aps);
528
529	for (i = 0; i < num_of_aps && i < IWL_MVM_TOF_MAX_APS; i++) {
530		struct cfg80211_pmsr_result result = {};
531		struct iwl_tof_range_rsp_ap_entry_ntfy *fw_ap;
532		int peer_idx;
533
534		if (new_api) {
535			if (fw_has_api(&mvm->fw->ucode_capa,
536				       IWL_UCODE_TLV_API_FTM_RTT_ACCURACY))
537				fw_ap = &fw_resp->ap[i];
538			else
 
 
539				fw_ap = (void *)&fw_resp_v6->ap[i];
 
540
541			result.final = fw_resp->ap[i].last_burst;
542			result.ap_tsf = le32_to_cpu(fw_ap->start_tsf);
543			result.ap_tsf_valid = 1;
544		} else {
545			/* the first part is the same for old and new APIs */
546			fw_ap = (void *)&fw_resp_v5->ap[i];
547			/*
548			 * FIXME: the firmware needs to report this, we don't
549			 * even know the number of bursts the responder picked
550			 * (if we asked it to)
551			 */
552			result.final = 0;
553		}
554
555		peer_idx = iwl_mvm_ftm_find_peer(mvm->ftm_initiator.req,
556						 fw_ap->bssid);
557		if (peer_idx < 0) {
558			IWL_WARN(mvm,
559				 "Unknown address (%pM, target #%d) in FTM response\n",
560				 fw_ap->bssid, i);
561			continue;
562		}
563
564		switch (fw_ap->measure_status) {
565		case IWL_TOF_ENTRY_SUCCESS:
566			result.status = NL80211_PMSR_STATUS_SUCCESS;
567			break;
568		case IWL_TOF_ENTRY_TIMING_MEASURE_TIMEOUT:
569			result.status = NL80211_PMSR_STATUS_TIMEOUT;
570			break;
571		case IWL_TOF_ENTRY_NO_RESPONSE:
572			result.status = NL80211_PMSR_STATUS_FAILURE;
573			result.ftm.failure_reason =
574				NL80211_PMSR_FTM_FAILURE_NO_RESPONSE;
575			break;
576		case IWL_TOF_ENTRY_REQUEST_REJECTED:
577			result.status = NL80211_PMSR_STATUS_FAILURE;
578			result.ftm.failure_reason =
579				NL80211_PMSR_FTM_FAILURE_PEER_BUSY;
580			result.ftm.busy_retry_time = fw_ap->refusal_period;
581			break;
582		default:
583			result.status = NL80211_PMSR_STATUS_FAILURE;
584			result.ftm.failure_reason =
585				NL80211_PMSR_FTM_FAILURE_UNSPECIFIED;
586			break;
587		}
588		memcpy(result.addr, fw_ap->bssid, ETH_ALEN);
589		result.host_time = iwl_mvm_ftm_get_host_time(mvm,
590							     fw_ap->timestamp);
591		result.type = NL80211_PMSR_TYPE_FTM;
592		result.ftm.burst_index = mvm->ftm_initiator.responses[peer_idx];
593		mvm->ftm_initiator.responses[peer_idx]++;
594		result.ftm.rssi_avg = fw_ap->rssi;
595		result.ftm.rssi_avg_valid = 1;
596		result.ftm.rssi_spread = fw_ap->rssi_spread;
597		result.ftm.rssi_spread_valid = 1;
598		result.ftm.rtt_avg = (s32)le32_to_cpu(fw_ap->rtt);
599		result.ftm.rtt_avg_valid = 1;
600		result.ftm.rtt_variance = le32_to_cpu(fw_ap->rtt_variance);
601		result.ftm.rtt_variance_valid = 1;
602		result.ftm.rtt_spread = le32_to_cpu(fw_ap->rtt_spread);
603		result.ftm.rtt_spread_valid = 1;
604
605		iwl_mvm_ftm_get_lci_civic(mvm, &result);
606
 
 
607		cfg80211_pmsr_report(mvm->ftm_initiator.req_wdev,
608				     mvm->ftm_initiator.req,
609				     &result, GFP_KERNEL);
610
611		if (fw_has_api(&mvm->fw->ucode_capa,
612			       IWL_UCODE_TLV_API_FTM_RTT_ACCURACY))
613			IWL_DEBUG_INFO(mvm, "RTT confidence: %hhu\n",
614				       fw_ap->rttConfidence);
615
616		iwl_mvm_debug_range_resp(mvm, i, &result);
617	}
618
619	if (last_in_batch) {
620		cfg80211_pmsr_complete(mvm->ftm_initiator.req_wdev,
621				       mvm->ftm_initiator.req,
622				       GFP_KERNEL);
623		iwl_mvm_ftm_reset(mvm);
624	}
625}
626
627void iwl_mvm_ftm_lc_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
628{
629	struct iwl_rx_packet *pkt = rxb_addr(rxb);
630	const struct ieee80211_mgmt *mgmt = (void *)pkt->data;
631	size_t len = iwl_rx_packet_payload_len(pkt);
632	struct iwl_mvm_loc_entry *entry;
633	const u8 *ies, *lci, *civic, *msr_ie;
634	size_t ies_len, lci_len = 0, civic_len = 0;
635	size_t baselen = IEEE80211_MIN_ACTION_SIZE +
636			 sizeof(mgmt->u.action.u.ftm);
637	static const u8 rprt_type_lci = IEEE80211_SPCT_MSR_RPRT_TYPE_LCI;
638	static const u8 rprt_type_civic = IEEE80211_SPCT_MSR_RPRT_TYPE_CIVIC;
639
640	if (len <= baselen)
641		return;
642
643	lockdep_assert_held(&mvm->mutex);
644
645	ies = mgmt->u.action.u.ftm.variable;
646	ies_len = len - baselen;
647
648	msr_ie = cfg80211_find_ie_match(WLAN_EID_MEASURE_REPORT, ies, ies_len,
649					&rprt_type_lci, 1, 4);
650	if (msr_ie) {
651		lci = msr_ie + 2;
652		lci_len = msr_ie[1];
653	}
654
655	msr_ie = cfg80211_find_ie_match(WLAN_EID_MEASURE_REPORT, ies, ies_len,
656					&rprt_type_civic, 1, 4);
657	if (msr_ie) {
658		civic = msr_ie + 2;
659		civic_len = msr_ie[1];
660	}
661
662	entry = kmalloc(sizeof(*entry) + lci_len + civic_len, GFP_KERNEL);
663	if (!entry)
664		return;
665
666	memcpy(entry->addr, mgmt->bssid, ETH_ALEN);
667
668	entry->lci_len = lci_len;
669	if (lci_len)
670		memcpy(entry->buf, lci, lci_len);
671
672	entry->civic_len = civic_len;
673	if (civic_len)
674		memcpy(entry->buf + lci_len, civic, civic_len);
675
676	list_add_tail(&entry->list, &mvm->ftm_initiator.loc_list);
677}