blob: 9e76f0e8772d7c7ec54e7925e0155c04749e066d [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
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080034#include "cds_sched.h"
35#include <cds_api.h>
36#include "sir_types.h"
Anurag Chouhan6d760662016-02-20 16:05:43 +053037#include "qdf_types.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080038#include "sir_api.h"
39#include "sir_mac_prot_def.h"
40#include "sme_api.h"
41#include "mac_init_api.h"
42#include "wlan_qct_sys.h"
43#include "wlan_hdd_misc.h"
44#include "i_cds_packet.h"
45#include "cds_reg_service.h"
46#include "wlan_hdd_main.h"
Jeff Johnson9078bdc2016-09-23 17:18:11 -070047#include "wlan_hdd_lpass.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080048#include "qwlan_version.h"
49#include "wma_types.h"
50#include "cfg_api.h"
51
52#if defined(QCA_WIFI_FTM)
53#include "bmi.h"
54#include "ol_fw.h"
55#include "wlan_hdd_cfg80211.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080056#include "hif.h"
57#endif
58
59#define HDD_FTM_WMA_PRE_START_TIMEOUT (30000) /* 30 seconds */
60
61#if defined(QCA_WIFI_FTM)
62#if defined(LINUX_QCMBR)
63#define ATH_XIOCTL_UNIFIED_UTF_CMD 0x1000
64#define ATH_XIOCTL_UNIFIED_UTF_RSP 0x1001
65#define MAX_UTF_LENGTH 1024
Jeff Johnsone0e77452017-08-21 14:59:12 -070066struct qcmbr_data {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080067 unsigned int cmd;
68 unsigned int length;
69 unsigned char buf[MAX_UTF_LENGTH + 4];
70 unsigned int copy_to_user;
Jeff Johnsone0e77452017-08-21 14:59:12 -070071};
72struct qcmbr_queue {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080073 unsigned char utf_buf[MAX_UTF_LENGTH + 4];
74 struct list_head list;
Jeff Johnsone0e77452017-08-21 14:59:12 -070075};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080076LIST_HEAD(qcmbr_queue_head);
77DEFINE_SPINLOCK(qcmbr_queue_lock);
Mohit Khannafa99aea2016-05-12 21:43:13 -070078static void wlanqcmbr_mc_process_msg(void *message);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080079#endif
80#endif
81
82/**
83 * wlan_ftm_postmsg() - Post FTM message
84 * @cmd_ptr: Pointer to FTM command buffer
85 * @cmd_len: Length of command in @cmd_ptr
86 *
87 * This function is used to send FTM commands to firmware
88 *
89 * Return: 0 for success, non zero for failure
90 */
91static uint32_t wlan_ftm_postmsg(uint8_t *cmd_ptr, uint16_t cmd_len)
92{
Rajeev Kumarcf7bd802017-04-18 11:11:42 -070093 struct scheduler_msg ftmMsg = {0};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080094
95 ENTER();
96
97 ftmMsg.type = WMA_FTM_CMD_REQ;
98 ftmMsg.reserved = 0;
99 ftmMsg.bodyptr = (uint8_t *) cmd_ptr;
100 ftmMsg.bodyval = 0;
101
Rajeev Kumarea95edd2017-01-11 20:49:36 -0800102 if (QDF_STATUS_SUCCESS != scheduler_post_msg(QDF_MODULE_ID_WMA,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800103 &ftmMsg)) {
Jeff Johnson6f917072016-08-05 17:14:35 -0700104 hdd_err("Failed to post Msg to HAL");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530105 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800106 }
107
108 EXIT();
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530109 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800110}
111
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800112/**
Arun Khandavallic811dcc2016-06-26 07:37:21 +0530113 * hdd_update_cds_config_ftm() - API to update cds configuration parameters
114 * for FTM mode.
115 * @hdd_ctx: HDD Context
116 *
117 * Return: 0 on success; errno on failure
118 */
119
Jeff Johnson2b59af62017-08-28 12:01:18 -0700120int hdd_update_cds_config_ftm(struct hdd_context *hdd_ctx)
Arun Khandavallic811dcc2016-06-26 07:37:21 +0530121{
122 struct cds_config_info *cds_cfg;
123
Jeff Johnson9078bdc2016-09-23 17:18:11 -0700124 cds_cfg = qdf_mem_malloc(sizeof(*cds_cfg));
Arun Khandavallic811dcc2016-06-26 07:37:21 +0530125 if (!cds_cfg) {
126 hdd_err("failed to allocate cds config");
127 return -ENOMEM;
128 }
Arun Khandavallic811dcc2016-06-26 07:37:21 +0530129
Srinivas Girigowda35b00312017-06-27 21:52:03 -0700130 cds_cfg->driver_type = QDF_DRIVER_TYPE_MFG;
Arun Khandavallic811dcc2016-06-26 07:37:21 +0530131 cds_cfg->powersave_offload_enabled =
132 hdd_ctx->config->enablePowersaveOffload;
Jeff Johnson9078bdc2016-09-23 17:18:11 -0700133 hdd_lpass_populate_cds_config(cds_cfg, hdd_ctx);
Naveen Rawat64e477e2016-05-20 10:34:56 -0700134 cds_cfg->sub_20_channel_width = WLAN_SUB_20_CH_WIDTH_NONE;
Arun Khandavallic811dcc2016-06-26 07:37:21 +0530135 cds_init_ini_config(cds_cfg);
136
137 return 0;
138}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800139
140/**
141 * hdd_ftm_mc_process_msg() - Process FTM mailbox message
142 * @message: FTM response message
143 *
144 * Process FTM mailbox message
145 *
146 * Return: void
147 */
Arun Khandavallifae92942016-08-01 13:31:08 +0530148void hdd_ftm_mc_process_msg(void *message)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800149{
150 void *data;
151 uint32_t data_len;
152
153 if (!message) {
Srinivas Girigowda650e7ba2017-03-06 16:34:47 -0800154 hdd_debug("Message is NULL, nothing to process");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800155 return;
156 }
157
158 data_len = *((uint32_t *) message);
159 data = (uint32_t *) message + 1;
160
161#if defined(LINUX_QCMBR)
162 wlanqcmbr_mc_process_msg(message);
163#else
164#ifdef CONFIG_NL80211_TESTMODE
165 wlan_hdd_testmode_rx_event(data, (size_t) data_len);
166#endif
167#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800168}
169
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800170#if defined(QCA_WIFI_FTM)
171#if defined(LINUX_QCMBR)
172/**
173 * wlan_hdd_qcmbr_command() - QCMBR command handler
174 * @adapter: adapter upon which the command was received
175 * @pqcmbr_data: QCMBR command
176 *
177 * Return: 0 on success, non-zero on error
178 */
Jeff Johnsona5dc3f42017-08-29 14:34:33 -0700179static int wlan_hdd_qcmbr_command(struct hdd_adapter *adapter,
Jeff Johnsone0e77452017-08-21 14:59:12 -0700180 struct qcmbr_data *pqcmbr_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800181{
182 int ret = 0;
Jeff Johnsone0e77452017-08-21 14:59:12 -0700183 struct qcmbr_queue *qcmbr_buf = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800184
185 switch (pqcmbr_data->cmd) {
186 case ATH_XIOCTL_UNIFIED_UTF_CMD: {
187 pqcmbr_data->copy_to_user = 0;
Ashish Kumar Dhanotiya41a5a772017-07-13 12:42:20 +0530188 if (pqcmbr_data->length &&
189 pqcmbr_data->length <= sizeof(pqcmbr_data->buf)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800190 if (wlan_hdd_ftm_testmode_cmd(pqcmbr_data->buf,
191 pqcmbr_data->
192 length)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530193 != QDF_STATUS_SUCCESS) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800194 ret = -EBUSY;
195 } else {
196 ret = 0;
197 }
198 }
199 }
200 break;
201
202 case ATH_XIOCTL_UNIFIED_UTF_RSP: {
203 pqcmbr_data->copy_to_user = 1;
zding6af26a32016-10-12 15:49:34 +0800204
205 spin_lock_bh(&qcmbr_queue_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800206 if (!list_empty(&qcmbr_queue_head)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800207 qcmbr_buf = list_first_entry(&qcmbr_queue_head,
Jeff Johnsone0e77452017-08-21 14:59:12 -0700208 struct qcmbr_queue,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800209 list);
210 list_del(&qcmbr_buf->list);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800211 ret = 0;
212 } else {
213 ret = -1;
214 }
zding6af26a32016-10-12 15:49:34 +0800215 spin_unlock_bh(&qcmbr_queue_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800216
217 if (!ret) {
218 memcpy(pqcmbr_data->buf, qcmbr_buf->utf_buf,
219 (MAX_UTF_LENGTH + 4));
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -0700220 qdf_mem_free(qcmbr_buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800221 } else {
222 ret = -EAGAIN;
223 }
224 }
225 break;
226 }
227
228 return ret;
229}
230
231#ifdef CONFIG_COMPAT
232/**
233 * wlan_hdd_qcmbr_ioctl() - Compatability-mode QCMBR ioctl handler
234 * @adapter: adapter upon which the ioctl was received
235 * @ifr: the ioctl request
236 *
237 * Return: 0 on success, non-zero on error
238 */
Jeff Johnsona5dc3f42017-08-29 14:34:33 -0700239static int wlan_hdd_qcmbr_compat_ioctl(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800240 struct ifreq *ifr)
241{
Jeff Johnsone0e77452017-08-21 14:59:12 -0700242 struct qcmbr_data *qcmbr_data;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800243 int ret = 0;
244
Jeff Johnsone0e77452017-08-21 14:59:12 -0700245 qcmbr_data = qdf_mem_malloc(sizeof(*qcmbr_data));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800246 if (qcmbr_data == NULL)
247 return -ENOMEM;
248
249 if (copy_from_user(qcmbr_data, ifr->ifr_data, sizeof(*qcmbr_data))) {
250 ret = -EFAULT;
251 goto exit;
252 }
253
254 ret = wlan_hdd_qcmbr_command(adapter, qcmbr_data);
zding6af26a32016-10-12 15:49:34 +0800255 if ((ret == 0) && qcmbr_data->copy_to_user) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800256 ret = copy_to_user(ifr->ifr_data, qcmbr_data->buf,
257 (MAX_UTF_LENGTH + 4));
258 }
259
260exit:
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -0700261 qdf_mem_free(qcmbr_data);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800262 return ret;
263}
264#else /* CONFIG_COMPAT */
Jeff Johnsona5dc3f42017-08-29 14:34:33 -0700265static int wlan_hdd_qcmbr_compat_ioctl(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800266 struct ifreq *ifr)
267{
268 return 0;
269}
270#endif /* CONFIG_COMPAT */
271
272/**
273 * wlan_hdd_qcmbr_ioctl() - Standard QCMBR ioctl handler
274 * @adapter: adapter upon which the ioctl was received
275 * @ifr: the ioctl request
276 *
277 * Return: 0 on success, non-zero on error
278 */
Jeff Johnsona5dc3f42017-08-29 14:34:33 -0700279static int wlan_hdd_qcmbr_ioctl(struct hdd_adapter *adapter, struct ifreq *ifr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800280{
Jeff Johnsone0e77452017-08-21 14:59:12 -0700281 struct qcmbr_data *qcmbr_data;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800282 int ret = 0;
283
Jeff Johnsone0e77452017-08-21 14:59:12 -0700284 qcmbr_data = qdf_mem_malloc(sizeof(*qcmbr_data));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800285 if (qcmbr_data == NULL)
286 return -ENOMEM;
287
288 if (copy_from_user(qcmbr_data, ifr->ifr_data, sizeof(*qcmbr_data))) {
289 ret = -EFAULT;
290 goto exit;
291 }
292
293 ret = wlan_hdd_qcmbr_command(adapter, qcmbr_data);
zding6af26a32016-10-12 15:49:34 +0800294 if ((ret == 0) && qcmbr_data->copy_to_user) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800295 ret = copy_to_user(ifr->ifr_data, qcmbr_data->buf,
296 (MAX_UTF_LENGTH + 4));
297 }
298
299exit:
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -0700300 qdf_mem_free(qcmbr_data);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800301 return ret;
302}
303
304/**
305 * wlan_hdd_qcmbr_unified_ioctl() - Unified QCMBR ioctl handler
306 * @adapter: adapter upon which the ioctl was received
307 * @ifr: the ioctl request
308 *
309 * Return: 0 on success, non-zero on error
310 */
Jeff Johnsona5dc3f42017-08-29 14:34:33 -0700311int wlan_hdd_qcmbr_unified_ioctl(struct hdd_adapter *adapter, struct ifreq *ifr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800312{
313 int ret = 0;
314
Srinivas Girigowda576b2352017-08-25 14:44:26 -0700315 if (is_compat_task())
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800316 ret = wlan_hdd_qcmbr_compat_ioctl(adapter, ifr);
Srinivas Girigowda576b2352017-08-25 14:44:26 -0700317 else
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800318 ret = wlan_hdd_qcmbr_ioctl(adapter, ifr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800319
320 return ret;
321}
322
323/**
324 * wlanqcmbr_mc_process_msg() - Process QCMBR response message
325 * @message: QCMBR message
326 *
327 * Return: None
328 */
329static void wlanqcmbr_mc_process_msg(void *message)
330{
Jeff Johnsone0e77452017-08-21 14:59:12 -0700331 struct qcmbr_queue *qcmbr_buf = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800332 uint32_t data_len;
333
334 data_len = *((uint32_t *) message) + sizeof(uint32_t);
Jeff Johnsone0e77452017-08-21 14:59:12 -0700335 qcmbr_buf = qdf_mem_malloc(sizeof(*qcmbr_buf));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800336 if (qcmbr_buf != NULL) {
337 memcpy(qcmbr_buf->utf_buf, message, data_len);
338 spin_lock_bh(&qcmbr_queue_lock);
339 list_add_tail(&(qcmbr_buf->list), &qcmbr_queue_head);
340 spin_unlock_bh(&qcmbr_queue_lock);
341 }
342}
343#endif /*LINUX_QCMBR */
344
345/**
346 * wlan_hdd_ftm_testmode_cmd() - Process FTM testmode command
347 * @data: FTM testmode command
348 * @len: length of @data
349 *
Anurag Chouhanf04e84f2016-03-03 10:12:12 +0530350 * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800351 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530352QDF_STATUS wlan_hdd_ftm_testmode_cmd(void *data, int len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800353{
354 struct ar6k_testmode_cmd_data *cmd_data;
355
356 cmd_data = (struct ar6k_testmode_cmd_data *)
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530357 qdf_mem_malloc(sizeof(*cmd_data));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800358
359 if (!cmd_data) {
Jeff Johnson6f917072016-08-05 17:14:35 -0700360 hdd_err("Failed to allocate FTM command data");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530361 return QDF_STATUS_E_NOMEM;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800362 }
363
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530364 cmd_data->data = qdf_mem_malloc(len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800365
366 if (!cmd_data->data) {
Jeff Johnson6f917072016-08-05 17:14:35 -0700367 hdd_err("Failed to allocate FTM command data buffer");
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530368 qdf_mem_free(cmd_data);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530369 return QDF_STATUS_E_NOMEM;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800370 }
371
372 cmd_data->len = len;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530373 qdf_mem_copy(cmd_data->data, data, len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800374
375 if (wlan_ftm_postmsg((uint8_t *) cmd_data, sizeof(*cmd_data))) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530376 qdf_mem_free(cmd_data->data);
377 qdf_mem_free(cmd_data);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530378 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800379 }
380
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530381 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800382}
383#endif /*QCA_WIFI_FTM */