1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
3 * Copyright (C) 2015-2017 Intel Deutschland GmbH
4 * Copyright (C) 2018-2024 Intel Corporation
6 #include <net/cfg80211.h>
7 #include <linux/etherdevice.h>
11 struct iwl_mvm_pasn_sta
{
12 struct list_head list
;
13 struct iwl_mvm_int_sta int_sta
;
16 /* must be last as it followed by buffer holding the key */
17 struct ieee80211_key_conf keyconf
;
20 struct iwl_mvm_pasn_hltk_data
{
26 static int iwl_mvm_ftm_responder_set_bw_v1(struct cfg80211_chan_def
*chandef
,
27 u8
*bw
, u8
*ctrl_ch_position
)
29 switch (chandef
->width
) {
30 case NL80211_CHAN_WIDTH_20_NOHT
:
31 *bw
= IWL_TOF_BW_20_LEGACY
;
33 case NL80211_CHAN_WIDTH_20
:
34 *bw
= IWL_TOF_BW_20_HT
;
36 case NL80211_CHAN_WIDTH_40
:
38 *ctrl_ch_position
= iwl_mvm_get_ctrl_pos(chandef
);
40 case NL80211_CHAN_WIDTH_80
:
42 *ctrl_ch_position
= iwl_mvm_get_ctrl_pos(chandef
);
51 static int iwl_mvm_ftm_responder_set_bw_v2(struct cfg80211_chan_def
*chandef
,
52 u8
*format_bw
, u8
*ctrl_ch_position
,
55 switch (chandef
->width
) {
56 case NL80211_CHAN_WIDTH_20_NOHT
:
57 *format_bw
= IWL_LOCATION_FRAME_FORMAT_LEGACY
;
58 *format_bw
|= IWL_LOCATION_BW_20MHZ
<< LOCATION_BW_POS
;
60 case NL80211_CHAN_WIDTH_20
:
61 *format_bw
= IWL_LOCATION_FRAME_FORMAT_HT
;
62 *format_bw
|= IWL_LOCATION_BW_20MHZ
<< LOCATION_BW_POS
;
64 case NL80211_CHAN_WIDTH_40
:
65 *format_bw
= IWL_LOCATION_FRAME_FORMAT_HT
;
66 *format_bw
|= IWL_LOCATION_BW_40MHZ
<< LOCATION_BW_POS
;
67 *ctrl_ch_position
= iwl_mvm_get_ctrl_pos(chandef
);
69 case NL80211_CHAN_WIDTH_80
:
70 *format_bw
= IWL_LOCATION_FRAME_FORMAT_VHT
;
71 *format_bw
|= IWL_LOCATION_BW_80MHZ
<< LOCATION_BW_POS
;
72 *ctrl_ch_position
= iwl_mvm_get_ctrl_pos(chandef
);
74 case NL80211_CHAN_WIDTH_160
:
76 *format_bw
= IWL_LOCATION_FRAME_FORMAT_HE
;
77 *format_bw
|= IWL_LOCATION_BW_160MHZ
<< LOCATION_BW_POS
;
78 *ctrl_ch_position
= iwl_mvm_get_ctrl_pos(chandef
);
90 iwl_mvm_ftm_responder_set_ndp(struct iwl_mvm
*mvm
,
91 struct iwl_tof_responder_config_cmd
*cmd
)
93 /* Up to 2 R2I STS are allowed on the responder */
94 u32 r2i_max_sts
= IWL_MVM_FTM_R2I_MAX_STS
< 2 ?
95 IWL_MVM_FTM_R2I_MAX_STS
: 1;
97 cmd
->r2i_ndp_params
= IWL_MVM_FTM_R2I_MAX_REP
|
98 (r2i_max_sts
<< IWL_RESPONDER_STS_POS
) |
99 (IWL_MVM_FTM_R2I_MAX_TOTAL_LTF
<< IWL_RESPONDER_TOTAL_LTF_POS
);
100 cmd
->i2r_ndp_params
= IWL_MVM_FTM_I2R_MAX_REP
|
101 (IWL_MVM_FTM_I2R_MAX_STS
<< IWL_RESPONDER_STS_POS
) |
102 (IWL_MVM_FTM_I2R_MAX_TOTAL_LTF
<< IWL_RESPONDER_TOTAL_LTF_POS
);
103 cmd
->cmd_valid_fields
|=
104 cpu_to_le32(IWL_TOF_RESPONDER_CMD_VALID_NDP_PARAMS
);
108 iwl_mvm_ftm_responder_cmd(struct iwl_mvm
*mvm
,
109 struct ieee80211_vif
*vif
,
110 struct cfg80211_chan_def
*chandef
,
111 struct ieee80211_bss_conf
*link_conf
)
113 u32 cmd_id
= WIDE_ID(LOCATION_GROUP
, TOF_RESPONDER_CONFIG_CMD
);
114 struct iwl_mvm_vif
*mvmvif
= iwl_mvm_vif_from_mac80211(vif
);
116 * The command structure is the same for versions 6, 7 and 8 (only the
117 * field interpretation is different), so the same struct can be use
120 struct iwl_tof_responder_config_cmd cmd
= {
121 .channel_num
= chandef
->chan
->hw_value
,
123 cpu_to_le32(IWL_TOF_RESPONDER_CMD_VALID_CHAN_INFO
|
124 IWL_TOF_RESPONDER_CMD_VALID_BSSID
|
125 IWL_TOF_RESPONDER_CMD_VALID_STA_ID
),
126 .sta_id
= mvmvif
->link
[link_conf
->link_id
]->bcast_sta
.sta_id
,
128 u8 cmd_ver
= iwl_fw_lookup_cmd_ver(mvm
->fw
, cmd_id
, 6);
132 lockdep_assert_held(&mvm
->mutex
);
136 iwl_mvm_phy_band_from_nl80211(chandef
->chan
->band
);
139 /* Use a default of bss_color=1 for now */
141 cmd
.cmd_valid_fields
|=
142 cpu_to_le32(IWL_TOF_RESPONDER_CMD_VALID_BSS_COLOR
|
143 IWL_TOF_RESPONDER_CMD_VALID_MIN_MAX_TIME_BETWEEN_MSR
);
145 cmd
.min_time_between_msr
=
146 cpu_to_le16(IWL_MVM_FTM_NON_TB_MIN_TIME_BETWEEN_MSR
);
147 cmd
.max_time_between_msr
=
148 cpu_to_le16(IWL_MVM_FTM_NON_TB_MAX_TIME_BETWEEN_MSR
);
149 cmd_size
= sizeof(struct iwl_tof_responder_config_cmd_v9
);
151 /* All versions up to version 8 have the same size */
152 cmd_size
= sizeof(struct iwl_tof_responder_config_cmd_v8
);
156 iwl_mvm_ftm_responder_set_ndp(mvm
, (void *)&cmd
);
159 err
= iwl_mvm_ftm_responder_set_bw_v2(chandef
, &cmd
.format_bw
,
160 &cmd
.ctrl_ch_position
,
163 err
= iwl_mvm_ftm_responder_set_bw_v1(chandef
, &cmd
.format_bw
,
164 &cmd
.ctrl_ch_position
);
167 IWL_ERR(mvm
, "Failed to set responder bandwidth\n");
171 memcpy(cmd
.bssid
, vif
->addr
, ETH_ALEN
);
173 return iwl_mvm_send_cmd_pdu(mvm
, cmd_id
, 0, cmd_size
, &cmd
);
177 iwl_mvm_ftm_responder_dyn_cfg_v2(struct iwl_mvm
*mvm
,
178 struct ieee80211_vif
*vif
,
179 struct ieee80211_ftm_responder_params
*params
)
181 struct iwl_tof_responder_dyn_config_cmd_v2 cmd
= {
182 .lci_len
= cpu_to_le32(params
->lci_len
+ 2),
183 .civic_len
= cpu_to_le32(params
->civicloc_len
+ 2),
185 u8 data
[IWL_LCI_CIVIC_IE_MAX_SIZE
] = {0};
186 struct iwl_host_cmd hcmd
= {
187 .id
= WIDE_ID(LOCATION_GROUP
, TOF_RESPONDER_DYN_CONFIG_CMD
),
189 .len
[0] = sizeof(cmd
),
191 /* .len[1] set later */
192 /* may not be able to DMA from stack */
193 .dataflags
[1] = IWL_HCMD_DFL_DUP
,
195 u32 aligned_lci_len
= ALIGN(params
->lci_len
+ 2, 4);
196 u32 aligned_civicloc_len
= ALIGN(params
->civicloc_len
+ 2, 4);
199 lockdep_assert_held(&mvm
->mutex
);
201 if (aligned_lci_len
+ aligned_civicloc_len
> sizeof(data
)) {
202 IWL_ERR(mvm
, "LCI/civicloc data too big (%zd + %zd)\n",
203 params
->lci_len
, params
->civicloc_len
);
207 pos
[0] = WLAN_EID_MEASURE_REPORT
;
208 pos
[1] = params
->lci_len
;
209 memcpy(pos
+ 2, params
->lci
, params
->lci_len
);
211 pos
+= aligned_lci_len
;
212 pos
[0] = WLAN_EID_MEASURE_REPORT
;
213 pos
[1] = params
->civicloc_len
;
214 memcpy(pos
+ 2, params
->civicloc
, params
->civicloc_len
);
216 hcmd
.len
[1] = aligned_lci_len
+ aligned_civicloc_len
;
218 return iwl_mvm_send_cmd(mvm
, &hcmd
);
222 iwl_mvm_ftm_responder_dyn_cfg_v3(struct iwl_mvm
*mvm
,
223 struct ieee80211_vif
*vif
,
224 struct ieee80211_ftm_responder_params
*params
,
225 struct iwl_mvm_pasn_hltk_data
*hltk_data
)
227 struct iwl_tof_responder_dyn_config_cmd cmd
;
228 struct iwl_host_cmd hcmd
= {
229 .id
= WIDE_ID(LOCATION_GROUP
, TOF_RESPONDER_DYN_CONFIG_CMD
),
231 .len
[0] = sizeof(cmd
),
232 /* may not be able to DMA from stack */
233 .dataflags
[0] = IWL_HCMD_DFL_DUP
,
236 lockdep_assert_held(&mvm
->mutex
);
241 if (params
->lci_len
+ 2 > sizeof(cmd
.lci_buf
) ||
242 params
->civicloc_len
+ 2 > sizeof(cmd
.civic_buf
)) {
244 "LCI/civic data too big (lci=%zd, civic=%zd)\n",
245 params
->lci_len
, params
->civicloc_len
);
249 cmd
.lci_buf
[0] = WLAN_EID_MEASURE_REPORT
;
250 cmd
.lci_buf
[1] = params
->lci_len
;
251 memcpy(cmd
.lci_buf
+ 2, params
->lci
, params
->lci_len
);
252 cmd
.lci_len
= params
->lci_len
+ 2;
254 cmd
.civic_buf
[0] = WLAN_EID_MEASURE_REPORT
;
255 cmd
.civic_buf
[1] = params
->civicloc_len
;
256 memcpy(cmd
.civic_buf
+ 2, params
->civicloc
,
257 params
->civicloc_len
);
258 cmd
.civic_len
= params
->civicloc_len
+ 2;
260 cmd
.valid_flags
|= IWL_RESPONDER_DYN_CFG_VALID_LCI
|
261 IWL_RESPONDER_DYN_CFG_VALID_CIVIC
;
265 if (hltk_data
->cipher
> IWL_LOCATION_CIPHER_GCMP_256
) {
266 IWL_ERR(mvm
, "invalid cipher: %u\n",
271 cmd
.cipher
= hltk_data
->cipher
;
272 memcpy(cmd
.addr
, hltk_data
->addr
, sizeof(cmd
.addr
));
273 memcpy(cmd
.hltk_buf
, hltk_data
->hltk
, sizeof(cmd
.hltk_buf
));
274 cmd
.valid_flags
|= IWL_RESPONDER_DYN_CFG_VALID_PASN_STA
;
277 return iwl_mvm_send_cmd(mvm
, &hcmd
);
281 iwl_mvm_ftm_responder_dyn_cfg_cmd(struct iwl_mvm
*mvm
,
282 struct ieee80211_vif
*vif
,
283 struct ieee80211_ftm_responder_params
*params
)
286 u8 cmd_ver
= iwl_fw_lookup_cmd_ver(mvm
->fw
,
287 WIDE_ID(LOCATION_GROUP
, TOF_RESPONDER_DYN_CONFIG_CMD
),
292 ret
= iwl_mvm_ftm_responder_dyn_cfg_v2(mvm
, vif
,
296 ret
= iwl_mvm_ftm_responder_dyn_cfg_v3(mvm
, vif
,
300 IWL_ERR(mvm
, "Unsupported DYN_CONFIG_CMD version %u\n",
308 static void iwl_mvm_resp_del_pasn_sta(struct iwl_mvm
*mvm
,
309 struct ieee80211_vif
*vif
,
310 struct iwl_mvm_pasn_sta
*sta
)
312 list_del(&sta
->list
);
314 if (sta
->keyconf
.keylen
)
315 iwl_mvm_sec_key_del_pasn(mvm
, vif
, BIT(sta
->int_sta
.sta_id
),
318 if (iwl_mvm_has_mld_api(mvm
->fw
))
319 iwl_mvm_mld_rm_sta_id(mvm
, sta
->int_sta
.sta_id
);
321 iwl_mvm_rm_sta_id(mvm
, vif
, sta
->int_sta
.sta_id
);
323 iwl_mvm_dealloc_int_sta(mvm
, &sta
->int_sta
);
327 int iwl_mvm_ftm_respoder_add_pasn_sta(struct iwl_mvm
*mvm
,
328 struct ieee80211_vif
*vif
,
329 u8
*addr
, u32 cipher
, u8
*tk
, u32 tk_len
,
330 u8
*hltk
, u32 hltk_len
)
333 struct iwl_mvm_pasn_sta
*sta
= NULL
;
334 struct iwl_mvm_pasn_hltk_data hltk_data
= {
338 struct iwl_mvm_pasn_hltk_data
*hltk_data_ptr
= NULL
;
340 u8 cmd_ver
= iwl_fw_lookup_cmd_ver(mvm
->fw
,
341 WIDE_ID(LOCATION_GROUP
, TOF_RESPONDER_DYN_CONFIG_CMD
),
344 lockdep_assert_held(&mvm
->mutex
);
347 IWL_ERR(mvm
, "Adding PASN station not supported by FW\n");
351 if ((!hltk
|| !hltk_len
) && (!tk
|| !tk_len
)) {
352 IWL_ERR(mvm
, "TK and HLTK not set\n");
356 if (hltk
&& hltk_len
) {
357 if (!fw_has_capa(&mvm
->fw
->ucode_capa
,
358 IWL_UCODE_TLV_CAPA_SECURE_LTF_SUPPORT
)) {
359 IWL_ERR(mvm
, "No support for secure LTF measurement\n");
363 hltk_data
.cipher
= iwl_mvm_cipher_to_location_cipher(cipher
);
364 if (hltk_data
.cipher
== IWL_LOCATION_CIPHER_INVALID
) {
365 IWL_ERR(mvm
, "invalid cipher: %u\n", cipher
);
369 hltk_data_ptr
= &hltk_data
;
373 sta
= kzalloc(sizeof(*sta
) + tk_len
, GFP_KERNEL
);
377 ret
= iwl_mvm_add_pasn_sta(mvm
, vif
, &sta
->int_sta
, addr
,
378 cipher
, tk
, tk_len
, &sta
->keyconf
);
384 memcpy(sta
->addr
, addr
, ETH_ALEN
);
385 list_add_tail(&sta
->list
, &mvm
->resp_pasn_list
);
388 ret
= iwl_mvm_ftm_responder_dyn_cfg_v3(mvm
, vif
, NULL
, hltk_data_ptr
);
390 iwl_mvm_resp_del_pasn_sta(mvm
, vif
, sta
);
395 int iwl_mvm_ftm_resp_remove_pasn_sta(struct iwl_mvm
*mvm
,
396 struct ieee80211_vif
*vif
, u8
*addr
)
398 struct iwl_mvm_pasn_sta
*sta
, *prev
;
400 lockdep_assert_held(&mvm
->mutex
);
402 list_for_each_entry_safe(sta
, prev
, &mvm
->resp_pasn_list
, list
) {
403 if (!memcmp(sta
->addr
, addr
, ETH_ALEN
)) {
404 iwl_mvm_resp_del_pasn_sta(mvm
, vif
, sta
);
409 IWL_ERR(mvm
, "FTM: PASN station %pM not found\n", addr
);
413 int iwl_mvm_ftm_start_responder(struct iwl_mvm
*mvm
, struct ieee80211_vif
*vif
,
414 struct ieee80211_bss_conf
*bss_conf
)
416 struct iwl_mvm_vif
*mvmvif
= iwl_mvm_vif_from_mac80211(vif
);
417 struct ieee80211_ftm_responder_params
*params
;
418 struct ieee80211_chanctx_conf ctx
, *pctx
;
420 struct iwl_mvm_phy_ctxt
*phy_ctxt
;
423 params
= bss_conf
->ftmr_params
;
425 lockdep_assert_held(&mvm
->mutex
);
427 if (WARN_ON_ONCE(!bss_conf
->ftm_responder
))
430 if (vif
->p2p
|| vif
->type
!= NL80211_IFTYPE_AP
||
431 !mvmvif
->ap_ibss_active
) {
432 IWL_ERR(mvm
, "Cannot start responder, not in AP mode\n");
437 pctx
= rcu_dereference(bss_conf
->chanctx_conf
);
438 /* Copy the ctx to unlock the rcu and send the phy ctxt. We don't care
439 * about changes in the ctx after releasing the lock because the driver
440 * is still protected by the mutex. */
442 phy_ctxt_id
= (u16
*)pctx
->drv_priv
;
445 phy_ctxt
= &mvm
->phy_ctxts
[*phy_ctxt_id
];
446 ret
= iwl_mvm_phy_ctxt_changed(mvm
, phy_ctxt
, &ctx
.def
, &ctx
.ap
,
447 ctx
.rx_chains_static
,
448 ctx
.rx_chains_dynamic
);
452 ret
= iwl_mvm_ftm_responder_cmd(mvm
, vif
, &ctx
.def
, bss_conf
);
457 ret
= iwl_mvm_ftm_responder_dyn_cfg_cmd(mvm
, vif
, params
);
462 void iwl_mvm_ftm_responder_clear(struct iwl_mvm
*mvm
,
463 struct ieee80211_vif
*vif
)
465 struct iwl_mvm_pasn_sta
*sta
, *prev
;
467 lockdep_assert_held(&mvm
->mutex
);
469 list_for_each_entry_safe(sta
, prev
, &mvm
->resp_pasn_list
, list
)
470 iwl_mvm_resp_del_pasn_sta(mvm
, vif
, sta
);
473 void iwl_mvm_ftm_restart_responder(struct iwl_mvm
*mvm
,
474 struct ieee80211_vif
*vif
,
475 struct ieee80211_bss_conf
*bss_conf
)
477 if (!bss_conf
->ftm_responder
)
480 iwl_mvm_ftm_responder_clear(mvm
, vif
);
481 iwl_mvm_ftm_start_responder(mvm
, vif
, bss_conf
);
484 void iwl_mvm_ftm_responder_stats(struct iwl_mvm
*mvm
,
485 struct iwl_rx_cmd_buffer
*rxb
)
487 struct iwl_rx_packet
*pkt
= rxb_addr(rxb
);
488 struct iwl_ftm_responder_stats
*resp
= (void *)pkt
->data
;
489 struct cfg80211_ftm_responder_stats
*stats
= &mvm
->ftm_resp_stats
;
490 u32 flags
= le32_to_cpu(resp
->flags
);
492 if (resp
->success_ftm
== resp
->ftm_per_burst
)
493 stats
->success_num
++;
494 else if (resp
->success_ftm
>= 2)
495 stats
->partial_num
++;
499 if ((flags
& FTM_RESP_STAT_ASAP_REQ
) &&
500 (flags
& FTM_RESP_STAT_ASAP_RESP
))
503 if (flags
& FTM_RESP_STAT_NON_ASAP_RESP
)
504 stats
->non_asap_num
++;
506 stats
->total_duration_ms
+= le32_to_cpu(resp
->duration
) / USEC_PER_MSEC
;
508 if (flags
& FTM_RESP_STAT_TRIGGER_UNKNOWN
)
509 stats
->unknown_triggers_num
++;
511 if (flags
& FTM_RESP_STAT_DUP
)
512 stats
->reschedule_requests_num
++;
514 if (flags
& FTM_RESP_STAT_NON_ASAP_OUT_WIN
)
515 stats
->out_of_window_triggers_num
++;