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 - 2020 Intel Corporation
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of version 2 of the GNU General Public License as
13 * published by the Free Software Foundation.
14 *
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18 * General Public License for more details.
19 *
20 * The full GNU General Public License is included in this distribution
21 * in the file called COPYING.
22 *
23 * Contact Information:
24 * Intel Linux Wireless <linuxwifi@intel.com>
25 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
26 *
27 * BSD LICENSE
28 *
29 * Copyright(c) 2015 - 2017 Intel Deutschland GmbH
30 * Copyright (C) 2018 - 2020 Intel Corporation
31 * All rights reserved.
32 *
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
35 * are met:
36 *
37 *  * Redistributions of source code must retain the above copyright
38 *    notice, this list of conditions and the following disclaimer.
39 *  * Redistributions in binary form must reproduce the above copyright
40 *    notice, this list of conditions and the following disclaimer in
41 *    the documentation and/or other materials provided with the
42 *    distribution.
43 *  * Neither the name Intel Corporation nor the names of its
44 *    contributors may be used to endorse or promote products derived
45 *    from this software without specific prior written permission.
46 *
47 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
48 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
49 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
50 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
51 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
52 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
53 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
54 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
55 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
56 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
57 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
58 *
59 *****************************************************************************/
60#include <net/cfg80211.h>
61#include <linux/etherdevice.h>
62#include "mvm.h"
63#include "constants.h"
64
65struct iwl_mvm_pasn_sta {
66	struct list_head list;
67	struct iwl_mvm_int_sta int_sta;
68	u8 addr[ETH_ALEN];
69};
70
71struct iwl_mvm_pasn_hltk_data {
72	u8 *addr;
73	u8 cipher;
74	u8 *hltk;
75};
76
77static int iwl_mvm_ftm_responder_set_bw_v1(struct cfg80211_chan_def *chandef,
78					   u8 *bw, u8 *ctrl_ch_position)
79{
80	switch (chandef->width) {
81	case NL80211_CHAN_WIDTH_20_NOHT:
82		*bw = IWL_TOF_BW_20_LEGACY;
83		break;
84	case NL80211_CHAN_WIDTH_20:
85		*bw = IWL_TOF_BW_20_HT;
86		break;
87	case NL80211_CHAN_WIDTH_40:
88		*bw = IWL_TOF_BW_40;
89		*ctrl_ch_position = iwl_mvm_get_ctrl_pos(chandef);
90		break;
91	case NL80211_CHAN_WIDTH_80:
92		*bw = IWL_TOF_BW_80;
93		*ctrl_ch_position = iwl_mvm_get_ctrl_pos(chandef);
94		break;
95	default:
96		return -ENOTSUPP;
97	}
98
99	return 0;
100}
101
102static int iwl_mvm_ftm_responder_set_bw_v2(struct cfg80211_chan_def *chandef,
103					   u8 *format_bw,
104					   u8 *ctrl_ch_position)
105{
106	switch (chandef->width) {
107	case NL80211_CHAN_WIDTH_20_NOHT:
108		*format_bw = IWL_LOCATION_FRAME_FORMAT_LEGACY;
109		*format_bw |= IWL_LOCATION_BW_20MHZ << LOCATION_BW_POS;
110		break;
111	case NL80211_CHAN_WIDTH_20:
112		*format_bw = IWL_LOCATION_FRAME_FORMAT_HT;
113		*format_bw |= IWL_LOCATION_BW_20MHZ << LOCATION_BW_POS;
114		break;
115	case NL80211_CHAN_WIDTH_40:
116		*format_bw = IWL_LOCATION_FRAME_FORMAT_HT;
117		*format_bw |= IWL_LOCATION_BW_40MHZ << LOCATION_BW_POS;
118		*ctrl_ch_position = iwl_mvm_get_ctrl_pos(chandef);
119		break;
120	case NL80211_CHAN_WIDTH_80:
121		*format_bw = IWL_LOCATION_FRAME_FORMAT_VHT;
122		*format_bw |= IWL_LOCATION_BW_80MHZ << LOCATION_BW_POS;
123		*ctrl_ch_position = iwl_mvm_get_ctrl_pos(chandef);
124		break;
125	default:
126		return -ENOTSUPP;
127	}
128
129	return 0;
130}
131
132static int
133iwl_mvm_ftm_responder_cmd(struct iwl_mvm *mvm,
134			  struct ieee80211_vif *vif,
135			  struct cfg80211_chan_def *chandef)
136{
137	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
138	/*
139	 * The command structure is the same for versions 6 and 7, (only the
140	 * field interpretation is different), so the same struct can be use
141	 * for all cases.
142	 */
143	struct iwl_tof_responder_config_cmd cmd = {
144		.channel_num = chandef->chan->hw_value,
145		.cmd_valid_fields =
146			cpu_to_le32(IWL_TOF_RESPONDER_CMD_VALID_CHAN_INFO |
147				    IWL_TOF_RESPONDER_CMD_VALID_BSSID |
148				    IWL_TOF_RESPONDER_CMD_VALID_STA_ID),
149		.sta_id = mvmvif->bcast_sta.sta_id,
150	};
151	u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, LOCATION_GROUP,
152					   TOF_RESPONDER_CONFIG_CMD, 6);
153	int err;
154
155	lockdep_assert_held(&mvm->mutex);
156
157	if (cmd_ver == 7)
158		err = iwl_mvm_ftm_responder_set_bw_v2(chandef, &cmd.format_bw,
159						      &cmd.ctrl_ch_position);
160	else
161		err = iwl_mvm_ftm_responder_set_bw_v1(chandef, &cmd.format_bw,
162						      &cmd.ctrl_ch_position);
163
164	if (err) {
165		IWL_ERR(mvm, "Failed to set responder bandwidth\n");
166		return err;
167	}
168
169	memcpy(cmd.bssid, vif->addr, ETH_ALEN);
170
171	return iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(TOF_RESPONDER_CONFIG_CMD,
172						    LOCATION_GROUP, 0),
173				    0, sizeof(cmd), &cmd);
174}
175
176static int
177iwl_mvm_ftm_responder_dyn_cfg_v2(struct iwl_mvm *mvm,
178				 struct ieee80211_vif *vif,
179				 struct ieee80211_ftm_responder_params *params)
180{
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),
184	};
185	u8 data[IWL_LCI_CIVIC_IE_MAX_SIZE] = {0};
186	struct iwl_host_cmd hcmd = {
187		.id = iwl_cmd_id(TOF_RESPONDER_DYN_CONFIG_CMD,
188				 LOCATION_GROUP, 0),
189		.data[0] = &cmd,
190		.len[0] = sizeof(cmd),
191		.data[1] = &data,
192		/* .len[1] set later */
193		/* may not be able to DMA from stack */
194		.dataflags[1] = IWL_HCMD_DFL_DUP,
195	};
196	u32 aligned_lci_len = ALIGN(params->lci_len + 2, 4);
197	u32 aligned_civicloc_len = ALIGN(params->civicloc_len + 2, 4);
198	u8 *pos = data;
199
200	lockdep_assert_held(&mvm->mutex);
201
202	if (aligned_lci_len + aligned_civicloc_len > sizeof(data)) {
203		IWL_ERR(mvm, "LCI/civicloc data too big (%zd + %zd)\n",
204			params->lci_len, params->civicloc_len);
205		return -ENOBUFS;
206	}
207
208	pos[0] = WLAN_EID_MEASURE_REPORT;
209	pos[1] = params->lci_len;
210	memcpy(pos + 2, params->lci, params->lci_len);
211
212	pos += aligned_lci_len;
213	pos[0] = WLAN_EID_MEASURE_REPORT;
214	pos[1] = params->civicloc_len;
215	memcpy(pos + 2, params->civicloc, params->civicloc_len);
216
217	hcmd.len[1] = aligned_lci_len + aligned_civicloc_len;
218
219	return iwl_mvm_send_cmd(mvm, &hcmd);
220}
221
222static int
223iwl_mvm_ftm_responder_dyn_cfg_v3(struct iwl_mvm *mvm,
224				 struct ieee80211_vif *vif,
225				 struct ieee80211_ftm_responder_params *params,
226				 struct iwl_mvm_pasn_hltk_data *hltk_data)
227{
228	struct iwl_tof_responder_dyn_config_cmd cmd;
229	struct iwl_host_cmd hcmd = {
230		.id = iwl_cmd_id(TOF_RESPONDER_DYN_CONFIG_CMD,
231				 LOCATION_GROUP, 0),
232		.data[0] = &cmd,
233		.len[0] = sizeof(cmd),
234		/* may not be able to DMA from stack */
235		.dataflags[0] = IWL_HCMD_DFL_DUP,
236	};
237
238	lockdep_assert_held(&mvm->mutex);
239
240	cmd.valid_flags = 0;
241
242	if (params) {
243		if (params->lci_len + 2 > sizeof(cmd.lci_buf) ||
244		    params->civicloc_len + 2 > sizeof(cmd.civic_buf)) {
245			IWL_ERR(mvm,
246				"LCI/civic data too big (lci=%zd, civic=%zd)\n",
247				params->lci_len, params->civicloc_len);
248			return -ENOBUFS;
249		}
250
251		cmd.lci_buf[0] = WLAN_EID_MEASURE_REPORT;
252		cmd.lci_buf[1] = params->lci_len;
253		memcpy(cmd.lci_buf + 2, params->lci, params->lci_len);
254		cmd.lci_len = params->lci_len + 2;
255
256		cmd.civic_buf[0] = WLAN_EID_MEASURE_REPORT;
257		cmd.civic_buf[1] = params->civicloc_len;
258		memcpy(cmd.civic_buf + 2, params->civicloc,
259		       params->civicloc_len);
260		cmd.civic_len = params->civicloc_len + 2;
261
262		cmd.valid_flags |= IWL_RESPONDER_DYN_CFG_VALID_LCI |
263			IWL_RESPONDER_DYN_CFG_VALID_CIVIC;
264	}
265
266	if (hltk_data) {
267		if (hltk_data->cipher > IWL_LOCATION_CIPHER_GCMP_256) {
268			IWL_ERR(mvm, "invalid cipher: %u\n",
269				hltk_data->cipher);
270			return -EINVAL;
271		}
272
273		cmd.cipher = hltk_data->cipher;
274		memcpy(cmd.addr, hltk_data->addr, sizeof(cmd.addr));
275		memcpy(cmd.hltk_buf, hltk_data->hltk, sizeof(cmd.hltk_buf));
276		cmd.valid_flags |= IWL_RESPONDER_DYN_CFG_VALID_PASN_STA;
277	}
278
279	return iwl_mvm_send_cmd(mvm, &hcmd);
280}
281
282static int
283iwl_mvm_ftm_responder_dyn_cfg_cmd(struct iwl_mvm *mvm,
284				  struct ieee80211_vif *vif,
285				  struct ieee80211_ftm_responder_params *params)
286{
287	int ret;
288	u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, LOCATION_GROUP,
289					   TOF_RESPONDER_DYN_CONFIG_CMD, 2);
290
291	switch (cmd_ver) {
292	case 2:
293		ret = iwl_mvm_ftm_responder_dyn_cfg_v2(mvm, vif,
294						       params);
295		break;
296	case 3:
297		ret = iwl_mvm_ftm_responder_dyn_cfg_v3(mvm, vif,
298						       params, NULL);
299		break;
300	default:
301		IWL_ERR(mvm, "Unsupported DYN_CONFIG_CMD version %u\n",
302			cmd_ver);
303		ret = -ENOTSUPP;
304	}
305
306	return ret;
307}
308
309static void iwl_mvm_resp_del_pasn_sta(struct iwl_mvm *mvm,
310				      struct ieee80211_vif *vif,
311				      struct iwl_mvm_pasn_sta *sta)
312{
313	list_del(&sta->list);
314	iwl_mvm_rm_sta_id(mvm, vif, sta->int_sta.sta_id);
315	iwl_mvm_dealloc_int_sta(mvm, &sta->int_sta);
316	kfree(sta);
317}
318
319int iwl_mvm_ftm_respoder_add_pasn_sta(struct iwl_mvm *mvm,
320				      struct ieee80211_vif *vif,
321				      u8 *addr, u32 cipher, u8 *tk, u32 tk_len,
322				      u8 *hltk, u32 hltk_len)
323{
324	int ret;
325	struct iwl_mvm_pasn_sta *sta = NULL;
326	struct iwl_mvm_pasn_hltk_data hltk_data = {
327		.addr = addr,
328		.hltk = hltk,
329	};
330	u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, LOCATION_GROUP,
331					   TOF_RESPONDER_DYN_CONFIG_CMD, 2);
332
333	lockdep_assert_held(&mvm->mutex);
334
335	if (cmd_ver < 3) {
336		IWL_ERR(mvm, "Adding PASN station not supported by FW\n");
337		return -ENOTSUPP;
338	}
339
340	hltk_data.cipher = iwl_mvm_cipher_to_location_cipher(cipher);
341	if (hltk_data.cipher == IWL_LOCATION_CIPHER_INVALID) {
342		IWL_ERR(mvm, "invalid cipher: %u\n", cipher);
343		return -EINVAL;
344	}
345
346	if (tk && tk_len) {
347		sta = kzalloc(sizeof(*sta), GFP_KERNEL);
348		if (!sta)
349			return -ENOBUFS;
350
351		ret = iwl_mvm_add_pasn_sta(mvm, vif, &sta->int_sta, addr,
352					   cipher, tk, tk_len);
353		if (ret) {
354			kfree(sta);
355			return ret;
356		}
357
358		memcpy(sta->addr, addr, ETH_ALEN);
359		list_add_tail(&sta->list, &mvm->resp_pasn_list);
360	}
361
362	ret = iwl_mvm_ftm_responder_dyn_cfg_v3(mvm, vif, NULL, &hltk_data);
363	if (ret && sta)
364		iwl_mvm_resp_del_pasn_sta(mvm, vif, sta);
365
366	return ret;
367}
368
369int iwl_mvm_ftm_resp_remove_pasn_sta(struct iwl_mvm *mvm,
370				     struct ieee80211_vif *vif, u8 *addr)
371{
372	struct iwl_mvm_pasn_sta *sta, *prev;
373
374	lockdep_assert_held(&mvm->mutex);
375
376	list_for_each_entry_safe(sta, prev, &mvm->resp_pasn_list, list) {
377		if (!memcmp(sta->addr, addr, ETH_ALEN)) {
378			iwl_mvm_resp_del_pasn_sta(mvm, vif, sta);
379			return 0;
380		}
381	}
382
383	IWL_ERR(mvm, "FTM: PASN station %pM not found\n", addr);
384	return -EINVAL;
385}
386
387int iwl_mvm_ftm_start_responder(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
388{
389	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
390	struct ieee80211_ftm_responder_params *params;
391	struct ieee80211_chanctx_conf ctx, *pctx;
392	u16 *phy_ctxt_id;
393	struct iwl_mvm_phy_ctxt *phy_ctxt;
394	int ret;
395
396	params = vif->bss_conf.ftmr_params;
397
398	lockdep_assert_held(&mvm->mutex);
399
400	if (WARN_ON_ONCE(!vif->bss_conf.ftm_responder))
401		return -EINVAL;
402
403	if (vif->p2p || vif->type != NL80211_IFTYPE_AP ||
404	    !mvmvif->ap_ibss_active) {
405		IWL_ERR(mvm, "Cannot start responder, not in AP mode\n");
406		return -EIO;
407	}
408
409	rcu_read_lock();
410	pctx = rcu_dereference(vif->chanctx_conf);
411	/* Copy the ctx to unlock the rcu and send the phy ctxt. We don't care
412	 * about changes in the ctx after releasing the lock because the driver
413	 * is still protected by the mutex. */
414	ctx = *pctx;
415	phy_ctxt_id  = (u16 *)pctx->drv_priv;
416	rcu_read_unlock();
417
418	phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id];
419	ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx.def,
420				       ctx.rx_chains_static,
421				       ctx.rx_chains_dynamic);
422	if (ret)
423		return ret;
424
425	ret = iwl_mvm_ftm_responder_cmd(mvm, vif, &ctx.def);
426	if (ret)
427		return ret;
428
429	if (params)
430		ret = iwl_mvm_ftm_responder_dyn_cfg_cmd(mvm, vif, params);
431
432	return ret;
433}
434
435void iwl_mvm_ftm_responder_clear(struct iwl_mvm *mvm,
436				 struct ieee80211_vif *vif)
437{
438	struct iwl_mvm_pasn_sta *sta, *prev;
439
440	lockdep_assert_held(&mvm->mutex);
441
442	list_for_each_entry_safe(sta, prev, &mvm->resp_pasn_list, list)
443		iwl_mvm_resp_del_pasn_sta(mvm, vif, sta);
444}
445
446void iwl_mvm_ftm_restart_responder(struct iwl_mvm *mvm,
447				   struct ieee80211_vif *vif)
448{
449	if (!vif->bss_conf.ftm_responder)
450		return;
451
452	iwl_mvm_ftm_responder_clear(mvm, vif);
453	iwl_mvm_ftm_start_responder(mvm, vif);
454}
455
456void iwl_mvm_ftm_responder_stats(struct iwl_mvm *mvm,
457				 struct iwl_rx_cmd_buffer *rxb)
458{
459	struct iwl_rx_packet *pkt = rxb_addr(rxb);
460	struct iwl_ftm_responder_stats *resp = (void *)pkt->data;
461	struct cfg80211_ftm_responder_stats *stats = &mvm->ftm_resp_stats;
462	u32 flags = le32_to_cpu(resp->flags);
463
464	if (resp->success_ftm == resp->ftm_per_burst)
465		stats->success_num++;
466	else if (resp->success_ftm >= 2)
467		stats->partial_num++;
468	else
469		stats->failed_num++;
470
471	if ((flags & FTM_RESP_STAT_ASAP_REQ) &&
472	    (flags & FTM_RESP_STAT_ASAP_RESP))
473		stats->asap_num++;
474
475	if (flags & FTM_RESP_STAT_NON_ASAP_RESP)
476		stats->non_asap_num++;
477
478	stats->total_duration_ms += le32_to_cpu(resp->duration) / USEC_PER_MSEC;
479
480	if (flags & FTM_RESP_STAT_TRIGGER_UNKNOWN)
481		stats->unknown_triggers_num++;
482
483	if (flags & FTM_RESP_STAT_DUP)
484		stats->reschedule_requests_num++;
485
486	if (flags & FTM_RESP_STAT_NON_ASAP_OUT_WIN)
487		stats->out_of_window_triggers_num++;
488}
489