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#if defined(__linux__)
258				   struct iwl_tof_range_req_cmd_v9 *cmd,
259#elif defined(__FreeBSD__)
260				   struct iwl_tof_range_req_cmd_v9 *cmd,	/* XXX-BZ Probably better solved by a common struct in fw for top parts of the struct. */
261#endif
262				   struct cfg80211_pmsr_request *req)
263{
264	int i;
265
266	cmd->initiator_flags =
267		cpu_to_le32(IWL_TOF_INITIATOR_FLAGS_MACADDR_RANDOM |
268			    IWL_TOF_INITIATOR_FLAGS_NON_ASAP_SUPPORT);
269	cmd->request_id = req->cookie;
270	cmd->num_of_ap = req->n_peers;
271
272	/*
273	 * Use a large value for "no timeout". Don't use the maximum value
274	 * because of fw limitations.
275	 */
276	if (req->timeout)
277		cmd->req_timeout_ms = cpu_to_le32(req->timeout);
278	else
279		cmd->req_timeout_ms = cpu_to_le32(0xfffff);
280
281	memcpy(cmd->macaddr_template, req->mac_addr, ETH_ALEN);
282	for (i = 0; i < ETH_ALEN; i++)
283		cmd->macaddr_mask[i] = ~req->mac_addr_mask[i];
284
285	if (vif->cfg.assoc) {
286		memcpy(cmd->range_req_bssid, vif->bss_conf.bssid, ETH_ALEN);
287
288		/* AP's TSF is only relevant if associated */
289		for (i = 0; i < req->n_peers; i++) {
290			if (req->peers[i].report_ap_tsf) {
291				struct iwl_mvm_vif *mvmvif =
292					iwl_mvm_vif_from_mac80211(vif);
293
294				cmd->tsf_mac_id = cpu_to_le32(mvmvif->id);
295				return;
296			}
297		}
298	} else {
299		eth_broadcast_addr(cmd->range_req_bssid);
300	}
301
302	/* Don't report AP's TSF */
303	cmd->tsf_mac_id = cpu_to_le32(0xff);
304}
305
306static void iwl_mvm_ftm_cmd_v8(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
307			       struct iwl_tof_range_req_cmd_v8 *cmd,
308			       struct cfg80211_pmsr_request *req)
309{
310	iwl_mvm_ftm_cmd_common(mvm, vif, (void *)cmd, req);
311}
312
313static int
314iwl_mvm_ftm_target_chandef_v1(struct iwl_mvm *mvm,
315			      struct cfg80211_pmsr_request_peer *peer,
316			      u8 *channel, u8 *bandwidth,
317			      u8 *ctrl_ch_position)
318{
319	u32 freq = peer->chandef.chan->center_freq;
320
321	*channel = ieee80211_frequency_to_channel(freq);
322
323	switch (peer->chandef.width) {
324	case NL80211_CHAN_WIDTH_20_NOHT:
325		*bandwidth = IWL_TOF_BW_20_LEGACY;
326		break;
327	case NL80211_CHAN_WIDTH_20:
328		*bandwidth = IWL_TOF_BW_20_HT;
329		break;
330	case NL80211_CHAN_WIDTH_40:
331		*bandwidth = IWL_TOF_BW_40;
332		break;
333	case NL80211_CHAN_WIDTH_80:
334		*bandwidth = IWL_TOF_BW_80;
335		break;
336	default:
337		IWL_ERR(mvm, "Unsupported BW in FTM request (%d)\n",
338			peer->chandef.width);
339		return -EINVAL;
340	}
341
342	*ctrl_ch_position = (peer->chandef.width > NL80211_CHAN_WIDTH_20) ?
343		iwl_mvm_get_ctrl_pos(&peer->chandef) : 0;
344
345	return 0;
346}
347
348static int
349iwl_mvm_ftm_target_chandef_v2(struct iwl_mvm *mvm,
350			      struct cfg80211_pmsr_request_peer *peer,
351			      u8 *channel, u8 *format_bw,
352			      u8 *ctrl_ch_position)
353{
354	u32 freq = peer->chandef.chan->center_freq;
355	u8 cmd_ver;
356
357	*channel = ieee80211_frequency_to_channel(freq);
358
359	switch (peer->chandef.width) {
360	case NL80211_CHAN_WIDTH_20_NOHT:
361		*format_bw = IWL_LOCATION_FRAME_FORMAT_LEGACY;
362		*format_bw |= IWL_LOCATION_BW_20MHZ << LOCATION_BW_POS;
363		break;
364	case NL80211_CHAN_WIDTH_20:
365		*format_bw = IWL_LOCATION_FRAME_FORMAT_HT;
366		*format_bw |= IWL_LOCATION_BW_20MHZ << LOCATION_BW_POS;
367		break;
368	case NL80211_CHAN_WIDTH_40:
369		*format_bw = IWL_LOCATION_FRAME_FORMAT_HT;
370		*format_bw |= IWL_LOCATION_BW_40MHZ << LOCATION_BW_POS;
371		break;
372	case NL80211_CHAN_WIDTH_80:
373		*format_bw = IWL_LOCATION_FRAME_FORMAT_VHT;
374		*format_bw |= IWL_LOCATION_BW_80MHZ << LOCATION_BW_POS;
375		break;
376	case NL80211_CHAN_WIDTH_160:
377		cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw,
378						WIDE_ID(LOCATION_GROUP, TOF_RANGE_REQ_CMD),
379						IWL_FW_CMD_VER_UNKNOWN);
380
381		if (cmd_ver >= 13) {
382			*format_bw = IWL_LOCATION_FRAME_FORMAT_HE;
383			*format_bw |= IWL_LOCATION_BW_160MHZ << LOCATION_BW_POS;
384			break;
385		}
386		fallthrough;
387	default:
388		IWL_ERR(mvm, "Unsupported BW in FTM request (%d)\n",
389			peer->chandef.width);
390		return -EINVAL;
391	}
392
393	/* non EDCA based measurement must use HE preamble */
394	if (peer->ftm.trigger_based || peer->ftm.non_trigger_based)
395		*format_bw |= IWL_LOCATION_FRAME_FORMAT_HE;
396
397	*ctrl_ch_position = (peer->chandef.width > NL80211_CHAN_WIDTH_20) ?
398		iwl_mvm_get_ctrl_pos(&peer->chandef) : 0;
399
400	return 0;
401}
402
403static int
404iwl_mvm_ftm_put_target_v2(struct iwl_mvm *mvm,
405			  struct cfg80211_pmsr_request_peer *peer,
406			  struct iwl_tof_range_req_ap_entry_v2 *target)
407{
408	int ret;
409
410	ret = iwl_mvm_ftm_target_chandef_v1(mvm, peer, &target->channel_num,
411					    &target->bandwidth,
412					    &target->ctrl_ch_position);
413	if (ret)
414		return ret;
415
416	memcpy(target->bssid, peer->addr, ETH_ALEN);
417	target->burst_period =
418		cpu_to_le16(peer->ftm.burst_period);
419	target->samples_per_burst = peer->ftm.ftms_per_burst;
420	target->num_of_bursts = peer->ftm.num_bursts_exp;
421	target->measure_type = 0; /* regular two-sided FTM */
422	target->retries_per_sample = peer->ftm.ftmr_retries;
423	target->asap_mode = peer->ftm.asap;
424	target->enable_dyn_ack = IWL_MVM_FTM_INITIATOR_DYNACK;
425
426	if (peer->ftm.request_lci)
427		target->location_req |= IWL_TOF_LOC_LCI;
428	if (peer->ftm.request_civicloc)
429		target->location_req |= IWL_TOF_LOC_CIVIC;
430
431	target->algo_type = IWL_MVM_FTM_INITIATOR_ALGO;
432
433	return 0;
434}
435
436#define FTM_PUT_FLAG(flag)	(target->initiator_ap_flags |= \
437				 cpu_to_le32(IWL_INITIATOR_AP_FLAGS_##flag))
438
439static void
440iwl_mvm_ftm_put_target_common(struct iwl_mvm *mvm,
441			      struct cfg80211_pmsr_request_peer *peer,
442			      struct iwl_tof_range_req_ap_entry_v6 *target)
443{
444	memcpy(target->bssid, peer->addr, ETH_ALEN);
445	target->burst_period =
446		cpu_to_le16(peer->ftm.burst_period);
447	target->samples_per_burst = peer->ftm.ftms_per_burst;
448	target->num_of_bursts = peer->ftm.num_bursts_exp;
449	target->ftmr_max_retries = peer->ftm.ftmr_retries;
450	target->initiator_ap_flags = cpu_to_le32(0);
451
452	if (peer->ftm.asap)
453		FTM_PUT_FLAG(ASAP);
454
455	if (peer->ftm.request_lci)
456		FTM_PUT_FLAG(LCI_REQUEST);
457
458	if (peer->ftm.request_civicloc)
459		FTM_PUT_FLAG(CIVIC_REQUEST);
460
461	if (IWL_MVM_FTM_INITIATOR_DYNACK)
462		FTM_PUT_FLAG(DYN_ACK);
463
464	if (IWL_MVM_FTM_INITIATOR_ALGO == IWL_TOF_ALGO_TYPE_LINEAR_REG)
465		FTM_PUT_FLAG(ALGO_LR);
466	else if (IWL_MVM_FTM_INITIATOR_ALGO == IWL_TOF_ALGO_TYPE_FFT)
467		FTM_PUT_FLAG(ALGO_FFT);
468
469	if (peer->ftm.trigger_based)
470		FTM_PUT_FLAG(TB);
471	else if (peer->ftm.non_trigger_based)
472		FTM_PUT_FLAG(NON_TB);
473
474	if ((peer->ftm.trigger_based || peer->ftm.non_trigger_based) &&
475	    peer->ftm.lmr_feedback)
476		FTM_PUT_FLAG(LMR_FEEDBACK);
477}
478
479static int
480iwl_mvm_ftm_put_target_v3(struct iwl_mvm *mvm,
481			  struct cfg80211_pmsr_request_peer *peer,
482			  struct iwl_tof_range_req_ap_entry_v3 *target)
483{
484	int ret;
485
486	ret = iwl_mvm_ftm_target_chandef_v1(mvm, peer, &target->channel_num,
487					    &target->bandwidth,
488					    &target->ctrl_ch_position);
489	if (ret)
490		return ret;
491
492	/*
493	 * Versions 3 and 4 has some common fields, so
494	 * iwl_mvm_ftm_put_target_common() can be used for version 7 too.
495	 */
496	iwl_mvm_ftm_put_target_common(mvm, peer, (void *)target);
497
498	return 0;
499}
500
501static int
502iwl_mvm_ftm_put_target_v4(struct iwl_mvm *mvm,
503			  struct cfg80211_pmsr_request_peer *peer,
504			  struct iwl_tof_range_req_ap_entry_v4 *target)
505{
506	int ret;
507
508	ret = iwl_mvm_ftm_target_chandef_v2(mvm, peer, &target->channel_num,
509					    &target->format_bw,
510					    &target->ctrl_ch_position);
511	if (ret)
512		return ret;
513
514	iwl_mvm_ftm_put_target_common(mvm, peer, (void *)target);
515
516	return 0;
517}
518
519static int
520iwl_mvm_ftm_put_target(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
521		       struct cfg80211_pmsr_request_peer *peer,
522		       struct iwl_tof_range_req_ap_entry_v6 *target)
523{
524	int ret;
525
526	ret = iwl_mvm_ftm_target_chandef_v2(mvm, peer, &target->channel_num,
527					    &target->format_bw,
528					    &target->ctrl_ch_position);
529	if (ret)
530		return ret;
531
532	iwl_mvm_ftm_put_target_common(mvm, peer, target);
533
534	if (vif->cfg.assoc) {
535		struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
536		struct ieee80211_sta *sta;
537		struct ieee80211_bss_conf *link_conf;
538		unsigned int link_id;
539
540		rcu_read_lock();
541		for_each_vif_active_link(vif, link_conf, link_id) {
542			if (memcmp(peer->addr, link_conf->bssid, ETH_ALEN))
543				continue;
544
545			target->sta_id = mvmvif->link[link_id]->ap_sta_id;
546			sta = rcu_dereference(mvm->fw_id_to_mac_id[target->sta_id]);
547			if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta))) {
548				rcu_read_unlock();
549				return PTR_ERR_OR_ZERO(sta);
550			}
551
552			if (sta->mfp && (peer->ftm.trigger_based ||
553					 peer->ftm.non_trigger_based))
554				FTM_PUT_FLAG(PMF);
555			break;
556		}
557		rcu_read_unlock();
558	} else {
559		target->sta_id = IWL_MVM_INVALID_STA;
560	}
561
562	/*
563	 * TODO: Beacon interval is currently unknown, so use the common value
564	 * of 100 TUs.
565	 */
566	target->beacon_interval = cpu_to_le16(100);
567	return 0;
568}
569
570static int iwl_mvm_ftm_send_cmd(struct iwl_mvm *mvm, struct iwl_host_cmd *hcmd)
571{
572	u32 status;
573	int err = iwl_mvm_send_cmd_status(mvm, hcmd, &status);
574
575	if (!err && status) {
576		IWL_ERR(mvm, "FTM range request command failure, status: %u\n",
577			status);
578		err = iwl_ftm_range_request_status_to_err(status);
579	}
580
581	return err;
582}
583
584static int iwl_mvm_ftm_start_v5(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
585				struct cfg80211_pmsr_request *req)
586{
587	struct iwl_tof_range_req_cmd_v5 cmd_v5;
588	struct iwl_host_cmd hcmd = {
589		.id = WIDE_ID(LOCATION_GROUP, TOF_RANGE_REQ_CMD),
590		.dataflags[0] = IWL_HCMD_DFL_DUP,
591		.data[0] = &cmd_v5,
592		.len[0] = sizeof(cmd_v5),
593	};
594	u8 i;
595	int err;
596
597	iwl_mvm_ftm_cmd_v5(mvm, vif, &cmd_v5, req);
598
599	for (i = 0; i < cmd_v5.num_of_ap; i++) {
600		struct cfg80211_pmsr_request_peer *peer = &req->peers[i];
601
602		err = iwl_mvm_ftm_put_target_v2(mvm, peer, &cmd_v5.ap[i]);
603		if (err)
604			return err;
605	}
606
607	return iwl_mvm_ftm_send_cmd(mvm, &hcmd);
608}
609
610static int iwl_mvm_ftm_start_v7(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
611				struct cfg80211_pmsr_request *req)
612{
613	struct iwl_tof_range_req_cmd_v7 cmd_v7;
614	struct iwl_host_cmd hcmd = {
615		.id = WIDE_ID(LOCATION_GROUP, TOF_RANGE_REQ_CMD),
616		.dataflags[0] = IWL_HCMD_DFL_DUP,
617		.data[0] = &cmd_v7,
618		.len[0] = sizeof(cmd_v7),
619	};
620	u8 i;
621	int err;
622
623	/*
624	 * Versions 7 and 8 has the same structure except from the responders
625	 * list, so iwl_mvm_ftm_cmd() can be used for version 7 too.
626	 */
627	iwl_mvm_ftm_cmd_v8(mvm, vif, (void *)&cmd_v7, req);
628
629	for (i = 0; i < cmd_v7.num_of_ap; i++) {
630		struct cfg80211_pmsr_request_peer *peer = &req->peers[i];
631
632		err = iwl_mvm_ftm_put_target_v3(mvm, peer, &cmd_v7.ap[i]);
633		if (err)
634			return err;
635	}
636
637	return iwl_mvm_ftm_send_cmd(mvm, &hcmd);
638}
639
640static int iwl_mvm_ftm_start_v8(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
641				struct cfg80211_pmsr_request *req)
642{
643	struct iwl_tof_range_req_cmd_v8 cmd;
644	struct iwl_host_cmd hcmd = {
645		.id = WIDE_ID(LOCATION_GROUP, TOF_RANGE_REQ_CMD),
646		.dataflags[0] = IWL_HCMD_DFL_DUP,
647		.data[0] = &cmd,
648		.len[0] = sizeof(cmd),
649	};
650	u8 i;
651	int err;
652
653	iwl_mvm_ftm_cmd_v8(mvm, vif, (void *)&cmd, req);
654
655	for (i = 0; i < cmd.num_of_ap; i++) {
656		struct cfg80211_pmsr_request_peer *peer = &req->peers[i];
657
658		err = iwl_mvm_ftm_put_target_v4(mvm, peer, &cmd.ap[i]);
659		if (err)
660			return err;
661	}
662
663	return iwl_mvm_ftm_send_cmd(mvm, &hcmd);
664}
665
666static int iwl_mvm_ftm_start_v9(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
667				struct cfg80211_pmsr_request *req)
668{
669	struct iwl_tof_range_req_cmd_v9 cmd;
670	struct iwl_host_cmd hcmd = {
671		.id = WIDE_ID(LOCATION_GROUP, TOF_RANGE_REQ_CMD),
672		.dataflags[0] = IWL_HCMD_DFL_DUP,
673		.data[0] = &cmd,
674		.len[0] = sizeof(cmd),
675	};
676	u8 i;
677	int err;
678
679	iwl_mvm_ftm_cmd_common(mvm, vif, &cmd, req);
680
681	for (i = 0; i < cmd.num_of_ap; i++) {
682		struct cfg80211_pmsr_request_peer *peer = &req->peers[i];
683		struct iwl_tof_range_req_ap_entry_v6 *target = &cmd.ap[i];
684
685		err = iwl_mvm_ftm_put_target(mvm, vif, peer, target);
686		if (err)
687			return err;
688	}
689
690	return iwl_mvm_ftm_send_cmd(mvm, &hcmd);
691}
692
693static void iter(struct ieee80211_hw *hw,
694		 struct ieee80211_vif *vif,
695		 struct ieee80211_sta *sta,
696		 struct ieee80211_key_conf *key,
697		 void *data)
698{
699	struct iwl_tof_range_req_ap_entry_v6 *target = data;
700
701	if (!sta || memcmp(sta->addr, target->bssid, ETH_ALEN))
702		return;
703
704	WARN_ON(!sta->mfp);
705
706	if (WARN_ON(key->keylen > sizeof(target->tk)))
707		return;
708
709	memcpy(target->tk, key->key, key->keylen);
710	target->cipher = iwl_mvm_cipher_to_location_cipher(key->cipher);
711	WARN_ON(target->cipher == IWL_LOCATION_CIPHER_INVALID);
712}
713
714static void
715iwl_mvm_ftm_set_secured_ranging(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
716				struct iwl_tof_range_req_ap_entry_v7 *target)
717{
718	struct iwl_mvm_ftm_pasn_entry *entry;
719	u32 flags = le32_to_cpu(target->initiator_ap_flags);
720
721	if (!(flags & (IWL_INITIATOR_AP_FLAGS_NON_TB |
722		       IWL_INITIATOR_AP_FLAGS_TB)))
723		return;
724
725	lockdep_assert_held(&mvm->mutex);
726
727	list_for_each_entry(entry, &mvm->ftm_initiator.pasn_list, list) {
728		if (memcmp(entry->addr, target->bssid, sizeof(entry->addr)))
729			continue;
730
731		target->cipher = entry->cipher;
732
733		if (entry->flags & IWL_MVM_PASN_FLAG_HAS_HLTK)
734			memcpy(target->hltk, entry->hltk, sizeof(target->hltk));
735		else
736			memset(target->hltk, 0, sizeof(target->hltk));
737
738		if (vif->cfg.assoc &&
739		    !memcmp(vif->bss_conf.bssid, target->bssid,
740			    sizeof(target->bssid)))
741			ieee80211_iter_keys(mvm->hw, vif, iter, target);
742		else
743			memcpy(target->tk, entry->tk, sizeof(target->tk));
744
745		memcpy(target->rx_pn, entry->rx_pn, sizeof(target->rx_pn));
746		memcpy(target->tx_pn, entry->tx_pn, sizeof(target->tx_pn));
747
748		target->initiator_ap_flags |=
749			cpu_to_le32(IWL_INITIATOR_AP_FLAGS_SECURED);
750		return;
751	}
752}
753
754static int
755iwl_mvm_ftm_put_target_v7(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
756			  struct cfg80211_pmsr_request_peer *peer,
757			  struct iwl_tof_range_req_ap_entry_v7 *target)
758{
759	int err = iwl_mvm_ftm_put_target(mvm, vif, peer, (void *)target);
760	if (err)
761		return err;
762
763	iwl_mvm_ftm_set_secured_ranging(mvm, vif, target);
764	return err;
765}
766
767static int iwl_mvm_ftm_start_v11(struct iwl_mvm *mvm,
768				 struct ieee80211_vif *vif,
769				 struct cfg80211_pmsr_request *req)
770{
771	struct iwl_tof_range_req_cmd_v11 cmd;
772	struct iwl_host_cmd hcmd = {
773		.id = WIDE_ID(LOCATION_GROUP, TOF_RANGE_REQ_CMD),
774		.dataflags[0] = IWL_HCMD_DFL_DUP,
775		.data[0] = &cmd,
776		.len[0] = sizeof(cmd),
777	};
778	u8 i;
779	int err;
780
781	iwl_mvm_ftm_cmd_common(mvm, vif, (void *)&cmd, req);
782
783	for (i = 0; i < cmd.num_of_ap; i++) {
784		struct cfg80211_pmsr_request_peer *peer = &req->peers[i];
785		struct iwl_tof_range_req_ap_entry_v7 *target = &cmd.ap[i];
786
787		err = iwl_mvm_ftm_put_target_v7(mvm, vif, peer, target);
788		if (err)
789			return err;
790	}
791
792	return iwl_mvm_ftm_send_cmd(mvm, &hcmd);
793}
794
795static void
796iwl_mvm_ftm_set_ndp_params(struct iwl_mvm *mvm,
797			   struct iwl_tof_range_req_ap_entry_v8 *target)
798{
799	/* Only 2 STS are supported on Tx */
800	u32 i2r_max_sts = IWL_MVM_FTM_I2R_MAX_STS > 1 ? 1 :
801		IWL_MVM_FTM_I2R_MAX_STS;
802
803	target->r2i_ndp_params = IWL_MVM_FTM_R2I_MAX_REP |
804		(IWL_MVM_FTM_R2I_MAX_STS << IWL_LOCATION_MAX_STS_POS);
805	target->i2r_ndp_params = IWL_MVM_FTM_I2R_MAX_REP |
806		(i2r_max_sts << IWL_LOCATION_MAX_STS_POS);
807	target->r2i_max_total_ltf = IWL_MVM_FTM_R2I_MAX_TOTAL_LTF;
808	target->i2r_max_total_ltf = IWL_MVM_FTM_I2R_MAX_TOTAL_LTF;
809}
810
811static int
812iwl_mvm_ftm_put_target_v8(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
813			  struct cfg80211_pmsr_request_peer *peer,
814			  struct iwl_tof_range_req_ap_entry_v8 *target)
815{
816	u32 flags;
817	int ret = iwl_mvm_ftm_put_target_v7(mvm, vif, peer, (void *)target);
818
819	if (ret)
820		return ret;
821
822	iwl_mvm_ftm_set_ndp_params(mvm, target);
823
824	/*
825	 * If secure LTF is turned off, replace the flag with PMF only
826	 */
827	flags = le32_to_cpu(target->initiator_ap_flags);
828	if ((flags & IWL_INITIATOR_AP_FLAGS_SECURED) &&
829	    !IWL_MVM_FTM_INITIATOR_SECURE_LTF) {
830		flags &= ~IWL_INITIATOR_AP_FLAGS_SECURED;
831		flags |= IWL_INITIATOR_AP_FLAGS_PMF;
832		target->initiator_ap_flags = cpu_to_le32(flags);
833	}
834
835	return 0;
836}
837
838static int iwl_mvm_ftm_start_v12(struct iwl_mvm *mvm,
839				 struct ieee80211_vif *vif,
840				 struct cfg80211_pmsr_request *req)
841{
842	struct iwl_tof_range_req_cmd_v12 cmd;
843	struct iwl_host_cmd hcmd = {
844		.id = WIDE_ID(LOCATION_GROUP, TOF_RANGE_REQ_CMD),
845		.dataflags[0] = IWL_HCMD_DFL_DUP,
846		.data[0] = &cmd,
847		.len[0] = sizeof(cmd),
848	};
849	u8 i;
850	int err;
851
852	iwl_mvm_ftm_cmd_common(mvm, vif, (void *)&cmd, req);
853
854	for (i = 0; i < cmd.num_of_ap; i++) {
855		struct cfg80211_pmsr_request_peer *peer = &req->peers[i];
856		struct iwl_tof_range_req_ap_entry_v8 *target = &cmd.ap[i];
857
858		err = iwl_mvm_ftm_put_target_v8(mvm, vif, peer, target);
859		if (err)
860			return err;
861	}
862
863	return iwl_mvm_ftm_send_cmd(mvm, &hcmd);
864}
865
866static int iwl_mvm_ftm_start_v13(struct iwl_mvm *mvm,
867				 struct ieee80211_vif *vif,
868				 struct cfg80211_pmsr_request *req)
869{
870	struct iwl_tof_range_req_cmd_v13 cmd;
871	struct iwl_host_cmd hcmd = {
872		.id = WIDE_ID(LOCATION_GROUP, TOF_RANGE_REQ_CMD),
873		.dataflags[0] = IWL_HCMD_DFL_DUP,
874		.data[0] = &cmd,
875		.len[0] = sizeof(cmd),
876	};
877	u8 i;
878	int err;
879
880	iwl_mvm_ftm_cmd_common(mvm, vif, (void *)&cmd, req);
881
882	for (i = 0; i < cmd.num_of_ap; i++) {
883		struct cfg80211_pmsr_request_peer *peer = &req->peers[i];
884		struct iwl_tof_range_req_ap_entry_v9 *target = &cmd.ap[i];
885
886		err = iwl_mvm_ftm_put_target_v8(mvm, vif, peer, (void *)target);
887		if (err)
888			return err;
889
890		if (peer->ftm.trigger_based || peer->ftm.non_trigger_based)
891			target->bss_color = peer->ftm.bss_color;
892
893		if (peer->ftm.non_trigger_based) {
894			target->min_time_between_msr =
895				cpu_to_le16(IWL_MVM_FTM_NON_TB_MIN_TIME_BETWEEN_MSR);
896			target->burst_period =
897				cpu_to_le16(IWL_MVM_FTM_NON_TB_MAX_TIME_BETWEEN_MSR);
898		} else {
899			target->min_time_between_msr = cpu_to_le16(0);
900		}
901
902		target->band =
903			iwl_mvm_phy_band_from_nl80211(peer->chandef.chan->band);
904	}
905
906	return iwl_mvm_ftm_send_cmd(mvm, &hcmd);
907}
908
909int iwl_mvm_ftm_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
910		      struct cfg80211_pmsr_request *req)
911{
912	bool new_api = fw_has_api(&mvm->fw->ucode_capa,
913				  IWL_UCODE_TLV_API_FTM_NEW_RANGE_REQ);
914	int err;
915
916	lockdep_assert_held(&mvm->mutex);
917
918	if (mvm->ftm_initiator.req)
919		return -EBUSY;
920
921	if (new_api) {
922		u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw,
923						   WIDE_ID(LOCATION_GROUP, TOF_RANGE_REQ_CMD),
924						   IWL_FW_CMD_VER_UNKNOWN);
925
926		switch (cmd_ver) {
927		case 13:
928			err = iwl_mvm_ftm_start_v13(mvm, vif, req);
929			break;
930		case 12:
931			err = iwl_mvm_ftm_start_v12(mvm, vif, req);
932			break;
933		case 11:
934			err = iwl_mvm_ftm_start_v11(mvm, vif, req);
935			break;
936		case 9:
937		case 10:
938			err = iwl_mvm_ftm_start_v9(mvm, vif, req);
939			break;
940		case 8:
941			err = iwl_mvm_ftm_start_v8(mvm, vif, req);
942			break;
943		default:
944			err = iwl_mvm_ftm_start_v7(mvm, vif, req);
945			break;
946		}
947	} else {
948		err = iwl_mvm_ftm_start_v5(mvm, vif, req);
949	}
950
951	if (!err) {
952		mvm->ftm_initiator.req = req;
953		mvm->ftm_initiator.req_wdev = ieee80211_vif_to_wdev(vif);
954	}
955
956	return err;
957}
958
959void iwl_mvm_ftm_abort(struct iwl_mvm *mvm, struct cfg80211_pmsr_request *req)
960{
961	struct iwl_tof_range_abort_cmd cmd = {
962		.request_id = req->cookie,
963	};
964
965	lockdep_assert_held(&mvm->mutex);
966
967	if (req != mvm->ftm_initiator.req)
968		return;
969
970	iwl_mvm_ftm_reset(mvm);
971
972	if (iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(LOCATION_GROUP, TOF_RANGE_ABORT_CMD),
973				 0, sizeof(cmd), &cmd))
974		IWL_ERR(mvm, "failed to abort FTM process\n");
975}
976
977static int iwl_mvm_ftm_find_peer(struct cfg80211_pmsr_request *req,
978				 const u8 *addr)
979{
980	int i;
981
982	for (i = 0; i < req->n_peers; i++) {
983		struct cfg80211_pmsr_request_peer *peer = &req->peers[i];
984
985		if (ether_addr_equal_unaligned(peer->addr, addr))
986			return i;
987	}
988
989	return -ENOENT;
990}
991
992static u64 iwl_mvm_ftm_get_host_time(struct iwl_mvm *mvm, __le32 fw_gp2_ts)
993{
994	u32 gp2_ts = le32_to_cpu(fw_gp2_ts);
995	u32 curr_gp2, diff;
996	u64 now_from_boot_ns;
997
998	iwl_mvm_get_sync_time(mvm, CLOCK_BOOTTIME, &curr_gp2,
999			      &now_from_boot_ns, NULL);
1000
1001	if (curr_gp2 >= gp2_ts)
1002		diff = curr_gp2 - gp2_ts;
1003	else
1004		diff = curr_gp2 + (U32_MAX - gp2_ts + 1);
1005
1006	return now_from_boot_ns - (u64)diff * 1000;
1007}
1008
1009static void iwl_mvm_ftm_get_lci_civic(struct iwl_mvm *mvm,
1010				      struct cfg80211_pmsr_result *res)
1011{
1012	struct iwl_mvm_loc_entry *entry;
1013
1014	list_for_each_entry(entry, &mvm->ftm_initiator.loc_list, list) {
1015		if (!ether_addr_equal_unaligned(res->addr, entry->addr))
1016			continue;
1017
1018		if (entry->lci_len) {
1019			res->ftm.lci_len = entry->lci_len;
1020			res->ftm.lci = entry->buf;
1021		}
1022
1023		if (entry->civic_len) {
1024			res->ftm.civicloc_len = entry->civic_len;
1025			res->ftm.civicloc = entry->buf + entry->lci_len;
1026		}
1027
1028		/* we found the entry we needed */
1029		break;
1030	}
1031}
1032
1033static int iwl_mvm_ftm_range_resp_valid(struct iwl_mvm *mvm, u8 request_id,
1034					u8 num_of_aps)
1035{
1036	lockdep_assert_held(&mvm->mutex);
1037
1038	if (request_id != (u8)mvm->ftm_initiator.req->cookie) {
1039		IWL_ERR(mvm, "Request ID mismatch, got %u, active %u\n",
1040			request_id, (u8)mvm->ftm_initiator.req->cookie);
1041		return -EINVAL;
1042	}
1043
1044	if (num_of_aps > mvm->ftm_initiator.req->n_peers) {
1045		IWL_ERR(mvm, "FTM range response invalid\n");
1046		return -EINVAL;
1047	}
1048
1049	return 0;
1050}
1051
1052static void iwl_mvm_ftm_rtt_smoothing(struct iwl_mvm *mvm,
1053				      struct cfg80211_pmsr_result *res)
1054{
1055	struct iwl_mvm_smooth_entry *resp = NULL, *iter;
1056	s64 rtt_avg, rtt = res->ftm.rtt_avg;
1057	u32 undershoot, overshoot;
1058	u8 alpha;
1059
1060	if (!IWL_MVM_FTM_INITIATOR_ENABLE_SMOOTH)
1061		return;
1062
1063	WARN_ON(rtt < 0);
1064
1065	if (res->status != NL80211_PMSR_STATUS_SUCCESS) {
1066		IWL_DEBUG_INFO(mvm,
1067			       ": %pM: ignore failed measurement. Status=%u\n",
1068			       res->addr, res->status);
1069		return;
1070	}
1071
1072	list_for_each_entry(iter, &mvm->ftm_initiator.smooth.resp, list) {
1073		if (!memcmp(res->addr, iter->addr, ETH_ALEN)) {
1074			resp = iter;
1075			break;
1076		}
1077	}
1078
1079	if (!resp) {
1080		resp = kzalloc(sizeof(*resp), GFP_KERNEL);
1081		if (!resp)
1082			return;
1083
1084		memcpy(resp->addr, res->addr, ETH_ALEN);
1085		list_add_tail(&resp->list, &mvm->ftm_initiator.smooth.resp);
1086
1087		resp->rtt_avg = rtt;
1088
1089		IWL_DEBUG_INFO(mvm, "new: %pM: rtt_avg=%lld\n",
1090			       resp->addr, resp->rtt_avg);
1091		goto update_time;
1092	}
1093
1094	if (res->host_time - resp->host_time >
1095	    IWL_MVM_FTM_INITIATOR_SMOOTH_AGE_SEC * 1000000000) {
1096		resp->rtt_avg = rtt;
1097
1098		IWL_DEBUG_INFO(mvm, "expired: %pM: rtt_avg=%lld\n",
1099			       resp->addr, resp->rtt_avg);
1100		goto update_time;
1101	}
1102
1103	/* Smooth the results based on the tracked RTT average */
1104	undershoot = IWL_MVM_FTM_INITIATOR_SMOOTH_UNDERSHOOT;
1105	overshoot = IWL_MVM_FTM_INITIATOR_SMOOTH_OVERSHOOT;
1106	alpha = IWL_MVM_FTM_INITIATOR_SMOOTH_ALPHA;
1107
1108	rtt_avg = div_s64(alpha * rtt + (100 - alpha) * resp->rtt_avg, 100);
1109
1110	IWL_DEBUG_INFO(mvm,
1111		       "%pM: prev rtt_avg=%lld, new rtt_avg=%lld, rtt=%lld\n",
1112		       resp->addr, resp->rtt_avg, rtt_avg, rtt);
1113
1114	/*
1115	 * update the responder's average RTT results regardless of
1116	 * the under/over shoot logic below
1117	 */
1118	resp->rtt_avg = rtt_avg;
1119
1120	/* smooth the results */
1121	if (rtt_avg > rtt && (rtt_avg - rtt) > undershoot) {
1122		res->ftm.rtt_avg = rtt_avg;
1123
1124		IWL_DEBUG_INFO(mvm,
1125			       "undershoot: val=%lld\n",
1126			       (rtt_avg - rtt));
1127	} else if (rtt_avg < rtt && (rtt - rtt_avg) >
1128		   overshoot) {
1129		res->ftm.rtt_avg = rtt_avg;
1130		IWL_DEBUG_INFO(mvm,
1131			       "overshoot: val=%lld\n",
1132			       (rtt - rtt_avg));
1133	}
1134
1135update_time:
1136	resp->host_time = res->host_time;
1137}
1138
1139static void iwl_mvm_debug_range_resp(struct iwl_mvm *mvm, u8 index,
1140				     struct cfg80211_pmsr_result *res)
1141{
1142	s64 rtt_avg = div_s64(res->ftm.rtt_avg * 100, 6666);
1143
1144	IWL_DEBUG_INFO(mvm, "entry %d\n", index);
1145	IWL_DEBUG_INFO(mvm, "\tstatus: %d\n", res->status);
1146	IWL_DEBUG_INFO(mvm, "\tBSSID: %pM\n", res->addr);
1147	IWL_DEBUG_INFO(mvm, "\thost time: %llu\n", res->host_time);
1148	IWL_DEBUG_INFO(mvm, "\tburst index: %d\n", res->ftm.burst_index);
1149	IWL_DEBUG_INFO(mvm, "\tsuccess num: %u\n", res->ftm.num_ftmr_successes);
1150	IWL_DEBUG_INFO(mvm, "\trssi: %d\n", res->ftm.rssi_avg);
1151	IWL_DEBUG_INFO(mvm, "\trssi spread: %d\n", res->ftm.rssi_spread);
1152	IWL_DEBUG_INFO(mvm, "\trtt: %lld\n", res->ftm.rtt_avg);
1153	IWL_DEBUG_INFO(mvm, "\trtt var: %llu\n", res->ftm.rtt_variance);
1154	IWL_DEBUG_INFO(mvm, "\trtt spread: %llu\n", res->ftm.rtt_spread);
1155	IWL_DEBUG_INFO(mvm, "\tdistance: %lld\n", rtt_avg);
1156}
1157
1158static void
1159iwl_mvm_ftm_pasn_update_pn(struct iwl_mvm *mvm,
1160			   struct iwl_tof_range_rsp_ap_entry_ntfy_v6 *fw_ap)
1161{
1162	struct iwl_mvm_ftm_pasn_entry *entry;
1163
1164	lockdep_assert_held(&mvm->mutex);
1165
1166	list_for_each_entry(entry, &mvm->ftm_initiator.pasn_list, list) {
1167		if (memcmp(fw_ap->bssid, entry->addr, sizeof(entry->addr)))
1168			continue;
1169
1170		memcpy(entry->rx_pn, fw_ap->rx_pn, sizeof(entry->rx_pn));
1171		memcpy(entry->tx_pn, fw_ap->tx_pn, sizeof(entry->tx_pn));
1172		return;
1173	}
1174}
1175
1176static u8 iwl_mvm_ftm_get_range_resp_ver(struct iwl_mvm *mvm)
1177{
1178	if (!fw_has_api(&mvm->fw->ucode_capa,
1179			IWL_UCODE_TLV_API_FTM_NEW_RANGE_REQ))
1180		return 5;
1181
1182	/* Starting from version 8, the FW advertises the version */
1183	if (mvm->cmd_ver.range_resp >= 8)
1184		return mvm->cmd_ver.range_resp;
1185	else if (fw_has_api(&mvm->fw->ucode_capa,
1186			    IWL_UCODE_TLV_API_FTM_RTT_ACCURACY))
1187		return 7;
1188
1189	/* The first version of the new range request API */
1190	return 6;
1191}
1192
1193static bool iwl_mvm_ftm_resp_size_validation(u8 ver, unsigned int pkt_len)
1194{
1195	switch (ver) {
1196	case 9:
1197	case 8:
1198		return pkt_len == sizeof(struct iwl_tof_range_rsp_ntfy_v8);
1199	case 7:
1200		return pkt_len == sizeof(struct iwl_tof_range_rsp_ntfy_v7);
1201	case 6:
1202		return pkt_len == sizeof(struct iwl_tof_range_rsp_ntfy_v6);
1203	case 5:
1204		return pkt_len == sizeof(struct iwl_tof_range_rsp_ntfy_v5);
1205	default:
1206		WARN_ONCE(1, "FTM: unsupported range response version %u", ver);
1207		return false;
1208	}
1209}
1210
1211void iwl_mvm_ftm_range_resp(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
1212{
1213	struct iwl_rx_packet *pkt = rxb_addr(rxb);
1214	unsigned int pkt_len = iwl_rx_packet_payload_len(pkt);
1215	struct iwl_tof_range_rsp_ntfy_v5 *fw_resp_v5 = (void *)pkt->data;
1216	struct iwl_tof_range_rsp_ntfy_v6 *fw_resp_v6 = (void *)pkt->data;
1217	struct iwl_tof_range_rsp_ntfy_v7 *fw_resp_v7 = (void *)pkt->data;
1218	struct iwl_tof_range_rsp_ntfy_v8 *fw_resp_v8 = (void *)pkt->data;
1219	int i;
1220	bool new_api = fw_has_api(&mvm->fw->ucode_capa,
1221				  IWL_UCODE_TLV_API_FTM_NEW_RANGE_REQ);
1222	u8 num_of_aps, last_in_batch;
1223	u8 notif_ver = iwl_mvm_ftm_get_range_resp_ver(mvm);
1224
1225	lockdep_assert_held(&mvm->mutex);
1226
1227	if (!mvm->ftm_initiator.req) {
1228		return;
1229	}
1230
1231	if (unlikely(!iwl_mvm_ftm_resp_size_validation(notif_ver, pkt_len)))
1232		return;
1233
1234	if (new_api) {
1235		if (iwl_mvm_ftm_range_resp_valid(mvm, fw_resp_v8->request_id,
1236						 fw_resp_v8->num_of_aps))
1237			return;
1238
1239		num_of_aps = fw_resp_v8->num_of_aps;
1240		last_in_batch = fw_resp_v8->last_report;
1241	} else {
1242		if (iwl_mvm_ftm_range_resp_valid(mvm, fw_resp_v5->request_id,
1243						 fw_resp_v5->num_of_aps))
1244			return;
1245
1246		num_of_aps = fw_resp_v5->num_of_aps;
1247		last_in_batch = fw_resp_v5->last_in_batch;
1248	}
1249
1250	IWL_DEBUG_INFO(mvm, "Range response received\n");
1251	IWL_DEBUG_INFO(mvm, "request id: %lld, num of entries: %u\n",
1252		       mvm->ftm_initiator.req->cookie, num_of_aps);
1253
1254	for (i = 0; i < num_of_aps && i < IWL_MVM_TOF_MAX_APS; i++) {
1255		struct cfg80211_pmsr_result result = {};
1256		struct iwl_tof_range_rsp_ap_entry_ntfy_v6 *fw_ap;
1257		int peer_idx;
1258
1259		if (new_api) {
1260			if (notif_ver >= 8) {
1261				fw_ap = &fw_resp_v8->ap[i];
1262				iwl_mvm_ftm_pasn_update_pn(mvm, fw_ap);
1263			} else if (notif_ver == 7) {
1264				fw_ap = (void *)&fw_resp_v7->ap[i];
1265			} else {
1266				fw_ap = (void *)&fw_resp_v6->ap[i];
1267			}
1268
1269			result.final = fw_ap->last_burst;
1270			result.ap_tsf = le32_to_cpu(fw_ap->start_tsf);
1271			result.ap_tsf_valid = 1;
1272		} else {
1273			/* the first part is the same for old and new APIs */
1274			fw_ap = (void *)&fw_resp_v5->ap[i];
1275			/*
1276			 * FIXME: the firmware needs to report this, we don't
1277			 * even know the number of bursts the responder picked
1278			 * (if we asked it to)
1279			 */
1280			result.final = 0;
1281		}
1282
1283		peer_idx = iwl_mvm_ftm_find_peer(mvm->ftm_initiator.req,
1284						 fw_ap->bssid);
1285		if (peer_idx < 0) {
1286			IWL_WARN(mvm,
1287				 "Unknown address (%pM, target #%d) in FTM response\n",
1288				 fw_ap->bssid, i);
1289			continue;
1290		}
1291
1292		switch (fw_ap->measure_status) {
1293		case IWL_TOF_ENTRY_SUCCESS:
1294			result.status = NL80211_PMSR_STATUS_SUCCESS;
1295			break;
1296		case IWL_TOF_ENTRY_TIMING_MEASURE_TIMEOUT:
1297			result.status = NL80211_PMSR_STATUS_TIMEOUT;
1298			break;
1299		case IWL_TOF_ENTRY_NO_RESPONSE:
1300			result.status = NL80211_PMSR_STATUS_FAILURE;
1301			result.ftm.failure_reason =
1302				NL80211_PMSR_FTM_FAILURE_NO_RESPONSE;
1303			break;
1304		case IWL_TOF_ENTRY_REQUEST_REJECTED:
1305			result.status = NL80211_PMSR_STATUS_FAILURE;
1306			result.ftm.failure_reason =
1307				NL80211_PMSR_FTM_FAILURE_PEER_BUSY;
1308			result.ftm.busy_retry_time = fw_ap->refusal_period;
1309			break;
1310		default:
1311			result.status = NL80211_PMSR_STATUS_FAILURE;
1312			result.ftm.failure_reason =
1313				NL80211_PMSR_FTM_FAILURE_UNSPECIFIED;
1314			break;
1315		}
1316		memcpy(result.addr, fw_ap->bssid, ETH_ALEN);
1317		result.host_time = iwl_mvm_ftm_get_host_time(mvm,
1318							     fw_ap->timestamp);
1319		result.type = NL80211_PMSR_TYPE_FTM;
1320		result.ftm.burst_index = mvm->ftm_initiator.responses[peer_idx];
1321		mvm->ftm_initiator.responses[peer_idx]++;
1322		result.ftm.rssi_avg = fw_ap->rssi;
1323		result.ftm.rssi_avg_valid = 1;
1324		result.ftm.rssi_spread = fw_ap->rssi_spread;
1325		result.ftm.rssi_spread_valid = 1;
1326		result.ftm.rtt_avg = (s32)le32_to_cpu(fw_ap->rtt);
1327		result.ftm.rtt_avg_valid = 1;
1328		result.ftm.rtt_variance = le32_to_cpu(fw_ap->rtt_variance);
1329		result.ftm.rtt_variance_valid = 1;
1330		result.ftm.rtt_spread = le32_to_cpu(fw_ap->rtt_spread);
1331		result.ftm.rtt_spread_valid = 1;
1332
1333		iwl_mvm_ftm_get_lci_civic(mvm, &result);
1334
1335		iwl_mvm_ftm_rtt_smoothing(mvm, &result);
1336
1337		cfg80211_pmsr_report(mvm->ftm_initiator.req_wdev,
1338				     mvm->ftm_initiator.req,
1339				     &result, GFP_KERNEL);
1340
1341		if (fw_has_api(&mvm->fw->ucode_capa,
1342			       IWL_UCODE_TLV_API_FTM_RTT_ACCURACY))
1343			IWL_DEBUG_INFO(mvm, "RTT confidence: %u\n",
1344				       fw_ap->rttConfidence);
1345
1346		iwl_mvm_debug_range_resp(mvm, i, &result);
1347	}
1348
1349	if (last_in_batch) {
1350		cfg80211_pmsr_complete(mvm->ftm_initiator.req_wdev,
1351				       mvm->ftm_initiator.req,
1352				       GFP_KERNEL);
1353		iwl_mvm_ftm_reset(mvm);
1354	}
1355}
1356
1357void iwl_mvm_ftm_lc_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
1358{
1359	struct iwl_rx_packet *pkt = rxb_addr(rxb);
1360	const struct ieee80211_mgmt *mgmt = (void *)pkt->data;
1361	size_t len = iwl_rx_packet_payload_len(pkt);
1362	struct iwl_mvm_loc_entry *entry;
1363	const u8 *ies, *lci, *civic, *msr_ie;
1364	size_t ies_len, lci_len = 0, civic_len = 0;
1365	size_t baselen = IEEE80211_MIN_ACTION_SIZE +
1366			 sizeof(mgmt->u.action.u.ftm);
1367	static const u8 rprt_type_lci = IEEE80211_SPCT_MSR_RPRT_TYPE_LCI;
1368	static const u8 rprt_type_civic = IEEE80211_SPCT_MSR_RPRT_TYPE_CIVIC;
1369
1370	if (len <= baselen)
1371		return;
1372
1373	lockdep_assert_held(&mvm->mutex);
1374
1375	ies = mgmt->u.action.u.ftm.variable;
1376	ies_len = len - baselen;
1377
1378	msr_ie = cfg80211_find_ie_match(WLAN_EID_MEASURE_REPORT, ies, ies_len,
1379					&rprt_type_lci, 1, 4);
1380	if (msr_ie) {
1381		lci = msr_ie + 2;
1382		lci_len = msr_ie[1];
1383	}
1384
1385	msr_ie = cfg80211_find_ie_match(WLAN_EID_MEASURE_REPORT, ies, ies_len,
1386					&rprt_type_civic, 1, 4);
1387	if (msr_ie) {
1388		civic = msr_ie + 2;
1389		civic_len = msr_ie[1];
1390	}
1391
1392	entry = kmalloc(sizeof(*entry) + lci_len + civic_len, GFP_KERNEL);
1393	if (!entry)
1394		return;
1395
1396	memcpy(entry->addr, mgmt->bssid, ETH_ALEN);
1397
1398	entry->lci_len = lci_len;
1399	if (lci_len)
1400		memcpy(entry->buf, lci, lci_len);
1401
1402	entry->civic_len = civic_len;
1403	if (civic_len)
1404		memcpy(entry->buf + lci_len, civic, civic_len);
1405
1406	list_add_tail(&entry->list, &mvm->ftm_initiator.loc_list);
1407}
1408