1 /******************************************************************************
2  *
3  * This file is provided under a dual BSD/GPLv2 license.  When using or
4  * redistributing this file, you may do so under either license.
5  *
6  * GPL LICENSE SUMMARY
7  *
8  * Copyright(c) 2015 - 2017 Intel Deutschland GmbH
9  * Copyright (C) 2018 Intel Corporation
10  *
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 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 
65 static int
66 iwl_mvm_ftm_responder_cmd(struct iwl_mvm *mvm,
67 			  struct ieee80211_vif *vif,
68 			  struct cfg80211_chan_def *chandef)
69 {
70 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
71 	struct iwl_tof_responder_config_cmd cmd = {
72 		.channel_num = chandef->chan->hw_value,
73 		.cmd_valid_fields =
74 			cpu_to_le32(IWL_TOF_RESPONDER_CMD_VALID_CHAN_INFO |
75 				    IWL_TOF_RESPONDER_CMD_VALID_BSSID |
76 				    IWL_TOF_RESPONDER_CMD_VALID_STA_ID),
77 		.sta_id = mvmvif->bcast_sta.sta_id,
78 	};
79 
80 	lockdep_assert_held(&mvm->mutex);
81 
82 	switch (chandef->width) {
83 	case NL80211_CHAN_WIDTH_20_NOHT:
84 		cmd.bandwidth = IWL_TOF_BW_20_LEGACY;
85 		break;
86 	case NL80211_CHAN_WIDTH_20:
87 		cmd.bandwidth = IWL_TOF_BW_20_HT;
88 		break;
89 	case NL80211_CHAN_WIDTH_40:
90 		cmd.bandwidth = IWL_TOF_BW_40;
91 		cmd.ctrl_ch_position = iwl_mvm_get_ctrl_pos(chandef);
92 		break;
93 	case NL80211_CHAN_WIDTH_80:
94 		cmd.bandwidth = IWL_TOF_BW_80;
95 		cmd.ctrl_ch_position = iwl_mvm_get_ctrl_pos(chandef);
96 		break;
97 	default:
98 		WARN_ON(1);
99 		return -EINVAL;
100 	}
101 
102 	memcpy(cmd.bssid, vif->addr, ETH_ALEN);
103 
104 	return iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(TOF_RESPONDER_CONFIG_CMD,
105 						    LOCATION_GROUP, 0),
106 				    0, sizeof(cmd), &cmd);
107 }
108 
109 static int
110 iwl_mvm_ftm_responder_dyn_cfg_cmd(struct iwl_mvm *mvm,
111 				  struct ieee80211_vif *vif,
112 				  struct ieee80211_ftm_responder_params *params)
113 {
114 	struct iwl_tof_responder_dyn_config_cmd cmd = {
115 		.lci_len = cpu_to_le32(params->lci_len + 2),
116 		.civic_len = cpu_to_le32(params->civicloc_len + 2),
117 	};
118 	u8 data[IWL_LCI_CIVIC_IE_MAX_SIZE] = {0};
119 	struct iwl_host_cmd hcmd = {
120 		.id = iwl_cmd_id(TOF_RESPONDER_DYN_CONFIG_CMD,
121 				 LOCATION_GROUP, 0),
122 		.data[0] = &cmd,
123 		.len[0] = sizeof(cmd),
124 		.data[1] = &data,
125 		/* .len[1] set later */
126 		/* may not be able to DMA from stack */
127 		.dataflags[1] = IWL_HCMD_DFL_DUP,
128 	};
129 	u32 aligned_lci_len = ALIGN(params->lci_len + 2, 4);
130 	u32 aligned_civicloc_len = ALIGN(params->civicloc_len + 2, 4);
131 	u8 *pos = data;
132 
133 	lockdep_assert_held(&mvm->mutex);
134 
135 	if (aligned_lci_len + aligned_civicloc_len > sizeof(data)) {
136 		IWL_ERR(mvm, "LCI/civicloc data too big (%zd + %zd)\n",
137 			params->lci_len, params->civicloc_len);
138 		return -ENOBUFS;
139 	}
140 
141 	pos[0] = WLAN_EID_MEASURE_REPORT;
142 	pos[1] = params->lci_len;
143 	memcpy(pos + 2, params->lci, params->lci_len);
144 
145 	pos += aligned_lci_len;
146 	pos[0] = WLAN_EID_MEASURE_REPORT;
147 	pos[1] = params->civicloc_len;
148 	memcpy(pos + 2, params->civicloc, params->civicloc_len);
149 
150 	hcmd.len[1] = aligned_lci_len + aligned_civicloc_len;
151 
152 	return iwl_mvm_send_cmd(mvm, &hcmd);
153 }
154 
155 int iwl_mvm_ftm_start_responder(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
156 {
157 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
158 	struct ieee80211_ftm_responder_params *params;
159 	struct ieee80211_chanctx_conf ctx, *pctx;
160 	u16 *phy_ctxt_id;
161 	struct iwl_mvm_phy_ctxt *phy_ctxt;
162 	int ret;
163 
164 	params = vif->bss_conf.ftmr_params;
165 
166 	lockdep_assert_held(&mvm->mutex);
167 
168 	if (WARN_ON_ONCE(!vif->bss_conf.ftm_responder))
169 		return -EINVAL;
170 
171 	if (vif->p2p || vif->type != NL80211_IFTYPE_AP ||
172 	    !mvmvif->ap_ibss_active) {
173 		IWL_ERR(mvm, "Cannot start responder, not in AP mode\n");
174 		return -EIO;
175 	}
176 
177 	rcu_read_lock();
178 	pctx = rcu_dereference(vif->chanctx_conf);
179 	/* Copy the ctx to unlock the rcu and send the phy ctxt. We don't care
180 	 * about changes in the ctx after releasing the lock because the driver
181 	 * is still protected by the mutex. */
182 	ctx = *pctx;
183 	phy_ctxt_id  = (u16 *)pctx->drv_priv;
184 	rcu_read_unlock();
185 
186 	phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id];
187 	ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx.def,
188 				       ctx.rx_chains_static,
189 				       ctx.rx_chains_dynamic);
190 	if (ret)
191 		return ret;
192 
193 	ret = iwl_mvm_ftm_responder_cmd(mvm, vif, &ctx.def);
194 	if (ret)
195 		return ret;
196 
197 	if (params)
198 		ret = iwl_mvm_ftm_responder_dyn_cfg_cmd(mvm, vif, params);
199 
200 	return ret;
201 }
202 
203 void iwl_mvm_ftm_restart_responder(struct iwl_mvm *mvm,
204 				   struct ieee80211_vif *vif)
205 {
206 	if (!vif->bss_conf.ftm_responder)
207 		return;
208 
209 	iwl_mvm_ftm_start_responder(mvm, vif);
210 }
211 
212 void iwl_mvm_ftm_responder_stats(struct iwl_mvm *mvm,
213 				 struct iwl_rx_cmd_buffer *rxb)
214 {
215 	struct iwl_rx_packet *pkt = rxb_addr(rxb);
216 	struct iwl_ftm_responder_stats *resp = (void *)pkt->data;
217 	struct cfg80211_ftm_responder_stats *stats = &mvm->ftm_resp_stats;
218 	u32 flags = le32_to_cpu(resp->flags);
219 
220 	if (resp->success_ftm == resp->ftm_per_burst)
221 		stats->success_num++;
222 	else if (resp->success_ftm >= 2)
223 		stats->partial_num++;
224 	else
225 		stats->failed_num++;
226 
227 	if ((flags & FTM_RESP_STAT_ASAP_REQ) &&
228 	    (flags & FTM_RESP_STAT_ASAP_RESP))
229 		stats->asap_num++;
230 
231 	if (flags & FTM_RESP_STAT_NON_ASAP_RESP)
232 		stats->non_asap_num++;
233 
234 	stats->total_duration_ms += le32_to_cpu(resp->duration) / USEC_PER_MSEC;
235 
236 	if (flags & FTM_RESP_STAT_TRIGGER_UNKNOWN)
237 		stats->unknown_triggers_num++;
238 
239 	if (flags & FTM_RESP_STAT_DUP)
240 		stats->reschedule_requests_num++;
241 
242 	if (flags & FTM_RESP_STAT_NON_ASAP_OUT_WIN)
243 		stats->out_of_window_triggers_num++;
244 }
245