1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
3 * Copyright (C) 2015-2017 Intel Deutschland GmbH
4 * Copyright (C) 2018-2020 Intel Corporation
6 #include <linux/etherdevice.h>
7 #include <linux/math64.h>
8 #include <net/cfg80211.h>
12 #include "constants.h"
14 struct iwl_mvm_loc_entry
{
15 struct list_head list
;
17 u8 lci_len
, civic_len
;
21 struct iwl_mvm_smooth_entry
{
22 struct list_head list
;
28 struct iwl_mvm_ftm_pasn_entry
{
29 struct list_head list
;
31 u8 hltk
[HLTK_11AZ_LEN
];
34 u8 tx_pn
[IEEE80211_CCMP_PN_LEN
];
35 u8 rx_pn
[IEEE80211_CCMP_PN_LEN
];
38 int iwl_mvm_ftm_add_pasn_sta(struct iwl_mvm
*mvm
, struct ieee80211_vif
*vif
,
39 u8
*addr
, u32 cipher
, u8
*tk
, u32 tk_len
,
40 u8
*hltk
, u32 hltk_len
)
42 struct iwl_mvm_ftm_pasn_entry
*pasn
= kzalloc(sizeof(*pasn
),
46 lockdep_assert_held(&mvm
->mutex
);
51 pasn
->cipher
= iwl_mvm_cipher_to_location_cipher(cipher
);
53 switch (pasn
->cipher
) {
54 case IWL_LOCATION_CIPHER_CCMP_128
:
55 case IWL_LOCATION_CIPHER_GCMP_128
:
56 expected_tk_len
= WLAN_KEY_LEN_CCMP
;
58 case IWL_LOCATION_CIPHER_GCMP_256
:
59 expected_tk_len
= WLAN_KEY_LEN_GCMP_256
;
66 * If associated to this AP and already have security context,
67 * the TK is already configured for this station, so it
68 * shouldn't be set again here.
70 if (vif
->bss_conf
.assoc
&&
71 !memcmp(addr
, vif
->bss_conf
.bssid
, ETH_ALEN
)) {
72 struct iwl_mvm_vif
*mvmvif
= iwl_mvm_vif_from_mac80211(vif
);
73 struct ieee80211_sta
*sta
;
76 sta
= rcu_dereference(mvm
->fw_id_to_mac_id
[mvmvif
->ap_sta_id
]);
77 if (!IS_ERR_OR_NULL(sta
) && sta
->mfp
)
82 if (tk_len
!= expected_tk_len
|| hltk_len
!= sizeof(pasn
->hltk
)) {
83 IWL_ERR(mvm
, "Invalid key length: tk_len=%u hltk_len=%u\n",
88 memcpy(pasn
->addr
, addr
, sizeof(pasn
->addr
));
89 memcpy(pasn
->hltk
, hltk
, sizeof(pasn
->hltk
));
92 memcpy(pasn
->tk
, tk
, sizeof(pasn
->tk
));
94 list_add_tail(&pasn
->list
, &mvm
->ftm_initiator
.pasn_list
);
101 void iwl_mvm_ftm_remove_pasn_sta(struct iwl_mvm
*mvm
, u8
*addr
)
103 struct iwl_mvm_ftm_pasn_entry
*entry
, *prev
;
105 lockdep_assert_held(&mvm
->mutex
);
107 list_for_each_entry_safe(entry
, prev
, &mvm
->ftm_initiator
.pasn_list
,
109 if (memcmp(entry
->addr
, addr
, sizeof(entry
->addr
)))
112 list_del(&entry
->list
);
118 static void iwl_mvm_ftm_reset(struct iwl_mvm
*mvm
)
120 struct iwl_mvm_loc_entry
*e
, *t
;
122 mvm
->ftm_initiator
.req
= NULL
;
123 mvm
->ftm_initiator
.req_wdev
= NULL
;
124 memset(mvm
->ftm_initiator
.responses
, 0,
125 sizeof(mvm
->ftm_initiator
.responses
));
127 list_for_each_entry_safe(e
, t
, &mvm
->ftm_initiator
.loc_list
, list
) {
133 void iwl_mvm_ftm_restart(struct iwl_mvm
*mvm
)
135 struct cfg80211_pmsr_result result
= {
136 .status
= NL80211_PMSR_STATUS_FAILURE
,
138 .host_time
= ktime_get_boottime_ns(),
139 .type
= NL80211_PMSR_TYPE_FTM
,
143 lockdep_assert_held(&mvm
->mutex
);
145 if (!mvm
->ftm_initiator
.req
)
148 for (i
= 0; i
< mvm
->ftm_initiator
.req
->n_peers
; i
++) {
149 memcpy(result
.addr
, mvm
->ftm_initiator
.req
->peers
[i
].addr
,
151 result
.ftm
.burst_index
= mvm
->ftm_initiator
.responses
[i
];
153 cfg80211_pmsr_report(mvm
->ftm_initiator
.req_wdev
,
154 mvm
->ftm_initiator
.req
,
155 &result
, GFP_KERNEL
);
158 cfg80211_pmsr_complete(mvm
->ftm_initiator
.req_wdev
,
159 mvm
->ftm_initiator
.req
, GFP_KERNEL
);
160 iwl_mvm_ftm_reset(mvm
);
163 void iwl_mvm_ftm_initiator_smooth_config(struct iwl_mvm
*mvm
)
165 INIT_LIST_HEAD(&mvm
->ftm_initiator
.smooth
.resp
);
168 "enable=%u, alpha=%u, age_jiffies=%u, thresh=(%u:%u)\n",
169 IWL_MVM_FTM_INITIATOR_ENABLE_SMOOTH
,
170 IWL_MVM_FTM_INITIATOR_SMOOTH_ALPHA
,
171 IWL_MVM_FTM_INITIATOR_SMOOTH_AGE_SEC
* HZ
,
172 IWL_MVM_FTM_INITIATOR_SMOOTH_OVERSHOOT
,
173 IWL_MVM_FTM_INITIATOR_SMOOTH_UNDERSHOOT
);
176 void iwl_mvm_ftm_initiator_smooth_stop(struct iwl_mvm
*mvm
)
178 struct iwl_mvm_smooth_entry
*se
, *st
;
180 list_for_each_entry_safe(se
, st
, &mvm
->ftm_initiator
.smooth
.resp
,
188 iwl_ftm_range_request_status_to_err(enum iwl_tof_range_request_status s
)
191 case IWL_TOF_RANGE_REQUEST_STATUS_SUCCESS
:
193 case IWL_TOF_RANGE_REQUEST_STATUS_BUSY
:
201 static void iwl_mvm_ftm_cmd_v5(struct iwl_mvm
*mvm
, struct ieee80211_vif
*vif
,
202 struct iwl_tof_range_req_cmd_v5
*cmd
,
203 struct cfg80211_pmsr_request
*req
)
207 cmd
->request_id
= req
->cookie
;
208 cmd
->num_of_ap
= req
->n_peers
;
210 /* use maximum for "no timeout" or bigger than what we can do */
211 if (!req
->timeout
|| req
->timeout
> 255 * 100)
212 cmd
->req_timeout
= 255;
214 cmd
->req_timeout
= DIV_ROUND_UP(req
->timeout
, 100);
217 * We treat it always as random, since if not we'll
218 * have filled our local address there instead.
220 cmd
->macaddr_random
= 1;
221 memcpy(cmd
->macaddr_template
, req
->mac_addr
, ETH_ALEN
);
222 for (i
= 0; i
< ETH_ALEN
; i
++)
223 cmd
->macaddr_mask
[i
] = ~req
->mac_addr_mask
[i
];
225 if (vif
->bss_conf
.assoc
)
226 memcpy(cmd
->range_req_bssid
, vif
->bss_conf
.bssid
, ETH_ALEN
);
228 eth_broadcast_addr(cmd
->range_req_bssid
);
231 static void iwl_mvm_ftm_cmd_common(struct iwl_mvm
*mvm
,
232 struct ieee80211_vif
*vif
,
233 struct iwl_tof_range_req_cmd_v9
*cmd
,
234 struct cfg80211_pmsr_request
*req
)
238 cmd
->initiator_flags
=
239 cpu_to_le32(IWL_TOF_INITIATOR_FLAGS_MACADDR_RANDOM
|
240 IWL_TOF_INITIATOR_FLAGS_NON_ASAP_SUPPORT
);
241 cmd
->request_id
= req
->cookie
;
242 cmd
->num_of_ap
= req
->n_peers
;
245 * Use a large value for "no timeout". Don't use the maximum value
246 * because of fw limitations.
249 cmd
->req_timeout_ms
= cpu_to_le32(req
->timeout
);
251 cmd
->req_timeout_ms
= cpu_to_le32(0xfffff);
253 memcpy(cmd
->macaddr_template
, req
->mac_addr
, ETH_ALEN
);
254 for (i
= 0; i
< ETH_ALEN
; i
++)
255 cmd
->macaddr_mask
[i
] = ~req
->mac_addr_mask
[i
];
257 if (vif
->bss_conf
.assoc
) {
258 memcpy(cmd
->range_req_bssid
, vif
->bss_conf
.bssid
, ETH_ALEN
);
260 /* AP's TSF is only relevant if associated */
261 for (i
= 0; i
< req
->n_peers
; i
++) {
262 if (req
->peers
[i
].report_ap_tsf
) {
263 struct iwl_mvm_vif
*mvmvif
=
264 iwl_mvm_vif_from_mac80211(vif
);
266 cmd
->tsf_mac_id
= cpu_to_le32(mvmvif
->id
);
271 eth_broadcast_addr(cmd
->range_req_bssid
);
274 /* Don't report AP's TSF */
275 cmd
->tsf_mac_id
= cpu_to_le32(0xff);
278 static void iwl_mvm_ftm_cmd_v8(struct iwl_mvm
*mvm
, struct ieee80211_vif
*vif
,
279 struct iwl_tof_range_req_cmd_v8
*cmd
,
280 struct cfg80211_pmsr_request
*req
)
282 iwl_mvm_ftm_cmd_common(mvm
, vif
, (void *)cmd
, req
);
286 iwl_mvm_ftm_target_chandef_v1(struct iwl_mvm
*mvm
,
287 struct cfg80211_pmsr_request_peer
*peer
,
288 u8
*channel
, u8
*bandwidth
,
289 u8
*ctrl_ch_position
)
291 u32 freq
= peer
->chandef
.chan
->center_freq
;
293 *channel
= ieee80211_frequency_to_channel(freq
);
295 switch (peer
->chandef
.width
) {
296 case NL80211_CHAN_WIDTH_20_NOHT
:
297 *bandwidth
= IWL_TOF_BW_20_LEGACY
;
299 case NL80211_CHAN_WIDTH_20
:
300 *bandwidth
= IWL_TOF_BW_20_HT
;
302 case NL80211_CHAN_WIDTH_40
:
303 *bandwidth
= IWL_TOF_BW_40
;
305 case NL80211_CHAN_WIDTH_80
:
306 *bandwidth
= IWL_TOF_BW_80
;
309 IWL_ERR(mvm
, "Unsupported BW in FTM request (%d)\n",
310 peer
->chandef
.width
);
314 *ctrl_ch_position
= (peer
->chandef
.width
> NL80211_CHAN_WIDTH_20
) ?
315 iwl_mvm_get_ctrl_pos(&peer
->chandef
) : 0;
321 iwl_mvm_ftm_target_chandef_v2(struct iwl_mvm
*mvm
,
322 struct cfg80211_pmsr_request_peer
*peer
,
323 u8
*channel
, u8
*format_bw
,
324 u8
*ctrl_ch_position
)
326 u32 freq
= peer
->chandef
.chan
->center_freq
;
328 *channel
= ieee80211_frequency_to_channel(freq
);
330 switch (peer
->chandef
.width
) {
331 case NL80211_CHAN_WIDTH_20_NOHT
:
332 *format_bw
= IWL_LOCATION_FRAME_FORMAT_LEGACY
;
333 *format_bw
|= IWL_LOCATION_BW_20MHZ
<< LOCATION_BW_POS
;
335 case NL80211_CHAN_WIDTH_20
:
336 *format_bw
= IWL_LOCATION_FRAME_FORMAT_HT
;
337 *format_bw
|= IWL_LOCATION_BW_20MHZ
<< LOCATION_BW_POS
;
339 case NL80211_CHAN_WIDTH_40
:
340 *format_bw
= IWL_LOCATION_FRAME_FORMAT_HT
;
341 *format_bw
|= IWL_LOCATION_BW_40MHZ
<< LOCATION_BW_POS
;
343 case NL80211_CHAN_WIDTH_80
:
344 *format_bw
= IWL_LOCATION_FRAME_FORMAT_VHT
;
345 *format_bw
|= IWL_LOCATION_BW_80MHZ
<< LOCATION_BW_POS
;
348 IWL_ERR(mvm
, "Unsupported BW in FTM request (%d)\n",
349 peer
->chandef
.width
);
353 /* non EDCA based measurement must use HE preamble */
354 if (peer
->ftm
.trigger_based
|| peer
->ftm
.non_trigger_based
)
355 *format_bw
|= IWL_LOCATION_FRAME_FORMAT_HE
;
357 *ctrl_ch_position
= (peer
->chandef
.width
> NL80211_CHAN_WIDTH_20
) ?
358 iwl_mvm_get_ctrl_pos(&peer
->chandef
) : 0;
364 iwl_mvm_ftm_put_target_v2(struct iwl_mvm
*mvm
,
365 struct cfg80211_pmsr_request_peer
*peer
,
366 struct iwl_tof_range_req_ap_entry_v2
*target
)
370 ret
= iwl_mvm_ftm_target_chandef_v1(mvm
, peer
, &target
->channel_num
,
372 &target
->ctrl_ch_position
);
376 memcpy(target
->bssid
, peer
->addr
, ETH_ALEN
);
377 target
->burst_period
=
378 cpu_to_le16(peer
->ftm
.burst_period
);
379 target
->samples_per_burst
= peer
->ftm
.ftms_per_burst
;
380 target
->num_of_bursts
= peer
->ftm
.num_bursts_exp
;
381 target
->measure_type
= 0; /* regular two-sided FTM */
382 target
->retries_per_sample
= peer
->ftm
.ftmr_retries
;
383 target
->asap_mode
= peer
->ftm
.asap
;
384 target
->enable_dyn_ack
= IWL_MVM_FTM_INITIATOR_DYNACK
;
386 if (peer
->ftm
.request_lci
)
387 target
->location_req
|= IWL_TOF_LOC_LCI
;
388 if (peer
->ftm
.request_civicloc
)
389 target
->location_req
|= IWL_TOF_LOC_CIVIC
;
391 target
->algo_type
= IWL_MVM_FTM_INITIATOR_ALGO
;
396 #define FTM_PUT_FLAG(flag) (target->initiator_ap_flags |= \
397 cpu_to_le32(IWL_INITIATOR_AP_FLAGS_##flag))
400 iwl_mvm_ftm_put_target_common(struct iwl_mvm
*mvm
,
401 struct cfg80211_pmsr_request_peer
*peer
,
402 struct iwl_tof_range_req_ap_entry_v6
*target
)
404 memcpy(target
->bssid
, peer
->addr
, ETH_ALEN
);
405 target
->burst_period
=
406 cpu_to_le16(peer
->ftm
.burst_period
);
407 target
->samples_per_burst
= peer
->ftm
.ftms_per_burst
;
408 target
->num_of_bursts
= peer
->ftm
.num_bursts_exp
;
409 target
->ftmr_max_retries
= peer
->ftm
.ftmr_retries
;
410 target
->initiator_ap_flags
= cpu_to_le32(0);
415 if (peer
->ftm
.request_lci
)
416 FTM_PUT_FLAG(LCI_REQUEST
);
418 if (peer
->ftm
.request_civicloc
)
419 FTM_PUT_FLAG(CIVIC_REQUEST
);
421 if (IWL_MVM_FTM_INITIATOR_DYNACK
)
422 FTM_PUT_FLAG(DYN_ACK
);
424 if (IWL_MVM_FTM_INITIATOR_ALGO
== IWL_TOF_ALGO_TYPE_LINEAR_REG
)
425 FTM_PUT_FLAG(ALGO_LR
);
426 else if (IWL_MVM_FTM_INITIATOR_ALGO
== IWL_TOF_ALGO_TYPE_FFT
)
427 FTM_PUT_FLAG(ALGO_FFT
);
429 if (peer
->ftm
.trigger_based
)
431 else if (peer
->ftm
.non_trigger_based
)
432 FTM_PUT_FLAG(NON_TB
);
436 iwl_mvm_ftm_put_target_v3(struct iwl_mvm
*mvm
,
437 struct cfg80211_pmsr_request_peer
*peer
,
438 struct iwl_tof_range_req_ap_entry_v3
*target
)
442 ret
= iwl_mvm_ftm_target_chandef_v1(mvm
, peer
, &target
->channel_num
,
444 &target
->ctrl_ch_position
);
449 * Versions 3 and 4 has some common fields, so
450 * iwl_mvm_ftm_put_target_common() can be used for version 7 too.
452 iwl_mvm_ftm_put_target_common(mvm
, peer
, (void *)target
);
458 iwl_mvm_ftm_put_target_v4(struct iwl_mvm
*mvm
,
459 struct cfg80211_pmsr_request_peer
*peer
,
460 struct iwl_tof_range_req_ap_entry_v4
*target
)
464 ret
= iwl_mvm_ftm_target_chandef_v2(mvm
, peer
, &target
->channel_num
,
466 &target
->ctrl_ch_position
);
470 iwl_mvm_ftm_put_target_common(mvm
, peer
, (void *)target
);
476 iwl_mvm_ftm_put_target(struct iwl_mvm
*mvm
, struct ieee80211_vif
*vif
,
477 struct cfg80211_pmsr_request_peer
*peer
,
478 struct iwl_tof_range_req_ap_entry_v6
*target
)
482 ret
= iwl_mvm_ftm_target_chandef_v2(mvm
, peer
, &target
->channel_num
,
484 &target
->ctrl_ch_position
);
488 iwl_mvm_ftm_put_target_common(mvm
, peer
, target
);
490 if (vif
->bss_conf
.assoc
&&
491 !memcmp(peer
->addr
, vif
->bss_conf
.bssid
, ETH_ALEN
)) {
492 struct iwl_mvm_vif
*mvmvif
= iwl_mvm_vif_from_mac80211(vif
);
494 target
->sta_id
= mvmvif
->ap_sta_id
;
496 target
->sta_id
= IWL_MVM_INVALID_STA
;
500 * TODO: Beacon interval is currently unknown, so use the common value
503 target
->beacon_interval
= cpu_to_le16(100);
507 static int iwl_mvm_ftm_send_cmd(struct iwl_mvm
*mvm
, struct iwl_host_cmd
*hcmd
)
510 int err
= iwl_mvm_send_cmd_status(mvm
, hcmd
, &status
);
512 if (!err
&& status
) {
513 IWL_ERR(mvm
, "FTM range request command failure, status: %u\n",
515 err
= iwl_ftm_range_request_status_to_err(status
);
521 static int iwl_mvm_ftm_start_v5(struct iwl_mvm
*mvm
, struct ieee80211_vif
*vif
,
522 struct cfg80211_pmsr_request
*req
)
524 struct iwl_tof_range_req_cmd_v5 cmd_v5
;
525 struct iwl_host_cmd hcmd
= {
526 .id
= iwl_cmd_id(TOF_RANGE_REQ_CMD
, LOCATION_GROUP
, 0),
527 .dataflags
[0] = IWL_HCMD_DFL_DUP
,
529 .len
[0] = sizeof(cmd_v5
),
534 iwl_mvm_ftm_cmd_v5(mvm
, vif
, &cmd_v5
, req
);
536 for (i
= 0; i
< cmd_v5
.num_of_ap
; i
++) {
537 struct cfg80211_pmsr_request_peer
*peer
= &req
->peers
[i
];
539 err
= iwl_mvm_ftm_put_target_v2(mvm
, peer
, &cmd_v5
.ap
[i
]);
544 return iwl_mvm_ftm_send_cmd(mvm
, &hcmd
);
547 static int iwl_mvm_ftm_start_v7(struct iwl_mvm
*mvm
, struct ieee80211_vif
*vif
,
548 struct cfg80211_pmsr_request
*req
)
550 struct iwl_tof_range_req_cmd_v7 cmd_v7
;
551 struct iwl_host_cmd hcmd
= {
552 .id
= iwl_cmd_id(TOF_RANGE_REQ_CMD
, LOCATION_GROUP
, 0),
553 .dataflags
[0] = IWL_HCMD_DFL_DUP
,
555 .len
[0] = sizeof(cmd_v7
),
561 * Versions 7 and 8 has the same structure except from the responders
562 * list, so iwl_mvm_ftm_cmd() can be used for version 7 too.
564 iwl_mvm_ftm_cmd_v8(mvm
, vif
, (void *)&cmd_v7
, req
);
566 for (i
= 0; i
< cmd_v7
.num_of_ap
; i
++) {
567 struct cfg80211_pmsr_request_peer
*peer
= &req
->peers
[i
];
569 err
= iwl_mvm_ftm_put_target_v3(mvm
, peer
, &cmd_v7
.ap
[i
]);
574 return iwl_mvm_ftm_send_cmd(mvm
, &hcmd
);
577 static int iwl_mvm_ftm_start_v8(struct iwl_mvm
*mvm
, struct ieee80211_vif
*vif
,
578 struct cfg80211_pmsr_request
*req
)
580 struct iwl_tof_range_req_cmd_v8 cmd
;
581 struct iwl_host_cmd hcmd
= {
582 .id
= iwl_cmd_id(TOF_RANGE_REQ_CMD
, LOCATION_GROUP
, 0),
583 .dataflags
[0] = IWL_HCMD_DFL_DUP
,
585 .len
[0] = sizeof(cmd
),
590 iwl_mvm_ftm_cmd_v8(mvm
, vif
, (void *)&cmd
, req
);
592 for (i
= 0; i
< cmd
.num_of_ap
; i
++) {
593 struct cfg80211_pmsr_request_peer
*peer
= &req
->peers
[i
];
595 err
= iwl_mvm_ftm_put_target_v4(mvm
, peer
, &cmd
.ap
[i
]);
600 return iwl_mvm_ftm_send_cmd(mvm
, &hcmd
);
603 static int iwl_mvm_ftm_start_v9(struct iwl_mvm
*mvm
, struct ieee80211_vif
*vif
,
604 struct cfg80211_pmsr_request
*req
)
606 struct iwl_tof_range_req_cmd_v9 cmd
;
607 struct iwl_host_cmd hcmd
= {
608 .id
= iwl_cmd_id(TOF_RANGE_REQ_CMD
, LOCATION_GROUP
, 0),
609 .dataflags
[0] = IWL_HCMD_DFL_DUP
,
611 .len
[0] = sizeof(cmd
),
616 iwl_mvm_ftm_cmd_common(mvm
, vif
, &cmd
, req
);
618 for (i
= 0; i
< cmd
.num_of_ap
; i
++) {
619 struct cfg80211_pmsr_request_peer
*peer
= &req
->peers
[i
];
620 struct iwl_tof_range_req_ap_entry_v6
*target
= &cmd
.ap
[i
];
622 err
= iwl_mvm_ftm_put_target(mvm
, vif
, peer
, target
);
627 return iwl_mvm_ftm_send_cmd(mvm
, &hcmd
);
630 static void iter(struct ieee80211_hw
*hw
,
631 struct ieee80211_vif
*vif
,
632 struct ieee80211_sta
*sta
,
633 struct ieee80211_key_conf
*key
,
636 struct iwl_tof_range_req_ap_entry_v6
*target
= data
;
638 if (!sta
|| memcmp(sta
->addr
, target
->bssid
, ETH_ALEN
))
643 if (WARN_ON(key
->keylen
> sizeof(target
->tk
)))
646 memcpy(target
->tk
, key
->key
, key
->keylen
);
647 target
->cipher
= iwl_mvm_cipher_to_location_cipher(key
->cipher
);
648 WARN_ON(target
->cipher
== IWL_LOCATION_CIPHER_INVALID
);
652 iwl_mvm_ftm_set_secured_ranging(struct iwl_mvm
*mvm
, struct ieee80211_vif
*vif
,
653 struct iwl_tof_range_req_ap_entry_v7
*target
)
655 struct iwl_mvm_ftm_pasn_entry
*entry
;
656 u32 flags
= le32_to_cpu(target
->initiator_ap_flags
);
658 if (!(flags
& (IWL_INITIATOR_AP_FLAGS_NON_TB
|
659 IWL_INITIATOR_AP_FLAGS_TB
)))
662 lockdep_assert_held(&mvm
->mutex
);
664 list_for_each_entry(entry
, &mvm
->ftm_initiator
.pasn_list
, list
) {
665 if (memcmp(entry
->addr
, target
->bssid
, sizeof(entry
->addr
)))
668 target
->cipher
= entry
->cipher
;
669 memcpy(target
->hltk
, entry
->hltk
, sizeof(target
->hltk
));
671 if (vif
->bss_conf
.assoc
&&
672 !memcmp(vif
->bss_conf
.bssid
, target
->bssid
,
673 sizeof(target
->bssid
)))
674 ieee80211_iter_keys(mvm
->hw
, vif
, iter
, target
);
676 memcpy(target
->tk
, entry
->tk
, sizeof(target
->tk
));
678 memcpy(target
->rx_pn
, entry
->rx_pn
, sizeof(target
->rx_pn
));
679 memcpy(target
->tx_pn
, entry
->tx_pn
, sizeof(target
->tx_pn
));
681 target
->initiator_ap_flags
|=
682 cpu_to_le32(IWL_INITIATOR_AP_FLAGS_SECURED
);
687 static int iwl_mvm_ftm_start_v11(struct iwl_mvm
*mvm
,
688 struct ieee80211_vif
*vif
,
689 struct cfg80211_pmsr_request
*req
)
691 struct iwl_tof_range_req_cmd_v11 cmd
;
692 struct iwl_host_cmd hcmd
= {
693 .id
= iwl_cmd_id(TOF_RANGE_REQ_CMD
, LOCATION_GROUP
, 0),
694 .dataflags
[0] = IWL_HCMD_DFL_DUP
,
696 .len
[0] = sizeof(cmd
),
701 iwl_mvm_ftm_cmd_common(mvm
, vif
, (void *)&cmd
, req
);
703 for (i
= 0; i
< cmd
.num_of_ap
; i
++) {
704 struct cfg80211_pmsr_request_peer
*peer
= &req
->peers
[i
];
705 struct iwl_tof_range_req_ap_entry_v7
*target
= &cmd
.ap
[i
];
707 err
= iwl_mvm_ftm_put_target(mvm
, vif
, peer
, (void *)target
);
711 iwl_mvm_ftm_set_secured_ranging(mvm
, vif
, target
);
714 return iwl_mvm_ftm_send_cmd(mvm
, &hcmd
);
717 int iwl_mvm_ftm_start(struct iwl_mvm
*mvm
, struct ieee80211_vif
*vif
,
718 struct cfg80211_pmsr_request
*req
)
720 bool new_api
= fw_has_api(&mvm
->fw
->ucode_capa
,
721 IWL_UCODE_TLV_API_FTM_NEW_RANGE_REQ
);
724 lockdep_assert_held(&mvm
->mutex
);
726 if (mvm
->ftm_initiator
.req
)
730 u8 cmd_ver
= iwl_fw_lookup_cmd_ver(mvm
->fw
, LOCATION_GROUP
,
732 IWL_FW_CMD_VER_UNKNOWN
);
736 err
= iwl_mvm_ftm_start_v11(mvm
, vif
, req
);
740 err
= iwl_mvm_ftm_start_v9(mvm
, vif
, req
);
743 err
= iwl_mvm_ftm_start_v8(mvm
, vif
, req
);
746 err
= iwl_mvm_ftm_start_v7(mvm
, vif
, req
);
750 err
= iwl_mvm_ftm_start_v5(mvm
, vif
, req
);
754 mvm
->ftm_initiator
.req
= req
;
755 mvm
->ftm_initiator
.req_wdev
= ieee80211_vif_to_wdev(vif
);
761 void iwl_mvm_ftm_abort(struct iwl_mvm
*mvm
, struct cfg80211_pmsr_request
*req
)
763 struct iwl_tof_range_abort_cmd cmd
= {
764 .request_id
= req
->cookie
,
767 lockdep_assert_held(&mvm
->mutex
);
769 if (req
!= mvm
->ftm_initiator
.req
)
772 iwl_mvm_ftm_reset(mvm
);
774 if (iwl_mvm_send_cmd_pdu(mvm
, iwl_cmd_id(TOF_RANGE_ABORT_CMD
,
776 0, sizeof(cmd
), &cmd
))
777 IWL_ERR(mvm
, "failed to abort FTM process\n");
780 static int iwl_mvm_ftm_find_peer(struct cfg80211_pmsr_request
*req
,
785 for (i
= 0; i
< req
->n_peers
; i
++) {
786 struct cfg80211_pmsr_request_peer
*peer
= &req
->peers
[i
];
788 if (ether_addr_equal_unaligned(peer
->addr
, addr
))
795 static u64
iwl_mvm_ftm_get_host_time(struct iwl_mvm
*mvm
, __le32 fw_gp2_ts
)
797 u32 gp2_ts
= le32_to_cpu(fw_gp2_ts
);
799 u64 now_from_boot_ns
;
801 iwl_mvm_get_sync_time(mvm
, &curr_gp2
, &now_from_boot_ns
);
803 if (curr_gp2
>= gp2_ts
)
804 diff
= curr_gp2
- gp2_ts
;
806 diff
= curr_gp2
+ (U32_MAX
- gp2_ts
+ 1);
808 return now_from_boot_ns
- (u64
)diff
* 1000;
811 static void iwl_mvm_ftm_get_lci_civic(struct iwl_mvm
*mvm
,
812 struct cfg80211_pmsr_result
*res
)
814 struct iwl_mvm_loc_entry
*entry
;
816 list_for_each_entry(entry
, &mvm
->ftm_initiator
.loc_list
, list
) {
817 if (!ether_addr_equal_unaligned(res
->addr
, entry
->addr
))
820 if (entry
->lci_len
) {
821 res
->ftm
.lci_len
= entry
->lci_len
;
822 res
->ftm
.lci
= entry
->buf
;
825 if (entry
->civic_len
) {
826 res
->ftm
.civicloc_len
= entry
->civic_len
;
827 res
->ftm
.civicloc
= entry
->buf
+ entry
->lci_len
;
830 /* we found the entry we needed */
835 static int iwl_mvm_ftm_range_resp_valid(struct iwl_mvm
*mvm
, u8 request_id
,
838 lockdep_assert_held(&mvm
->mutex
);
840 if (request_id
!= (u8
)mvm
->ftm_initiator
.req
->cookie
) {
841 IWL_ERR(mvm
, "Request ID mismatch, got %u, active %u\n",
842 request_id
, (u8
)mvm
->ftm_initiator
.req
->cookie
);
846 if (num_of_aps
> mvm
->ftm_initiator
.req
->n_peers
) {
847 IWL_ERR(mvm
, "FTM range response invalid\n");
854 static void iwl_mvm_ftm_rtt_smoothing(struct iwl_mvm
*mvm
,
855 struct cfg80211_pmsr_result
*res
)
857 struct iwl_mvm_smooth_entry
*resp
;
858 s64 rtt_avg
, rtt
= res
->ftm
.rtt_avg
;
859 u32 undershoot
, overshoot
;
863 if (!IWL_MVM_FTM_INITIATOR_ENABLE_SMOOTH
)
868 if (res
->status
!= NL80211_PMSR_STATUS_SUCCESS
) {
870 ": %pM: ignore failed measurement. Status=%u\n",
871 res
->addr
, res
->status
);
876 list_for_each_entry(resp
, &mvm
->ftm_initiator
.smooth
.resp
, list
) {
877 if (!memcmp(res
->addr
, resp
->addr
, ETH_ALEN
)) {
884 resp
= kzalloc(sizeof(*resp
), GFP_KERNEL
);
888 memcpy(resp
->addr
, res
->addr
, ETH_ALEN
);
889 list_add_tail(&resp
->list
, &mvm
->ftm_initiator
.smooth
.resp
);
893 IWL_DEBUG_INFO(mvm
, "new: %pM: rtt_avg=%lld\n",
894 resp
->addr
, resp
->rtt_avg
);
898 if (res
->host_time
- resp
->host_time
>
899 IWL_MVM_FTM_INITIATOR_SMOOTH_AGE_SEC
* 1000000000) {
902 IWL_DEBUG_INFO(mvm
, "expired: %pM: rtt_avg=%lld\n",
903 resp
->addr
, resp
->rtt_avg
);
907 /* Smooth the results based on the tracked RTT average */
908 undershoot
= IWL_MVM_FTM_INITIATOR_SMOOTH_UNDERSHOOT
;
909 overshoot
= IWL_MVM_FTM_INITIATOR_SMOOTH_OVERSHOOT
;
910 alpha
= IWL_MVM_FTM_INITIATOR_SMOOTH_ALPHA
;
912 rtt_avg
= (alpha
* rtt
+ (100 - alpha
) * resp
->rtt_avg
) / 100;
915 "%pM: prev rtt_avg=%lld, new rtt_avg=%lld, rtt=%lld\n",
916 resp
->addr
, resp
->rtt_avg
, rtt_avg
, rtt
);
919 * update the responder's average RTT results regardless of
920 * the under/over shoot logic below
922 resp
->rtt_avg
= rtt_avg
;
924 /* smooth the results */
925 if (rtt_avg
> rtt
&& (rtt_avg
- rtt
) > undershoot
) {
926 res
->ftm
.rtt_avg
= rtt_avg
;
929 "undershoot: val=%lld\n",
931 } else if (rtt_avg
< rtt
&& (rtt
- rtt_avg
) >
933 res
->ftm
.rtt_avg
= rtt_avg
;
935 "overshoot: val=%lld\n",
940 resp
->host_time
= res
->host_time
;
943 static void iwl_mvm_debug_range_resp(struct iwl_mvm
*mvm
, u8 index
,
944 struct cfg80211_pmsr_result
*res
)
946 s64 rtt_avg
= div_s64(res
->ftm
.rtt_avg
* 100, 6666);
948 IWL_DEBUG_INFO(mvm
, "entry %d\n", index
);
949 IWL_DEBUG_INFO(mvm
, "\tstatus: %d\n", res
->status
);
950 IWL_DEBUG_INFO(mvm
, "\tBSSID: %pM\n", res
->addr
);
951 IWL_DEBUG_INFO(mvm
, "\thost time: %llu\n", res
->host_time
);
952 IWL_DEBUG_INFO(mvm
, "\tburst index: %hhu\n", res
->ftm
.burst_index
);
953 IWL_DEBUG_INFO(mvm
, "\tsuccess num: %u\n", res
->ftm
.num_ftmr_successes
);
954 IWL_DEBUG_INFO(mvm
, "\trssi: %d\n", res
->ftm
.rssi_avg
);
955 IWL_DEBUG_INFO(mvm
, "\trssi spread: %hhu\n", res
->ftm
.rssi_spread
);
956 IWL_DEBUG_INFO(mvm
, "\trtt: %lld\n", res
->ftm
.rtt_avg
);
957 IWL_DEBUG_INFO(mvm
, "\trtt var: %llu\n", res
->ftm
.rtt_variance
);
958 IWL_DEBUG_INFO(mvm
, "\trtt spread: %llu\n", res
->ftm
.rtt_spread
);
959 IWL_DEBUG_INFO(mvm
, "\tdistance: %lld\n", rtt_avg
);
963 iwl_mvm_ftm_pasn_update_pn(struct iwl_mvm
*mvm
,
964 struct iwl_tof_range_rsp_ap_entry_ntfy_v6
*fw_ap
)
966 struct iwl_mvm_ftm_pasn_entry
*entry
;
968 lockdep_assert_held(&mvm
->mutex
);
970 list_for_each_entry(entry
, &mvm
->ftm_initiator
.pasn_list
, list
) {
971 if (memcmp(fw_ap
->bssid
, entry
->addr
, sizeof(entry
->addr
)))
974 memcpy(entry
->rx_pn
, fw_ap
->rx_pn
, sizeof(entry
->rx_pn
));
975 memcpy(entry
->tx_pn
, fw_ap
->tx_pn
, sizeof(entry
->tx_pn
));
980 static u8
iwl_mvm_ftm_get_range_resp_ver(struct iwl_mvm
*mvm
)
982 if (!fw_has_api(&mvm
->fw
->ucode_capa
,
983 IWL_UCODE_TLV_API_FTM_NEW_RANGE_REQ
))
986 /* Starting from version 8, the FW advertises the version */
987 if (mvm
->cmd_ver
.range_resp
>= 8)
988 return mvm
->cmd_ver
.range_resp
;
989 else if (fw_has_api(&mvm
->fw
->ucode_capa
,
990 IWL_UCODE_TLV_API_FTM_RTT_ACCURACY
))
993 /* The first version of the new range request API */
997 static bool iwl_mvm_ftm_resp_size_validation(u8 ver
, unsigned int pkt_len
)
1001 return pkt_len
== sizeof(struct iwl_tof_range_rsp_ntfy_v8
);
1003 return pkt_len
== sizeof(struct iwl_tof_range_rsp_ntfy_v7
);
1005 return pkt_len
== sizeof(struct iwl_tof_range_rsp_ntfy_v6
);
1007 return pkt_len
== sizeof(struct iwl_tof_range_rsp_ntfy_v5
);
1009 WARN_ONCE(1, "FTM: unsupported range response version %u", ver
);
1014 void iwl_mvm_ftm_range_resp(struct iwl_mvm
*mvm
, struct iwl_rx_cmd_buffer
*rxb
)
1016 struct iwl_rx_packet
*pkt
= rxb_addr(rxb
);
1017 unsigned int pkt_len
= iwl_rx_packet_payload_len(pkt
);
1018 struct iwl_tof_range_rsp_ntfy_v5
*fw_resp_v5
= (void *)pkt
->data
;
1019 struct iwl_tof_range_rsp_ntfy_v6
*fw_resp_v6
= (void *)pkt
->data
;
1020 struct iwl_tof_range_rsp_ntfy_v7
*fw_resp_v7
= (void *)pkt
->data
;
1021 struct iwl_tof_range_rsp_ntfy_v8
*fw_resp_v8
= (void *)pkt
->data
;
1023 bool new_api
= fw_has_api(&mvm
->fw
->ucode_capa
,
1024 IWL_UCODE_TLV_API_FTM_NEW_RANGE_REQ
);
1025 u8 num_of_aps
, last_in_batch
;
1026 u8 notif_ver
= iwl_mvm_ftm_get_range_resp_ver(mvm
);
1028 lockdep_assert_held(&mvm
->mutex
);
1030 if (!mvm
->ftm_initiator
.req
) {
1034 if (unlikely(!iwl_mvm_ftm_resp_size_validation(notif_ver
, pkt_len
)))
1038 if (iwl_mvm_ftm_range_resp_valid(mvm
, fw_resp_v8
->request_id
,
1039 fw_resp_v8
->num_of_aps
))
1042 num_of_aps
= fw_resp_v8
->num_of_aps
;
1043 last_in_batch
= fw_resp_v8
->last_report
;
1045 if (iwl_mvm_ftm_range_resp_valid(mvm
, fw_resp_v5
->request_id
,
1046 fw_resp_v5
->num_of_aps
))
1049 num_of_aps
= fw_resp_v5
->num_of_aps
;
1050 last_in_batch
= fw_resp_v5
->last_in_batch
;
1053 IWL_DEBUG_INFO(mvm
, "Range response received\n");
1054 IWL_DEBUG_INFO(mvm
, "request id: %lld, num of entries: %hhu\n",
1055 mvm
->ftm_initiator
.req
->cookie
, num_of_aps
);
1057 for (i
= 0; i
< num_of_aps
&& i
< IWL_MVM_TOF_MAX_APS
; i
++) {
1058 struct cfg80211_pmsr_result result
= {};
1059 struct iwl_tof_range_rsp_ap_entry_ntfy_v6
*fw_ap
;
1063 if (notif_ver
== 8) {
1064 fw_ap
= &fw_resp_v8
->ap
[i
];
1065 iwl_mvm_ftm_pasn_update_pn(mvm
, fw_ap
);
1066 } else if (notif_ver
== 7) {
1067 fw_ap
= (void *)&fw_resp_v7
->ap
[i
];
1069 fw_ap
= (void *)&fw_resp_v6
->ap
[i
];
1072 result
.final
= fw_ap
->last_burst
;
1073 result
.ap_tsf
= le32_to_cpu(fw_ap
->start_tsf
);
1074 result
.ap_tsf_valid
= 1;
1076 /* the first part is the same for old and new APIs */
1077 fw_ap
= (void *)&fw_resp_v5
->ap
[i
];
1079 * FIXME: the firmware needs to report this, we don't
1080 * even know the number of bursts the responder picked
1081 * (if we asked it to)
1086 peer_idx
= iwl_mvm_ftm_find_peer(mvm
->ftm_initiator
.req
,
1090 "Unknown address (%pM, target #%d) in FTM response\n",
1095 switch (fw_ap
->measure_status
) {
1096 case IWL_TOF_ENTRY_SUCCESS
:
1097 result
.status
= NL80211_PMSR_STATUS_SUCCESS
;
1099 case IWL_TOF_ENTRY_TIMING_MEASURE_TIMEOUT
:
1100 result
.status
= NL80211_PMSR_STATUS_TIMEOUT
;
1102 case IWL_TOF_ENTRY_NO_RESPONSE
:
1103 result
.status
= NL80211_PMSR_STATUS_FAILURE
;
1104 result
.ftm
.failure_reason
=
1105 NL80211_PMSR_FTM_FAILURE_NO_RESPONSE
;
1107 case IWL_TOF_ENTRY_REQUEST_REJECTED
:
1108 result
.status
= NL80211_PMSR_STATUS_FAILURE
;
1109 result
.ftm
.failure_reason
=
1110 NL80211_PMSR_FTM_FAILURE_PEER_BUSY
;
1111 result
.ftm
.busy_retry_time
= fw_ap
->refusal_period
;
1114 result
.status
= NL80211_PMSR_STATUS_FAILURE
;
1115 result
.ftm
.failure_reason
=
1116 NL80211_PMSR_FTM_FAILURE_UNSPECIFIED
;
1119 memcpy(result
.addr
, fw_ap
->bssid
, ETH_ALEN
);
1120 result
.host_time
= iwl_mvm_ftm_get_host_time(mvm
,
1122 result
.type
= NL80211_PMSR_TYPE_FTM
;
1123 result
.ftm
.burst_index
= mvm
->ftm_initiator
.responses
[peer_idx
];
1124 mvm
->ftm_initiator
.responses
[peer_idx
]++;
1125 result
.ftm
.rssi_avg
= fw_ap
->rssi
;
1126 result
.ftm
.rssi_avg_valid
= 1;
1127 result
.ftm
.rssi_spread
= fw_ap
->rssi_spread
;
1128 result
.ftm
.rssi_spread_valid
= 1;
1129 result
.ftm
.rtt_avg
= (s32
)le32_to_cpu(fw_ap
->rtt
);
1130 result
.ftm
.rtt_avg_valid
= 1;
1131 result
.ftm
.rtt_variance
= le32_to_cpu(fw_ap
->rtt_variance
);
1132 result
.ftm
.rtt_variance_valid
= 1;
1133 result
.ftm
.rtt_spread
= le32_to_cpu(fw_ap
->rtt_spread
);
1134 result
.ftm
.rtt_spread_valid
= 1;
1136 iwl_mvm_ftm_get_lci_civic(mvm
, &result
);
1138 iwl_mvm_ftm_rtt_smoothing(mvm
, &result
);
1140 cfg80211_pmsr_report(mvm
->ftm_initiator
.req_wdev
,
1141 mvm
->ftm_initiator
.req
,
1142 &result
, GFP_KERNEL
);
1144 if (fw_has_api(&mvm
->fw
->ucode_capa
,
1145 IWL_UCODE_TLV_API_FTM_RTT_ACCURACY
))
1146 IWL_DEBUG_INFO(mvm
, "RTT confidence: %hhu\n",
1147 fw_ap
->rttConfidence
);
1149 iwl_mvm_debug_range_resp(mvm
, i
, &result
);
1152 if (last_in_batch
) {
1153 cfg80211_pmsr_complete(mvm
->ftm_initiator
.req_wdev
,
1154 mvm
->ftm_initiator
.req
,
1156 iwl_mvm_ftm_reset(mvm
);
1160 void iwl_mvm_ftm_lc_notif(struct iwl_mvm
*mvm
, struct iwl_rx_cmd_buffer
*rxb
)
1162 struct iwl_rx_packet
*pkt
= rxb_addr(rxb
);
1163 const struct ieee80211_mgmt
*mgmt
= (void *)pkt
->data
;
1164 size_t len
= iwl_rx_packet_payload_len(pkt
);
1165 struct iwl_mvm_loc_entry
*entry
;
1166 const u8
*ies
, *lci
, *civic
, *msr_ie
;
1167 size_t ies_len
, lci_len
= 0, civic_len
= 0;
1168 size_t baselen
= IEEE80211_MIN_ACTION_SIZE
+
1169 sizeof(mgmt
->u
.action
.u
.ftm
);
1170 static const u8 rprt_type_lci
= IEEE80211_SPCT_MSR_RPRT_TYPE_LCI
;
1171 static const u8 rprt_type_civic
= IEEE80211_SPCT_MSR_RPRT_TYPE_CIVIC
;
1176 lockdep_assert_held(&mvm
->mutex
);
1178 ies
= mgmt
->u
.action
.u
.ftm
.variable
;
1179 ies_len
= len
- baselen
;
1181 msr_ie
= cfg80211_find_ie_match(WLAN_EID_MEASURE_REPORT
, ies
, ies_len
,
1182 &rprt_type_lci
, 1, 4);
1185 lci_len
= msr_ie
[1];
1188 msr_ie
= cfg80211_find_ie_match(WLAN_EID_MEASURE_REPORT
, ies
, ies_len
,
1189 &rprt_type_civic
, 1, 4);
1192 civic_len
= msr_ie
[1];
1195 entry
= kmalloc(sizeof(*entry
) + lci_len
+ civic_len
, GFP_KERNEL
);
1199 memcpy(entry
->addr
, mgmt
->bssid
, ETH_ALEN
);
1201 entry
->lci_len
= lci_len
;
1203 memcpy(entry
->buf
, lci
, lci_len
);
1205 entry
->civic_len
= civic_len
;
1207 memcpy(entry
->buf
+ lci_len
, civic
, civic_len
);
1209 list_add_tail(&entry
->list
, &mvm
->ftm_initiator
.loc_list
);