blob: 189fd6957fb36c6adad6ed8b99b91690cddf6f7a [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Jeff Johnsond9f08602016-12-02 11:31:30 -08002 * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/*
23 * This file was originally distributed by Qualcomm Atheros, Inc.
24 * under proprietary terms before Copyright ownership was assigned
25 * to the Linux Foundation.
26 */
27
28/**
29 * DOC: wlan_hdd_ftm.c
30 *
31 * This file contains the WLAN factory test mode implementation
32 */
33
Jeff Johnson6f917072016-08-05 17:14:35 -070034/* denote that this file does not allow legacy hddLog */
35#define HDD_DISALLOW_LEGACY_HDDLOG 1
36
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080037#include <cds_mq.h>
38#include "cds_sched.h"
39#include <cds_api.h>
40#include "sir_types.h"
Anurag Chouhan6d760662016-02-20 16:05:43 +053041#include "qdf_types.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080042#include "sir_api.h"
43#include "sir_mac_prot_def.h"
44#include "sme_api.h"
45#include "mac_init_api.h"
46#include "wlan_qct_sys.h"
47#include "wlan_hdd_misc.h"
48#include "i_cds_packet.h"
49#include "cds_reg_service.h"
50#include "wlan_hdd_main.h"
Jeff Johnson9078bdc2016-09-23 17:18:11 -070051#include "wlan_hdd_lpass.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080052#include "qwlan_version.h"
53#include "wma_types.h"
54#include "cfg_api.h"
55
56#if defined(QCA_WIFI_FTM)
57#include "bmi.h"
58#include "ol_fw.h"
59#include "wlan_hdd_cfg80211.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080060#include "hif.h"
61#endif
62
63#define HDD_FTM_WMA_PRE_START_TIMEOUT (30000) /* 30 seconds */
64
65#if defined(QCA_WIFI_FTM)
66#if defined(LINUX_QCMBR)
67#define ATH_XIOCTL_UNIFIED_UTF_CMD 0x1000
68#define ATH_XIOCTL_UNIFIED_UTF_RSP 0x1001
69#define MAX_UTF_LENGTH 1024
70typedef struct qcmbr_data_s {
71 unsigned int cmd;
72 unsigned int length;
73 unsigned char buf[MAX_UTF_LENGTH + 4];
74 unsigned int copy_to_user;
75} qcmbr_data_t;
76typedef struct qcmbr_queue_s {
77 unsigned char utf_buf[MAX_UTF_LENGTH + 4];
78 struct list_head list;
79} qcmbr_queue_t;
80LIST_HEAD(qcmbr_queue_head);
81DEFINE_SPINLOCK(qcmbr_queue_lock);
Mohit Khannafa99aea2016-05-12 21:43:13 -070082static void wlanqcmbr_mc_process_msg(void *message);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080083#endif
84#endif
85
86/**
87 * wlan_ftm_postmsg() - Post FTM message
88 * @cmd_ptr: Pointer to FTM command buffer
89 * @cmd_len: Length of command in @cmd_ptr
90 *
91 * This function is used to send FTM commands to firmware
92 *
93 * Return: 0 for success, non zero for failure
94 */
95static uint32_t wlan_ftm_postmsg(uint8_t *cmd_ptr, uint16_t cmd_len)
96{
97 cds_msg_t ftmMsg;
98
99 ENTER();
100
101 ftmMsg.type = WMA_FTM_CMD_REQ;
102 ftmMsg.reserved = 0;
103 ftmMsg.bodyptr = (uint8_t *) cmd_ptr;
104 ftmMsg.bodyval = 0;
105
Anurag Chouhan6d760662016-02-20 16:05:43 +0530106 if (QDF_STATUS_SUCCESS != cds_mq_post_message(QDF_MODULE_ID_WMA,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800107 &ftmMsg)) {
Jeff Johnson6f917072016-08-05 17:14:35 -0700108 hdd_err("Failed to post Msg to HAL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800109
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530110 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800111 }
112
113 EXIT();
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530114 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800115}
116
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800117/**
Arun Khandavallic811dcc2016-06-26 07:37:21 +0530118 * hdd_update_cds_config_ftm() - API to update cds configuration parameters
119 * for FTM mode.
120 * @hdd_ctx: HDD Context
121 *
122 * Return: 0 on success; errno on failure
123 */
124
125int hdd_update_cds_config_ftm(hdd_context_t *hdd_ctx)
126{
127 struct cds_config_info *cds_cfg;
128
Jeff Johnson9078bdc2016-09-23 17:18:11 -0700129 cds_cfg = qdf_mem_malloc(sizeof(*cds_cfg));
Arun Khandavallic811dcc2016-06-26 07:37:21 +0530130 if (!cds_cfg) {
131 hdd_err("failed to allocate cds config");
132 return -ENOMEM;
133 }
Arun Khandavallic811dcc2016-06-26 07:37:21 +0530134
135 cds_cfg->driver_type = eDRIVER_TYPE_MFG;
136 cds_cfg->powersave_offload_enabled =
137 hdd_ctx->config->enablePowersaveOffload;
Jeff Johnson9078bdc2016-09-23 17:18:11 -0700138 hdd_lpass_populate_cds_config(cds_cfg, hdd_ctx);
Naveen Rawat64e477e2016-05-20 10:34:56 -0700139 cds_cfg->sub_20_channel_width = WLAN_SUB_20_CH_WIDTH_NONE;
Arun Khandavallic811dcc2016-06-26 07:37:21 +0530140 cds_init_ini_config(cds_cfg);
141
142 return 0;
143}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800144
145/**
146 * hdd_ftm_mc_process_msg() - Process FTM mailbox message
147 * @message: FTM response message
148 *
149 * Process FTM mailbox message
150 *
151 * Return: void
152 */
Arun Khandavallifae92942016-08-01 13:31:08 +0530153void hdd_ftm_mc_process_msg(void *message)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800154{
155 void *data;
156 uint32_t data_len;
157
158 if (!message) {
159 hdd_err("Message is NULL, nothing to process.");
160 return;
161 }
162
163 data_len = *((uint32_t *) message);
164 data = (uint32_t *) message + 1;
165
166#if defined(LINUX_QCMBR)
167 wlanqcmbr_mc_process_msg(message);
168#else
169#ifdef CONFIG_NL80211_TESTMODE
170 wlan_hdd_testmode_rx_event(data, (size_t) data_len);
171#endif
172#endif
173 return;
174}
175
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800176#if defined(QCA_WIFI_FTM)
177#if defined(LINUX_QCMBR)
178/**
179 * wlan_hdd_qcmbr_command() - QCMBR command handler
180 * @adapter: adapter upon which the command was received
181 * @pqcmbr_data: QCMBR command
182 *
183 * Return: 0 on success, non-zero on error
184 */
185static int wlan_hdd_qcmbr_command(hdd_adapter_t *adapter,
186 qcmbr_data_t *pqcmbr_data)
187{
188 int ret = 0;
189 qcmbr_queue_t *qcmbr_buf = NULL;
190
191 switch (pqcmbr_data->cmd) {
192 case ATH_XIOCTL_UNIFIED_UTF_CMD: {
193 pqcmbr_data->copy_to_user = 0;
194 if (pqcmbr_data->length) {
195 if (wlan_hdd_ftm_testmode_cmd(pqcmbr_data->buf,
196 pqcmbr_data->
197 length)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530198 != QDF_STATUS_SUCCESS) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800199 ret = -EBUSY;
200 } else {
201 ret = 0;
202 }
203 }
204 }
205 break;
206
207 case ATH_XIOCTL_UNIFIED_UTF_RSP: {
208 pqcmbr_data->copy_to_user = 1;
zding6af26a32016-10-12 15:49:34 +0800209
210 spin_lock_bh(&qcmbr_queue_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800211 if (!list_empty(&qcmbr_queue_head)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800212 qcmbr_buf = list_first_entry(&qcmbr_queue_head,
213 qcmbr_queue_t,
214 list);
215 list_del(&qcmbr_buf->list);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800216 ret = 0;
217 } else {
218 ret = -1;
219 }
zding6af26a32016-10-12 15:49:34 +0800220 spin_unlock_bh(&qcmbr_queue_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800221
222 if (!ret) {
223 memcpy(pqcmbr_data->buf, qcmbr_buf->utf_buf,
224 (MAX_UTF_LENGTH + 4));
225 kfree(qcmbr_buf);
226 } else {
227 ret = -EAGAIN;
228 }
229 }
230 break;
231 }
232
233 return ret;
234}
235
236#ifdef CONFIG_COMPAT
237/**
238 * wlan_hdd_qcmbr_ioctl() - Compatability-mode QCMBR ioctl handler
239 * @adapter: adapter upon which the ioctl was received
240 * @ifr: the ioctl request
241 *
242 * Return: 0 on success, non-zero on error
243 */
244static int wlan_hdd_qcmbr_compat_ioctl(hdd_adapter_t *adapter,
245 struct ifreq *ifr)
246{
247 qcmbr_data_t *qcmbr_data;
248 int ret = 0;
249
250 qcmbr_data = kzalloc(sizeof(qcmbr_data_t), GFP_KERNEL);
251 if (qcmbr_data == NULL)
252 return -ENOMEM;
253
254 if (copy_from_user(qcmbr_data, ifr->ifr_data, sizeof(*qcmbr_data))) {
255 ret = -EFAULT;
256 goto exit;
257 }
258
259 ret = wlan_hdd_qcmbr_command(adapter, qcmbr_data);
zding6af26a32016-10-12 15:49:34 +0800260 if ((ret == 0) && qcmbr_data->copy_to_user) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800261 ret = copy_to_user(ifr->ifr_data, qcmbr_data->buf,
262 (MAX_UTF_LENGTH + 4));
263 }
264
265exit:
266 kfree(qcmbr_data);
267 return ret;
268}
269#else /* CONFIG_COMPAT */
270static int wlan_hdd_qcmbr_compat_ioctl(hdd_adapter_t *adapter,
271 struct ifreq *ifr)
272{
273 return 0;
274}
275#endif /* CONFIG_COMPAT */
276
277/**
278 * wlan_hdd_qcmbr_ioctl() - Standard QCMBR ioctl handler
279 * @adapter: adapter upon which the ioctl was received
280 * @ifr: the ioctl request
281 *
282 * Return: 0 on success, non-zero on error
283 */
284static int wlan_hdd_qcmbr_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
285{
286 qcmbr_data_t *qcmbr_data;
287 int ret = 0;
288
289 qcmbr_data = kzalloc(sizeof(qcmbr_data_t), GFP_KERNEL);
290 if (qcmbr_data == NULL)
291 return -ENOMEM;
292
293 if (copy_from_user(qcmbr_data, ifr->ifr_data, sizeof(*qcmbr_data))) {
294 ret = -EFAULT;
295 goto exit;
296 }
297
298 ret = wlan_hdd_qcmbr_command(adapter, qcmbr_data);
zding6af26a32016-10-12 15:49:34 +0800299 if ((ret == 0) && qcmbr_data->copy_to_user) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800300 ret = copy_to_user(ifr->ifr_data, qcmbr_data->buf,
301 (MAX_UTF_LENGTH + 4));
302 }
303
304exit:
305 kfree(qcmbr_data);
306 return ret;
307}
308
309/**
310 * wlan_hdd_qcmbr_unified_ioctl() - Unified QCMBR ioctl handler
311 * @adapter: adapter upon which the ioctl was received
312 * @ifr: the ioctl request
313 *
314 * Return: 0 on success, non-zero on error
315 */
316int wlan_hdd_qcmbr_unified_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
317{
318 int ret = 0;
319
320 if (is_compat_task()) {
321 ret = wlan_hdd_qcmbr_compat_ioctl(adapter, ifr);
322 } else {
323 ret = wlan_hdd_qcmbr_ioctl(adapter, ifr);
324 }
325
326 return ret;
327}
328
329/**
330 * wlanqcmbr_mc_process_msg() - Process QCMBR response message
331 * @message: QCMBR message
332 *
333 * Return: None
334 */
335static void wlanqcmbr_mc_process_msg(void *message)
336{
337 qcmbr_queue_t *qcmbr_buf = NULL;
338 uint32_t data_len;
339
340 data_len = *((uint32_t *) message) + sizeof(uint32_t);
341 qcmbr_buf = kzalloc(sizeof(qcmbr_queue_t), GFP_KERNEL);
342 if (qcmbr_buf != NULL) {
343 memcpy(qcmbr_buf->utf_buf, message, data_len);
344 spin_lock_bh(&qcmbr_queue_lock);
345 list_add_tail(&(qcmbr_buf->list), &qcmbr_queue_head);
346 spin_unlock_bh(&qcmbr_queue_lock);
347 }
348}
349#endif /*LINUX_QCMBR */
350
351/**
352 * wlan_hdd_ftm_testmode_cmd() - Process FTM testmode command
353 * @data: FTM testmode command
354 * @len: length of @data
355 *
Anurag Chouhanf04e84f2016-03-03 10:12:12 +0530356 * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800357 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530358QDF_STATUS wlan_hdd_ftm_testmode_cmd(void *data, int len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800359{
360 struct ar6k_testmode_cmd_data *cmd_data;
361
362 cmd_data = (struct ar6k_testmode_cmd_data *)
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530363 qdf_mem_malloc(sizeof(*cmd_data));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800364
365 if (!cmd_data) {
Jeff Johnson6f917072016-08-05 17:14:35 -0700366 hdd_err("Failed to allocate FTM command data");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530367 return QDF_STATUS_E_NOMEM;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800368 }
369
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530370 cmd_data->data = qdf_mem_malloc(len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800371
372 if (!cmd_data->data) {
Jeff Johnson6f917072016-08-05 17:14:35 -0700373 hdd_err("Failed to allocate FTM command data buffer");
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530374 qdf_mem_free(cmd_data);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530375 return QDF_STATUS_E_NOMEM;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800376 }
377
378 cmd_data->len = len;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530379 qdf_mem_copy(cmd_data->data, data, len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800380
381 if (wlan_ftm_postmsg((uint8_t *) cmd_data, sizeof(*cmd_data))) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530382 qdf_mem_free(cmd_data->data);
383 qdf_mem_free(cmd_data);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530384 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800385 }
386
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530387 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800388}
389#endif /*QCA_WIFI_FTM */