blob: da03cf0548caa592e052d2403cba59f50558c229 [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Prashanth Bhatta98f04d22016-01-08 16:46:21 -08002 * Copyright (c) 2012-2016 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);
Arun Khandavallic811dcc2016-06-26 07:37:21 +0530139 /* UMA is supported in hardware for performing the
140 * frame translation 802.11 <-> 802.3
141 */
142 cds_cfg->frame_xln_reqd = 1;
Naveen Rawat64e477e2016-05-20 10:34:56 -0700143 cds_cfg->sub_20_channel_width = WLAN_SUB_20_CH_WIDTH_NONE;
Arun Khandavallic811dcc2016-06-26 07:37:21 +0530144 cds_init_ini_config(cds_cfg);
145
146 return 0;
147}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800148
149/**
150 * hdd_ftm_mc_process_msg() - Process FTM mailbox message
151 * @message: FTM response message
152 *
153 * Process FTM mailbox message
154 *
155 * Return: void
156 */
Arun Khandavallifae92942016-08-01 13:31:08 +0530157void hdd_ftm_mc_process_msg(void *message)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800158{
159 void *data;
160 uint32_t data_len;
161
162 if (!message) {
163 hdd_err("Message is NULL, nothing to process.");
164 return;
165 }
166
167 data_len = *((uint32_t *) message);
168 data = (uint32_t *) message + 1;
169
170#if defined(LINUX_QCMBR)
171 wlanqcmbr_mc_process_msg(message);
172#else
173#ifdef CONFIG_NL80211_TESTMODE
174 wlan_hdd_testmode_rx_event(data, (size_t) data_len);
175#endif
176#endif
177 return;
178}
179
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800180#if defined(QCA_WIFI_FTM)
181#if defined(LINUX_QCMBR)
182/**
183 * wlan_hdd_qcmbr_command() - QCMBR command handler
184 * @adapter: adapter upon which the command was received
185 * @pqcmbr_data: QCMBR command
186 *
187 * Return: 0 on success, non-zero on error
188 */
189static int wlan_hdd_qcmbr_command(hdd_adapter_t *adapter,
190 qcmbr_data_t *pqcmbr_data)
191{
192 int ret = 0;
193 qcmbr_queue_t *qcmbr_buf = NULL;
194
195 switch (pqcmbr_data->cmd) {
196 case ATH_XIOCTL_UNIFIED_UTF_CMD: {
197 pqcmbr_data->copy_to_user = 0;
198 if (pqcmbr_data->length) {
199 if (wlan_hdd_ftm_testmode_cmd(pqcmbr_data->buf,
200 pqcmbr_data->
201 length)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530202 != QDF_STATUS_SUCCESS) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800203 ret = -EBUSY;
204 } else {
205 ret = 0;
206 }
207 }
208 }
209 break;
210
211 case ATH_XIOCTL_UNIFIED_UTF_RSP: {
212 pqcmbr_data->copy_to_user = 1;
213 if (!list_empty(&qcmbr_queue_head)) {
214 spin_lock_bh(&qcmbr_queue_lock);
215 qcmbr_buf = list_first_entry(&qcmbr_queue_head,
216 qcmbr_queue_t,
217 list);
218 list_del(&qcmbr_buf->list);
219 spin_unlock_bh(&qcmbr_queue_lock);
220 ret = 0;
221 } else {
222 ret = -1;
223 }
224
225 if (!ret) {
226 memcpy(pqcmbr_data->buf, qcmbr_buf->utf_buf,
227 (MAX_UTF_LENGTH + 4));
228 kfree(qcmbr_buf);
229 } else {
230 ret = -EAGAIN;
231 }
232 }
233 break;
234 }
235
236 return ret;
237}
238
239#ifdef CONFIG_COMPAT
240/**
241 * wlan_hdd_qcmbr_ioctl() - Compatability-mode QCMBR ioctl handler
242 * @adapter: adapter upon which the ioctl was received
243 * @ifr: the ioctl request
244 *
245 * Return: 0 on success, non-zero on error
246 */
247static int wlan_hdd_qcmbr_compat_ioctl(hdd_adapter_t *adapter,
248 struct ifreq *ifr)
249{
250 qcmbr_data_t *qcmbr_data;
251 int ret = 0;
252
253 qcmbr_data = kzalloc(sizeof(qcmbr_data_t), GFP_KERNEL);
254 if (qcmbr_data == NULL)
255 return -ENOMEM;
256
257 if (copy_from_user(qcmbr_data, ifr->ifr_data, sizeof(*qcmbr_data))) {
258 ret = -EFAULT;
259 goto exit;
260 }
261
262 ret = wlan_hdd_qcmbr_command(adapter, qcmbr_data);
263 if (qcmbr_data->copy_to_user) {
264 ret = copy_to_user(ifr->ifr_data, qcmbr_data->buf,
265 (MAX_UTF_LENGTH + 4));
266 }
267
268exit:
269 kfree(qcmbr_data);
270 return ret;
271}
272#else /* CONFIG_COMPAT */
273static int wlan_hdd_qcmbr_compat_ioctl(hdd_adapter_t *adapter,
274 struct ifreq *ifr)
275{
276 return 0;
277}
278#endif /* CONFIG_COMPAT */
279
280/**
281 * wlan_hdd_qcmbr_ioctl() - Standard QCMBR ioctl handler
282 * @adapter: adapter upon which the ioctl was received
283 * @ifr: the ioctl request
284 *
285 * Return: 0 on success, non-zero on error
286 */
287static int wlan_hdd_qcmbr_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
288{
289 qcmbr_data_t *qcmbr_data;
290 int ret = 0;
291
292 qcmbr_data = kzalloc(sizeof(qcmbr_data_t), GFP_KERNEL);
293 if (qcmbr_data == NULL)
294 return -ENOMEM;
295
296 if (copy_from_user(qcmbr_data, ifr->ifr_data, sizeof(*qcmbr_data))) {
297 ret = -EFAULT;
298 goto exit;
299 }
300
301 ret = wlan_hdd_qcmbr_command(adapter, qcmbr_data);
302 if (qcmbr_data->copy_to_user) {
303 ret = copy_to_user(ifr->ifr_data, qcmbr_data->buf,
304 (MAX_UTF_LENGTH + 4));
305 }
306
307exit:
308 kfree(qcmbr_data);
309 return ret;
310}
311
312/**
313 * wlan_hdd_qcmbr_unified_ioctl() - Unified QCMBR ioctl handler
314 * @adapter: adapter upon which the ioctl was received
315 * @ifr: the ioctl request
316 *
317 * Return: 0 on success, non-zero on error
318 */
319int wlan_hdd_qcmbr_unified_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
320{
321 int ret = 0;
322
323 if (is_compat_task()) {
324 ret = wlan_hdd_qcmbr_compat_ioctl(adapter, ifr);
325 } else {
326 ret = wlan_hdd_qcmbr_ioctl(adapter, ifr);
327 }
328
329 return ret;
330}
331
332/**
333 * wlanqcmbr_mc_process_msg() - Process QCMBR response message
334 * @message: QCMBR message
335 *
336 * Return: None
337 */
338static void wlanqcmbr_mc_process_msg(void *message)
339{
340 qcmbr_queue_t *qcmbr_buf = NULL;
341 uint32_t data_len;
342
343 data_len = *((uint32_t *) message) + sizeof(uint32_t);
344 qcmbr_buf = kzalloc(sizeof(qcmbr_queue_t), GFP_KERNEL);
345 if (qcmbr_buf != NULL) {
346 memcpy(qcmbr_buf->utf_buf, message, data_len);
347 spin_lock_bh(&qcmbr_queue_lock);
348 list_add_tail(&(qcmbr_buf->list), &qcmbr_queue_head);
349 spin_unlock_bh(&qcmbr_queue_lock);
350 }
351}
352#endif /*LINUX_QCMBR */
353
354/**
355 * wlan_hdd_ftm_testmode_cmd() - Process FTM testmode command
356 * @data: FTM testmode command
357 * @len: length of @data
358 *
Anurag Chouhanf04e84f2016-03-03 10:12:12 +0530359 * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800360 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530361QDF_STATUS wlan_hdd_ftm_testmode_cmd(void *data, int len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800362{
363 struct ar6k_testmode_cmd_data *cmd_data;
364
365 cmd_data = (struct ar6k_testmode_cmd_data *)
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530366 qdf_mem_malloc(sizeof(*cmd_data));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800367
368 if (!cmd_data) {
Jeff Johnson6f917072016-08-05 17:14:35 -0700369 hdd_err("Failed to allocate FTM command data");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530370 return QDF_STATUS_E_NOMEM;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800371 }
372
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530373 cmd_data->data = qdf_mem_malloc(len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800374
375 if (!cmd_data->data) {
Jeff Johnson6f917072016-08-05 17:14:35 -0700376 hdd_err("Failed to allocate FTM command data buffer");
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530377 qdf_mem_free(cmd_data);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530378 return QDF_STATUS_E_NOMEM;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800379 }
380
381 cmd_data->len = len;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530382 qdf_mem_copy(cmd_data->data, data, len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800383
384 if (wlan_ftm_postmsg((uint8_t *) cmd_data, sizeof(*cmd_data))) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530385 qdf_mem_free(cmd_data->data);
386 qdf_mem_free(cmd_data);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530387 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800388 }
389
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530390 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800391}
392#endif /*QCA_WIFI_FTM */