blob: cb6b23a34c3bf43765c52ceaa17329b5d7a1225e [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Rajeev Kumarea95edd2017-01-11 20:49:36 -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/* Include Files */
29
30#include <wlan_hdd_includes.h>
31#include <wlan_hdd_wowl.h>
32#include "wlan_hdd_trace.h"
33#include "wlan_hdd_ioctl.h"
34#include "wlan_hdd_power.h"
Jeff Johnson253c0c22017-01-23 16:59:38 -080035#include "wlan_hdd_request_manager.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080036#include "wlan_hdd_driver_ops.h"
Tushnim Bhattacharyyade1070d2017-03-09 13:23:55 -080037#include "wlan_policy_mgr_api.h"
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +053038#include "wlan_hdd_hostapd.h"
Rajeev Kumarea95edd2017-01-11 20:49:36 -080039#include "scheduler_api.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080040
41#include "wlan_hdd_p2p.h"
42#include <linux/ctype.h>
43#include "wma.h"
44#include "wlan_hdd_napi.h"
45
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -080046#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080047#include <sme_api.h>
48#include <sir_api.h>
49#endif
50#include "hif.h"
51
52#if defined(LINUX_QCMBR)
53#define SIOCIOCTLTX99 (SIOCDEVPRIVATE+13)
54#endif
55
56/*
57 * Size of Driver command strings from upper layer
58 */
59#define SIZE_OF_SETROAMMODE 11 /* size of SETROAMMODE */
60#define SIZE_OF_GETROAMMODE 11 /* size of GETROAMMODE */
61
Rajeev Kumar8e3e2832015-11-06 16:02:54 -080062/*
63 * Ibss prop IE from command will be of size:
64 * size = sizeof(oui) + sizeof(oui_data) + 1(Element ID) + 1(EID Length)
65 * OUI_DATA should be at least 3 bytes long
66 */
67#define WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH (3)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080068
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -080069#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080070#define TID_MIN_VALUE 0
71#define TID_MAX_VALUE 15
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -080072#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080073
74/*
75 * Maximum buffer size used for returning the data back to user space
76 */
77#define WLAN_MAX_BUF_SIZE 1024
78#define WLAN_PRIV_DATA_MAX_LEN 8192
79
80/*
81 * Driver miracast parameters 0-Disabled
82 * 1-Source, 2-Sink
83 */
84#define WLAN_HDD_DRIVER_MIRACAST_CFG_MIN_VAL 0
85#define WLAN_HDD_DRIVER_MIRACAST_CFG_MAX_VAL 2
86
87/*
88 * When ever we need to print IBSSPEERINFOALL for more than 16 STA
89 * we will split the printing.
90 */
91#define NUM_OF_STA_DATA_TO_PRINT 16
92
93/*
94 * Android DRIVER command structures
95 */
96struct android_wifi_reassoc_params {
97 unsigned char bssid[18];
98 int channel;
99};
100
101#define ANDROID_WIFI_ACTION_FRAME_SIZE 1040
102struct android_wifi_af_params {
103 unsigned char bssid[18];
104 int channel;
105 int dwell_time;
106 int len;
107 unsigned char data[ANDROID_WIFI_ACTION_FRAME_SIZE];
108};
109
110/*
111 * Define HDD driver command handling entry, each contains a command
112 * string and the handler.
113 */
114typedef int (*hdd_drv_cmd_handler_t)(hdd_adapter_t *adapter,
115 hdd_context_t *hdd_ctx,
116 uint8_t *cmd,
117 uint8_t cmd_name_len,
118 hdd_priv_data_t *priv_data);
119
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700120struct hdd_drv_cmd {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800121 const char *cmd;
122 hdd_drv_cmd_handler_t handler;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700123};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800124
125#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
126#define WLAN_WAIT_TIME_READY_TO_EXTWOW 2000
127#define WLAN_HDD_MAX_TCP_PORT 65535
128#endif
129
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800130static uint16_t cesium_pid;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800131
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -0800132#ifdef FEATURE_WLAN_ESE
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800133struct tsm_priv {
134 tAniTrafStrmMetrics tsm_metrics;
135};
136
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800137static void hdd_get_tsm_stats_cb(tAniTrafStrmMetrics tsm_metrics,
138 const uint32_t staId, void *context)
139{
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800140 struct hdd_request *request;
141 struct tsm_priv *priv;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800142
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800143 request = hdd_request_get(context);
144 if (!request) {
145 hdd_err("Obsolete request");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800146 return;
147 }
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800148 priv = hdd_request_priv(request);
149 priv->tsm_metrics = tsm_metrics;
150 hdd_request_complete(request);
151 hdd_request_put(request);
152 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800153
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800154}
155
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800156static int hdd_get_tsm_stats(hdd_adapter_t *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800157 const uint8_t tid,
158 tAniTrafStrmMetrics *tsm_metrics)
159{
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800160 hdd_context_t *hdd_ctx;
161 hdd_station_ctx_t *hdd_sta_ctx;
162 QDF_STATUS status;
163 int ret;
164 void *cookie;
165 struct hdd_request *request;
166 struct tsm_priv *priv;
167 static const struct hdd_request_params params = {
168 .priv_size = sizeof(*priv),
169 .timeout_ms = WLAN_WAIT_TIME_STATS,
170 };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800171
172 if (NULL == adapter) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700173 hdd_err("adapter is NULL");
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800174 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800175 }
176
177 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
178 hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
179
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800180 request = hdd_request_alloc(&params);
181 if (!request) {
182 hdd_err("Request allocation failure");
183 return -ENOMEM;
184 }
185 cookie = hdd_request_cookie(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800186
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800187 status = sme_get_tsm_stats(hdd_ctx->hHal, hdd_get_tsm_stats_cb,
188 hdd_sta_ctx->conn_info.staId[0],
189 hdd_sta_ctx->conn_info.bssId,
190 cookie, hdd_ctx->pcds_context, tid);
191 if (QDF_STATUS_SUCCESS != status) {
192 hdd_err("Unable to retrieve tsm statistics");
193 ret = qdf_status_to_os_return(status);
194 goto cleanup;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800195 }
196
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800197 ret = hdd_request_wait_for_response(request);
198 if (ret) {
199 hdd_err("SME timed out while retrieving tsm statistics");
200 goto cleanup;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800201 }
Jeff Johnsonc13bdf12017-01-25 16:28:19 -0800202
203 priv = hdd_request_priv(request);
204 *tsm_metrics = priv->tsm_metrics;
205
206 cleanup:
207 hdd_request_put(request);
208
209 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800210}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -0800211#endif /*FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800212
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800213/* Function header is left blank intentionally */
214static int hdd_parse_setrmcenable_command(uint8_t *pValue,
215 uint8_t *pRmcEnable)
216{
217 uint8_t *inPtr = pValue;
218 int tempInt;
219 int v = 0;
220 char buf[32];
221 *pRmcEnable = 0;
222
223 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
224
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700225 if (NULL == inPtr)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800226 return 0;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700227 else if (SPACE_ASCII_VALUE != *inPtr)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800228 return 0;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800229
230 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
231 inPtr++;
232
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700233 if ('\0' == *inPtr)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800234 return 0;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800235
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700236 v = sscanf(inPtr, "%32s ", buf);
237 if (1 != v)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800238 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700239
240 v = kstrtos32(buf, 10, &tempInt);
241 if (v < 0)
242 return -EINVAL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800243
244 *pRmcEnable = tempInt;
245
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800246 hdd_debug("ucRmcEnable: %d", *pRmcEnable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800247
248 return 0;
249}
250
251/* Function header is left blank intentionally */
252static int hdd_parse_setrmcactionperiod_command(uint8_t *pValue,
253 uint32_t *pActionPeriod)
254{
255 uint8_t *inPtr = pValue;
256 int tempInt;
257 int v = 0;
258 char buf[32];
259 *pActionPeriod = 0;
260
261 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
262
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700263 if (NULL == inPtr)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800264 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700265 else if (SPACE_ASCII_VALUE != *inPtr)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800266 return -EINVAL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800267
268 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
269 inPtr++;
270
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700271 if ('\0' == *inPtr)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800272 return 0;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800273
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700274 v = sscanf(inPtr, "%32s ", buf);
275 if (1 != v)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800276 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700277
278 v = kstrtos32(buf, 10, &tempInt);
279 if (v < 0)
280 return -EINVAL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800281
282 if ((tempInt < WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STAMIN) ||
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700283 (tempInt > WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STAMAX))
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800284 return -EINVAL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800285
286 *pActionPeriod = tempInt;
287
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800288 hdd_debug("uActionPeriod: %d", *pActionPeriod);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800289
290 return 0;
291}
292
293/* Function header is left blank intentionally */
294static int hdd_parse_setrmcrate_command(uint8_t *pValue,
295 uint32_t *pRate,
296 tTxrateinfoflags *pTxFlags)
297{
298 uint8_t *inPtr = pValue;
299 int tempInt;
300 int v = 0;
301 char buf[32];
302 *pRate = 0;
303 *pTxFlags = 0;
304
305 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
306
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700307 if (NULL == inPtr)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800308 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700309 else if (SPACE_ASCII_VALUE != *inPtr)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800310 return -EINVAL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800311
312 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
313 inPtr++;
314
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700315 if ('\0' == *inPtr)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800316 return 0;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800317
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700318 v = sscanf(inPtr, "%32s ", buf);
319 if (1 != v)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800320 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700321
322 v = kstrtos32(buf, 10, &tempInt);
323 if (v < 0)
324 return -EINVAL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800325
326 switch (tempInt) {
327 default:
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700328 hdd_warn("Unsupported rate: %d", tempInt);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800329 return -EINVAL;
330 case 0:
331 case 6:
332 case 9:
333 case 12:
334 case 18:
335 case 24:
336 case 36:
337 case 48:
338 case 54:
339 *pTxFlags = eHAL_TX_RATE_LEGACY;
340 *pRate = tempInt * 10;
341 break;
342 case 65:
343 *pTxFlags = eHAL_TX_RATE_HT20;
344 *pRate = tempInt * 10;
345 break;
346 case 72:
347 *pTxFlags = eHAL_TX_RATE_HT20 | eHAL_TX_RATE_SGI;
348 *pRate = 722;
349 break;
350 }
351
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800352 hdd_debug("Rate: %d", *pRate);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800353
354 return 0;
355}
356
357/**
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700358 * hdd_get_ibss_peer_info_cb() - IBSS peer Info request callback
359 * @UserData: Adapter private data
360 * @pPeerInfoRsp: Peer info response
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800361 *
362 * This is an asynchronous callback function from SME when the peer info
363 * is received
364 *
365 * Return: 0 for success non-zero for failure
366 */
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700367void
368hdd_get_ibss_peer_info_cb(void *pUserData,
369 tSirPeerInfoRspParams *pPeerInfo)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800370{
371 hdd_adapter_t *adapter = (hdd_adapter_t *) pUserData;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800372 hdd_station_ctx_t *pStaCtx;
373 uint8_t i;
374
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800375 if ((NULL == adapter) ||
376 (WLAN_HDD_ADAPTER_MAGIC != adapter->magic)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800377 hdd_err("invalid adapter or adapter has invalid magic");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800378 return;
379 }
380
381 pStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
382 if (NULL != pPeerInfo && QDF_STATUS_SUCCESS == pPeerInfo->status) {
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700383 /* validate number of peers */
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530384 if (pPeerInfo->numPeers > SIR_MAX_NUM_STA_IN_IBSS) {
385 hdd_warn("Limiting num_peers %u to %u",
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700386 pPeerInfo->numPeers, SIR_MAX_NUM_STA_IN_IBSS);
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530387 pPeerInfo->numPeers = SIR_MAX_NUM_STA_IN_IBSS;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800388 }
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530389 pStaCtx->ibss_peer_info.status = pPeerInfo->status;
390 pStaCtx->ibss_peer_info.numPeers = pPeerInfo->numPeers;
391
392 for (i = 0; i < pPeerInfo->numPeers; i++)
393 pStaCtx->ibss_peer_info.peerInfoParams[i] =
394 pPeerInfo->peerInfoParams[i];
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800395 } else {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800396 hdd_debug("peerInfo %s: status %u, numPeers %u",
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530397 pPeerInfo ? "valid" : "null",
398 pPeerInfo ? pPeerInfo->status : QDF_STATUS_E_FAILURE,
399 pPeerInfo ? pPeerInfo->numPeers : 0);
400 pStaCtx->ibss_peer_info.numPeers = 0;
401 pStaCtx->ibss_peer_info.status = QDF_STATUS_E_FAILURE;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800402 }
403
404 complete(&adapter->ibss_peer_info_comp);
405}
406
407/**
408 * hdd_cfg80211_get_ibss_peer_info_all() - get ibss peers' info
409 * @adapter: Adapter context
410 *
411 * Request function to get IBSS peer info from lower layers
412 *
413 * Return: 0 for success non-zero for failure
414 */
415static
416QDF_STATUS hdd_cfg80211_get_ibss_peer_info_all(hdd_adapter_t *adapter)
417{
418 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
419 QDF_STATUS retStatus = QDF_STATUS_E_FAILURE;
420 unsigned long rc;
421
422 INIT_COMPLETION(adapter->ibss_peer_info_comp);
423
424 retStatus = sme_request_ibss_peer_info(hHal, adapter,
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700425 hdd_get_ibss_peer_info_cb,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800426 true, 0xFF);
427
428 if (QDF_STATUS_SUCCESS == retStatus) {
429 rc = wait_for_completion_timeout
430 (&adapter->ibss_peer_info_comp,
431 msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT));
432
433 /* status will be 0 if timed out */
434 if (!rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700435 hdd_warn("Warning: IBSS_PEER_INFO_TIMEOUT");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800436 retStatus = QDF_STATUS_E_FAILURE;
437 return retStatus;
438 }
439 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700440 hdd_warn("Warning: sme_request_ibss_peer_info Request failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800441 }
442
443 return retStatus;
444}
445
446/**
447 * hdd_cfg80211_get_ibss_peer_info() - get ibss peer info
448 * @adapter: Adapter context
449 * @staIdx: Sta index for which the peer info is requested
450 *
451 * Request function to get IBSS peer info from lower layers
452 *
453 * Return: 0 for success non-zero for failure
454 */
455static QDF_STATUS
456hdd_cfg80211_get_ibss_peer_info(hdd_adapter_t *adapter, uint8_t staIdx)
457{
458 unsigned long rc;
459 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
460 QDF_STATUS retStatus = QDF_STATUS_E_FAILURE;
461
462 INIT_COMPLETION(adapter->ibss_peer_info_comp);
463
464 retStatus = sme_request_ibss_peer_info(hHal, adapter,
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700465 hdd_get_ibss_peer_info_cb,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800466 false, staIdx);
467
468 if (QDF_STATUS_SUCCESS == retStatus) {
469 rc = wait_for_completion_timeout(
470 &adapter->ibss_peer_info_comp,
471 msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT));
472
473 /* status = 0 on timeout */
474 if (!rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700475 hdd_warn("Warning: IBSS_PEER_INFO_TIMEOUT");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800476 retStatus = QDF_STATUS_E_FAILURE;
477 return retStatus;
478 }
479 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700480 hdd_warn("Warning: sme_request_ibss_peer_info Request failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800481 }
482
483 return retStatus;
484}
485
486/* Function header is left blank intentionally */
Jeff Johnsonf731b302016-10-05 16:00:55 -0700487static QDF_STATUS
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800488hdd_parse_get_ibss_peer_info(uint8_t *pValue, struct qdf_mac_addr *pPeerMacAddr)
489{
490 uint8_t *inPtr = pValue;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700491
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800492 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
493
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700494 if (NULL == inPtr)
495 return QDF_STATUS_E_FAILURE;
496 else if (SPACE_ASCII_VALUE != *inPtr)
497 return QDF_STATUS_E_FAILURE;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800498
499 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
500 inPtr++;
501
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700502 if ('\0' == *inPtr)
503 return QDF_STATUS_E_FAILURE;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800504
505 if (inPtr[2] != ':' || inPtr[5] != ':' || inPtr[8] != ':' ||
506 inPtr[11] != ':' || inPtr[14] != ':') {
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700507 return QDF_STATUS_E_FAILURE;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800508 }
509 sscanf(inPtr, "%2x:%2x:%2x:%2x:%2x:%2x",
510 (unsigned int *)&pPeerMacAddr->bytes[0],
511 (unsigned int *)&pPeerMacAddr->bytes[1],
512 (unsigned int *)&pPeerMacAddr->bytes[2],
513 (unsigned int *)&pPeerMacAddr->bytes[3],
514 (unsigned int *)&pPeerMacAddr->bytes[4],
515 (unsigned int *)&pPeerMacAddr->bytes[5]);
516
517 return QDF_STATUS_SUCCESS;
518}
519
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800520static void hdd_get_band_helper(hdd_context_t *hdd_ctx, int *pBand)
521{
522 eCsrBand band = -1;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700523
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800524 sme_get_freq_band((tHalHandle) (hdd_ctx->hHal), &band);
525 switch (band) {
526 case eCSR_BAND_ALL:
527 *pBand = WLAN_HDD_UI_BAND_AUTO;
528 break;
529
530 case eCSR_BAND_24:
531 *pBand = WLAN_HDD_UI_BAND_2_4_GHZ;
532 break;
533
534 case eCSR_BAND_5G:
535 *pBand = WLAN_HDD_UI_BAND_5_GHZ;
536 break;
537
538 default:
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700539 hdd_warn("Invalid Band %d", band);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800540 *pBand = -1;
541 break;
542 }
543}
544
545/**
546 * _hdd_parse_bssid_and_chan() - helper function to parse bssid and channel
547 * @data: input data
548 * @target_ap_bssid: pointer to bssid (output parameter)
549 * @channel: pointer to channel (output parameter)
550 *
551 * Return: 0 if parsing is successful; -EINVAL otherwise
552 */
553static int _hdd_parse_bssid_and_chan(const uint8_t **data,
554 uint8_t *bssid,
555 uint8_t *channel)
556{
557 const uint8_t *in_ptr;
558 int v = 0;
559 int temp_int;
560 uint8_t temp_buf[32];
561
562 /* 12 hexa decimal digits, 5 ':' and '\0' */
563 uint8_t mac_addr[18];
564
565 if (!data || !*data)
566 return -EINVAL;
567
568 in_ptr = *data;
569
570 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
571 /* no argument after the command */
572 if (NULL == in_ptr)
573 goto error;
574 /* no space after the command */
575 else if (SPACE_ASCII_VALUE != *in_ptr)
576 goto error;
577
578 /* remove empty spaces */
579 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
580 in_ptr++;
581
582 /* no argument followed by spaces */
583 if ('\0' == *in_ptr)
584 goto error;
585
586 v = sscanf(in_ptr, "%17s", mac_addr);
587 if (!((1 == v) && hdd_is_valid_mac_address(mac_addr))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700588 hdd_err("Invalid MAC address or All hex inputs are not read (%d)",
589 v);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800590 goto error;
591 }
592
593 bssid[0] = hex_to_bin(mac_addr[0]) << 4 |
594 hex_to_bin(mac_addr[1]);
595 bssid[1] = hex_to_bin(mac_addr[3]) << 4 |
596 hex_to_bin(mac_addr[4]);
597 bssid[2] = hex_to_bin(mac_addr[6]) << 4 |
598 hex_to_bin(mac_addr[7]);
599 bssid[3] = hex_to_bin(mac_addr[9]) << 4 |
600 hex_to_bin(mac_addr[10]);
601 bssid[4] = hex_to_bin(mac_addr[12]) << 4 |
602 hex_to_bin(mac_addr[13]);
603 bssid[5] = hex_to_bin(mac_addr[15]) << 4 |
604 hex_to_bin(mac_addr[16]);
605
606 /* point to the next argument */
607 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
608 /* no argument after the command */
609 if (NULL == in_ptr)
610 goto error;
611
612 /* remove empty spaces */
613 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
614 in_ptr++;
615
616 /* no argument followed by spaces */
617 if ('\0' == *in_ptr)
618 goto error;
619
620 /* get the next argument ie the channel number */
621 v = sscanf(in_ptr, "%31s ", temp_buf);
622 if (1 != v)
623 goto error;
624
625 v = kstrtos32(temp_buf, 10, &temp_int);
626 if ((v < 0) || (temp_int < 0) ||
627 (temp_int > WNI_CFG_CURRENT_CHANNEL_STAMAX))
628 return -EINVAL;
629
630 *channel = temp_int;
631 *data = in_ptr;
632 return 0;
633error:
634 *data = in_ptr;
635 return -EINVAL;
636}
637
638/**
639 * hdd_parse_send_action_frame_data() - HDD Parse send action frame data
640 * @pValue: Pointer to input data
641 * @pTargetApBssid: Pointer to target Ap bssid
642 * @pChannel: Pointer to the Target AP channel
643 * @pDwellTime: Pointer to the time to stay off-channel
644 * after transmitting action frame
645 * @pBuf: Pointer to data
646 * @pBufLen: Pointer to data length
647 *
648 * This function parses the send action frame data passed in the format
649 * SENDACTIONFRAME<space><bssid><space><channel><space><dwelltime><space><data>
650 *
651 * Return: 0 for success non-zero for failure
652 */
653static int
654hdd_parse_send_action_frame_v1_data(const uint8_t *pValue,
655 uint8_t *pTargetApBssid,
656 uint8_t *pChannel, uint8_t *pDwellTime,
657 uint8_t **pBuf, uint8_t *pBufLen)
658{
659 const uint8_t *inPtr = pValue;
660 const uint8_t *dataEnd;
661 int tempInt;
662 int j = 0;
663 int i = 0;
664 int v = 0;
665 uint8_t tempBuf[32];
666 uint8_t tempByte = 0;
667
668 if (_hdd_parse_bssid_and_chan(&inPtr, pTargetApBssid, pChannel))
669 return -EINVAL;
670
671 /* point to the next argument */
672 inPtr = strnchr(inPtr, strlen(inPtr), SPACE_ASCII_VALUE);
673 /* no argument after the command */
674 if (NULL == inPtr)
675 return -EINVAL;
676 /* removing empty spaces */
677 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
678 inPtr++;
679
680 /* no argument followed by spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700681 if ('\0' == *inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800682 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800683
684 /* getting the next argument ie the dwell time */
685 v = sscanf(inPtr, "%31s ", tempBuf);
686 if (1 != v)
687 return -EINVAL;
688
689 v = kstrtos32(tempBuf, 10, &tempInt);
690 if (v < 0 || tempInt < 0)
691 return -EINVAL;
692
693 *pDwellTime = tempInt;
694
695 /* point to the next argument */
696 inPtr = strnchr(inPtr, strlen(inPtr), SPACE_ASCII_VALUE);
697 /* no argument after the command */
698 if (NULL == inPtr)
699 return -EINVAL;
700 /* removing empty spaces */
701 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
702 inPtr++;
703
704 /* no argument followed by spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700705 if ('\0' == *inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800706 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800707
708 /* find the length of data */
709 dataEnd = inPtr;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700710 while (('\0' != *dataEnd))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800711 dataEnd++;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700712
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800713 *pBufLen = dataEnd - inPtr;
714 if (*pBufLen <= 0)
715 return -EINVAL;
716
717 /*
718 * Allocate the number of bytes based on the number of input characters
719 * whether it is even or odd.
720 * if the number of input characters are even, then we need N/2 byte.
721 * if the number of input characters are odd, then we need do (N+1)/2
722 * to compensate rounding off.
723 * For example, if N = 18, then (18 + 1)/2 = 9 bytes are enough.
724 * If N = 19, then we need 10 bytes, hence (19 + 1)/2 = 10 bytes
725 */
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530726 *pBuf = qdf_mem_malloc((*pBufLen + 1) / 2);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800727 if (NULL == *pBuf) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700728 hdd_err("qdf_mem_malloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800729 return -ENOMEM;
730 }
731
732 /* the buffer received from the upper layer is character buffer,
733 * we need to prepare the buffer taking 2 characters in to a U8 hex
734 * decimal number for example 7f0000f0...form a buffer to contain 7f
735 * in 0th location, 00 in 1st and f0 in 3rd location
736 */
737 for (i = 0, j = 0; j < *pBufLen; j += 2) {
738 if (j + 1 == *pBufLen) {
739 tempByte = hex_to_bin(inPtr[j]);
740 } else {
741 tempByte =
742 (hex_to_bin(inPtr[j]) << 4) |
743 (hex_to_bin(inPtr[j + 1]));
744 }
745 (*pBuf)[i++] = tempByte;
746 }
747 *pBufLen = i;
748 return 0;
749}
750
751/**
752 * hdd_parse_reassoc_command_data() - HDD Parse reassoc command data
753 * @pValue: Pointer to input data (its a NULL terminated string)
754 * @pTargetApBssid: Pointer to target Ap bssid
755 * @pChannel: Pointer to the Target AP channel
756 *
757 * This function parses the reasoc command data passed in the format
758 * REASSOC<space><bssid><space><channel>
759 *
760 * Return: 0 for success non-zero for failure
761 */
762static int hdd_parse_reassoc_command_v1_data(const uint8_t *pValue,
763 uint8_t *pTargetApBssid,
764 uint8_t *pChannel)
765{
766 const uint8_t *inPtr = pValue;
767
768 if (_hdd_parse_bssid_and_chan(&inPtr, pTargetApBssid, pChannel))
769 return -EINVAL;
770
771 return 0;
772}
773
Naveen Rawat05376ee2016-07-18 16:43:32 -0700774#ifdef WLAN_FEATURE_ROAM_OFFLOAD
Naveen Rawat664a7cb2017-01-19 17:58:14 -0800775void hdd_wma_send_fastreassoc_cmd(hdd_adapter_t *adapter,
776 const tSirMacAddr bssid, int channel)
Naveen Rawat05376ee2016-07-18 16:43:32 -0700777{
Naveen Rawat664a7cb2017-01-19 17:58:14 -0800778 QDF_STATUS status;
779 hdd_wext_state_t *wext_state = WLAN_HDD_GET_WEXT_STATE_PTR(adapter);
780 tCsrRoamProfile *profile = &wext_state->roamProfile;
Naveen Rawat05376ee2016-07-18 16:43:32 -0700781 struct wma_roam_invoke_cmd *fastreassoc;
Rajeev Kumarea95edd2017-01-11 20:49:36 -0800782 struct scheduler_msg msg = {0};
Naveen Rawat05376ee2016-07-18 16:43:32 -0700783
784 fastreassoc = qdf_mem_malloc(sizeof(*fastreassoc));
785 if (NULL == fastreassoc) {
786 hdd_err("qdf_mem_malloc failed for fastreassoc");
787 return;
788 }
Naveen Rawat664a7cb2017-01-19 17:58:14 -0800789 fastreassoc->vdev_id = adapter->sessionId;
Naveen Rawat05376ee2016-07-18 16:43:32 -0700790 fastreassoc->channel = channel;
791 fastreassoc->bssid[0] = bssid[0];
792 fastreassoc->bssid[1] = bssid[1];
793 fastreassoc->bssid[2] = bssid[2];
794 fastreassoc->bssid[3] = bssid[3];
795 fastreassoc->bssid[4] = bssid[4];
796 fastreassoc->bssid[5] = bssid[5];
797
Naveen Rawat664a7cb2017-01-19 17:58:14 -0800798 status = sme_get_beacon_frm(WLAN_HDD_GET_HAL_CTX(adapter), profile,
799 bssid, &fastreassoc->frame_buf,
800 &fastreassoc->frame_len);
801
802 if (QDF_STATUS_SUCCESS != status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800803 hdd_warn("sme_get_beacon_frm failed");
Naveen Rawat664a7cb2017-01-19 17:58:14 -0800804 fastreassoc->frame_buf = NULL;
805 fastreassoc->frame_len = 0;
806 }
807
Naveen Rawat05376ee2016-07-18 16:43:32 -0700808 msg.type = SIR_HAL_ROAM_INVOKE;
809 msg.reserved = 0;
810 msg.bodyptr = fastreassoc;
Naveen Rawat664a7cb2017-01-19 17:58:14 -0800811 status = scheduler_post_msg(QDF_MODULE_ID_WMA, &msg);
812 if (QDF_STATUS_SUCCESS != status) {
Naveen Rawat05376ee2016-07-18 16:43:32 -0700813 hdd_err("Not able to post ROAM_INVOKE_CMD message to WMA");
Naveen Rawat664a7cb2017-01-19 17:58:14 -0800814 qdf_mem_free(fastreassoc);
Naveen Rawat05376ee2016-07-18 16:43:32 -0700815 }
816}
Naveen Rawat05376ee2016-07-18 16:43:32 -0700817#endif
818
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800819/**
820 * hdd_reassoc() - perform a userspace-directed reassoc
Deepak Dhamdhere5a36a4a2016-11-12 15:08:22 -0800821 * @adapter: Adapter upon which the command was received
822 * @bssid: BSSID with which to reassociate
823 * @channel: channel upon which to reassociate
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700824 * @src: The source for the trigger of this action
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800825 *
826 * This function performs a userspace-directed reassoc operation
827 *
828 * Return: 0 for success non-zero for failure
829 */
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700830int hdd_reassoc(hdd_adapter_t *adapter, const uint8_t *bssid,
Deepak Dhamdhere5a36a4a2016-11-12 15:08:22 -0800831 uint8_t channel, const handoff_src src)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800832{
833 hdd_station_ctx_t *pHddStaCtx;
Naveen Rawat05376ee2016-07-18 16:43:32 -0700834 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800835 int ret = 0;
836
Naveen Rawat05376ee2016-07-18 16:43:32 -0700837 if (hdd_ctx == NULL) {
838 hdd_err("Invalid hdd ctx");
839 return -EINVAL;
840 }
841
Krunal Sonibe766b02016-03-10 13:00:44 -0800842 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800843 hdd_warn("Unsupported in mode %s(%d)",
844 hdd_device_mode_to_string(adapter->device_mode),
845 adapter->device_mode);
846 return -EINVAL;
847 }
848
849 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
850
851 /* if not associated, no need to proceed with reassoc */
852 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800853 hdd_warn("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800854 ret = -EINVAL;
855 goto exit;
856 }
857
858 /*
859 * if the target bssid is same as currently associated AP,
Deepak Dhamdhere5a36a4a2016-11-12 15:08:22 -0800860 * use the current connections's channel.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800861 */
862 if (!memcmp(bssid, pHddStaCtx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530863 QDF_MAC_ADDR_SIZE)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800864 hdd_warn("Reassoc BSSID is same as currently associated AP bssid");
Deepak Dhamdhere5a36a4a2016-11-12 15:08:22 -0800865 channel = pHddStaCtx->conn_info.operationChannel;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800866 }
867
868 /* Check channel number is a valid channel number */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530869 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800870 wlan_hdd_validate_operation_channel(adapter, channel)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -0800871 hdd_err("Invalid Channel: %d", channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800872 ret = -EINVAL;
873 goto exit;
874 }
875
876 /* Proceed with reassoc */
Naveen Rawat05376ee2016-07-18 16:43:32 -0700877 if (roaming_offload_enabled(hdd_ctx)) {
Naveen Rawat664a7cb2017-01-19 17:58:14 -0800878 hdd_wma_send_fastreassoc_cmd(adapter,
Naveen Rawat05376ee2016-07-18 16:43:32 -0700879 bssid, (int)channel);
880 } else {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800881 tCsrHandoffRequest handoffInfo;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800882
883 handoffInfo.channel = channel;
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700884 handoffInfo.src = src;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530885 qdf_mem_copy(handoffInfo.bssid.bytes, bssid, QDF_MAC_ADDR_SIZE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800886 sme_handoff_request(hdd_ctx->hHal, adapter->sessionId,
887 &handoffInfo);
888 }
889exit:
890 return ret;
891}
892
893/**
894 * hdd_parse_reassoc_v1() - parse version 1 of the REASSOC command
895 * @adapter: Adapter upon which the command was received
896 * @command: ASCII text command that was received
897 *
898 * This function parses the v1 REASSOC command with the format
899 *
900 * REASSOC xx:xx:xx:xx:xx:xx CH
901 *
902 * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the
903 * BSSID and CH is the ASCII representation of the channel. For
904 * example
905 *
906 * REASSOC 00:0a:0b:11:22:33 48
907 *
908 * Return: 0 for success non-zero for failure
909 */
910static int hdd_parse_reassoc_v1(hdd_adapter_t *adapter, const char *command)
911{
912 uint8_t channel = 0;
913 tSirMacAddr bssid;
914 int ret;
915
916 ret = hdd_parse_reassoc_command_v1_data(command, bssid, &channel);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700917 if (ret)
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700918 hdd_err("Failed to parse reassoc command data");
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700919 else
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700920 ret = hdd_reassoc(adapter, bssid, channel, REASSOC);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700921
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800922 return ret;
923}
924
925/**
926 * hdd_parse_reassoc_v2() - parse version 2 of the REASSOC command
927 * @adapter: Adapter upon which the command was received
928 * @command: Command that was received, ASCII command
Jeff Johnson560dc562017-03-17 15:19:31 -0700929 * followed by binary data
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800930 *
931 * This function parses the v2 REASSOC command with the format
932 *
933 * REASSOC <android_wifi_reassoc_params>
934 *
935 * Return: 0 for success non-zero for failure
936 */
937static int hdd_parse_reassoc_v2(hdd_adapter_t *adapter, const char *command)
938{
939 struct android_wifi_reassoc_params params;
940 tSirMacAddr bssid;
941 int ret;
942
943 /* The params are located after "REASSOC " */
944 memcpy(&params, command + 8, sizeof(params));
945
946 if (!mac_pton(params.bssid, (u8 *) &bssid)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700947 hdd_err("MAC address parsing failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800948 ret = -EINVAL;
949 } else {
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700950 ret = hdd_reassoc(adapter, bssid, params.channel, REASSOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800951 }
952 return ret;
953}
954
955/**
956 * hdd_parse_reassoc() - parse the REASSOC command
957 * @adapter: Adapter upon which the command was received
958 * @command: Command that was received
959 *
960 * There are two different versions of the REASSOC command. Version 1
961 * of the command contains a parameter list that is ASCII characters
962 * whereas version 2 contains a combination of ASCII and binary
963 * payload. Determine if a version 1 or a version 2 command is being
964 * parsed by examining the parameters, and then dispatch the parser
965 * that is appropriate for the command.
966 *
967 * Return: 0 for success non-zero for failure
968 */
969static int hdd_parse_reassoc(hdd_adapter_t *adapter, const char *command)
970{
971 int ret;
972
973 /* both versions start with "REASSOC "
974 * v1 has a bssid and channel # as an ASCII string
975 * REASSOC xx:xx:xx:xx:xx:xx CH
976 * v2 has a C struct
977 * REASSOC <binary c struct>
978 *
979 * The first field in the v2 struct is also the bssid in ASCII.
980 * But in the case of a v2 message the BSSID is NUL-terminated.
981 * Hence we can peek at that offset to see if this is V1 or V2
982 * REASSOC xx:xx:xx:xx:xx:xx*
983 * 1111111111222222
984 * 01234567890123456789012345
985 */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700986 if (command[25])
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800987 ret = hdd_parse_reassoc_v1(adapter, command);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -0700988 else
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800989 ret = hdd_parse_reassoc_v2(adapter, command);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800990
991 return ret;
992}
993
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800994/**
995 * hdd_sendactionframe() - send a userspace-supplied action frame
996 * @adapter: Adapter upon which the command was received
997 * @bssid: BSSID target of the action frame
998 * @channel: Channel upon which to send the frame
999 * @dwell_time: Amount of time to dwell when the frame is sent
1000 * @payload_len:Length of the payload
1001 * @payload: Payload of the frame
1002 *
1003 * This function sends a userspace-supplied action frame
1004 *
1005 * Return: 0 for success non-zero for failure
1006 */
1007static int
1008hdd_sendactionframe(hdd_adapter_t *adapter, const uint8_t *bssid,
1009 const uint8_t channel, const uint8_t dwell_time,
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001010 const int payload_len, const uint8_t *payload)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001011{
1012 struct ieee80211_channel chan;
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001013 int frame_len, ret = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001014 uint8_t *frame;
1015 struct ieee80211_hdr_3addr *hdr;
1016 u64 cookie;
1017 hdd_station_ctx_t *pHddStaCtx;
1018 hdd_context_t *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001019 tpSirMacVendorSpecificFrameHdr pVendorSpecific =
1020 (tpSirMacVendorSpecificFrameHdr) payload;
1021#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
1022 struct cfg80211_mgmt_tx_params params;
1023#endif
1024
Krunal Sonibe766b02016-03-10 13:00:44 -08001025 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001026 hdd_warn("Unsupported in mode %s(%d)",
1027 hdd_device_mode_to_string(adapter->device_mode),
1028 adapter->device_mode);
1029 return -EINVAL;
1030 }
1031
1032 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
1033 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1034
1035 /* if not associated, no need to send action frame */
1036 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001037 hdd_warn("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001038 ret = -EINVAL;
1039 goto exit;
1040 }
1041
1042 /*
1043 * if the target bssid is different from currently associated AP,
1044 * then no need to send action frame
1045 */
1046 if (memcmp(bssid, pHddStaCtx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05301047 QDF_MAC_ADDR_SIZE)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001048 hdd_warn("STA is not associated to this AP");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001049 ret = -EINVAL;
1050 goto exit;
1051 }
1052
1053 chan.center_freq = sme_chn_to_freq(channel);
1054 /* Check if it is specific action frame */
1055 if (pVendorSpecific->category ==
1056 SIR_MAC_ACTION_VENDOR_SPECIFIC_CATEGORY) {
1057 static const uint8_t Oui[] = { 0x00, 0x00, 0xf0 };
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001058
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301059 if (!qdf_mem_cmp(pVendorSpecific->Oui, (void *)Oui, 3)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001060 /*
1061 * if the channel number is different from operating
1062 * channel then no need to send action frame
1063 */
1064 if (channel != 0) {
1065 if (channel !=
1066 pHddStaCtx->conn_info.operationChannel) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001067 hdd_warn("channel(%d) is different from operating channel(%d)",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001068 channel,
1069 pHddStaCtx->conn_info.
1070 operationChannel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001071 ret = -EINVAL;
1072 goto exit;
1073 }
1074 /*
1075 * If channel number is specified and same
1076 * as home channel, ensure that action frame
1077 * is sent immediately by cancelling
1078 * roaming scans. Otherwise large dwell times
1079 * may cause long delays in sending action
1080 * frames.
1081 */
1082 sme_abort_roam_scan(hdd_ctx->hHal,
1083 adapter->sessionId);
1084 } else {
1085 /*
1086 * 0 is accepted as current home channel,
1087 * delayed transmission of action frame is ok.
1088 */
1089 chan.center_freq =
1090 sme_chn_to_freq(pHddStaCtx->conn_info.
1091 operationChannel);
1092 }
1093 }
1094 }
1095 if (chan.center_freq == 0) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001096 hdd_err("Invalid channel number: %d", channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001097 ret = -EINVAL;
1098 goto exit;
1099 }
1100
1101 frame_len = payload_len + 24;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301102 frame = qdf_mem_malloc(frame_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001103 if (!frame) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001104 hdd_err("memory allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001105 ret = -ENOMEM;
1106 goto exit;
1107 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001108
1109 hdr = (struct ieee80211_hdr_3addr *)frame;
1110 hdr->frame_control =
1111 cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301112 qdf_mem_copy(hdr->addr1, bssid, QDF_MAC_ADDR_SIZE);
1113 qdf_mem_copy(hdr->addr2, adapter->macAddressCurrent.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05301114 QDF_MAC_ADDR_SIZE);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301115 qdf_mem_copy(hdr->addr3, bssid, QDF_MAC_ADDR_SIZE);
1116 qdf_mem_copy(hdr + 1, payload, payload_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001117
1118#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
1119 params.chan = &chan;
1120 params.offchan = 0;
1121 params.wait = dwell_time;
1122 params.buf = frame;
1123 params.len = frame_len;
1124 params.no_cck = 1;
1125 params.dont_wait_for_ack = 1;
1126 ret = wlan_hdd_mgmt_tx(NULL, &adapter->wdev, &params, &cookie);
1127#else
1128 ret = wlan_hdd_mgmt_tx(NULL,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001129 &(adapter->wdev),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001130 &chan, 0,
Amar Singhal01098f72015-10-08 11:55:32 -07001131
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001132 dwell_time, frame, frame_len, 1, 1, &cookie);
1133#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
1134
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301135 qdf_mem_free(frame);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001136exit:
1137 return ret;
1138}
1139
1140/**
1141 * hdd_parse_sendactionframe_v1() - parse version 1 of the
1142 * SENDACTIONFRAME command
1143 * @adapter: Adapter upon which the command was received
1144 * @command: ASCII text command that was received
1145 *
1146 * This function parses the v1 SENDACTIONFRAME command with the format
1147 *
1148 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DW xxxxxx
1149 *
1150 * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the
1151 * BSSID, CH is the ASCII representation of the channel, DW is the
1152 * ASCII representation of the dwell time, and xxxxxx is the Hex-ASCII
1153 * payload. For example
1154 *
1155 * SENDACTIONFRAME 00:0a:0b:11:22:33 48 40 aabbccddee
1156 *
1157 * Return: 0 for success non-zero for failure
1158 */
1159static int
1160hdd_parse_sendactionframe_v1(hdd_adapter_t *adapter, const char *command)
1161{
1162 uint8_t channel = 0;
1163 uint8_t dwell_time = 0;
1164 uint8_t payload_len = 0;
1165 uint8_t *payload = NULL;
1166 tSirMacAddr bssid;
1167 int ret;
1168
1169 ret = hdd_parse_send_action_frame_v1_data(command, bssid, &channel,
1170 &dwell_time, &payload,
1171 &payload_len);
1172 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001173 hdd_err("Failed to parse send action frame data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001174 } else {
1175 ret = hdd_sendactionframe(adapter, bssid, channel,
1176 dwell_time, payload_len, payload);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301177 qdf_mem_free(payload);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001178 }
1179
1180 return ret;
1181}
1182
1183/**
1184 * hdd_parse_sendactionframe_v2() - parse version 2 of the
1185 * SENDACTIONFRAME command
1186 * @adapter: Adapter upon which the command was received
1187 * @command: Command that was received, ASCII command
Jeff Johnson560dc562017-03-17 15:19:31 -07001188 * followed by binary data
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001189 *
1190 * This function parses the v2 SENDACTIONFRAME command with the format
1191 *
1192 * SENDACTIONFRAME <android_wifi_af_params>
1193 *
1194 * Return: 0 for success non-zero for failure
1195 */
1196static int
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001197hdd_parse_sendactionframe_v2(hdd_adapter_t *adapter,
1198 const char *command, int total_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001199{
1200 struct android_wifi_af_params *params;
1201 tSirMacAddr bssid;
1202 int ret;
1203
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001204 /* The params are located after "SENDACTIONFRAME " */
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001205 total_len -= 16;
1206 params = (struct android_wifi_af_params *)(command + 16);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001207
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001208 if (params->len <= 0 || params->len > ANDROID_WIFI_ACTION_FRAME_SIZE ||
1209 (params->len > total_len)) {
1210 hdd_err("Invalid payload length: %d", params->len);
1211 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001212 }
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001213
1214 if (!mac_pton(params->bssid, (u8 *)&bssid)) {
1215 hdd_err("MAC address parsing failed");
1216 return -EINVAL;
1217 }
1218
1219 if (params->channel < 0 ||
1220 params->channel > WNI_CFG_CURRENT_CHANNEL_STAMAX) {
1221 hdd_err("Invalid channel: %d", params->channel);
1222 return -EINVAL;
1223 }
1224
1225 if (params->dwell_time < 0) {
1226 hdd_err("Invalid dwell_time: %d", params->dwell_time);
1227 return -EINVAL;
1228 }
1229
1230 ret = hdd_sendactionframe(adapter, bssid, params->channel,
1231 params->dwell_time, params->len, params->data);
1232
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001233 return ret;
1234}
1235
1236/**
1237 * hdd_parse_sendactionframe() - parse the SENDACTIONFRAME command
1238 * @adapter: Adapter upon which the command was received
1239 * @command: Command that was received
1240 *
1241 * There are two different versions of the SENDACTIONFRAME command.
1242 * Version 1 of the command contains a parameter list that is ASCII
1243 * characters whereas version 2 contains a combination of ASCII and
1244 * binary payload. Determine if a version 1 or a version 2 command is
1245 * being parsed by examining the parameters, and then dispatch the
1246 * parser that is appropriate for the version of the command.
1247 *
1248 * Return: 0 for success non-zero for failure
1249 */
1250static int
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001251hdd_parse_sendactionframe(hdd_adapter_t *adapter, const char *command,
1252 int total_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001253{
1254 int ret;
1255
1256 /*
1257 * both versions start with "SENDACTIONFRAME "
1258 * v1 has a bssid and other parameters as an ASCII string
1259 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DWELL LEN FRAME
1260 * v2 has a C struct
1261 * SENDACTIONFRAME <binary c struct>
1262 *
1263 * The first field in the v2 struct is also the bssid in ASCII.
1264 * But in the case of a v2 message the BSSID is NUL-terminated.
1265 * Hence we can peek at that offset to see if this is V1 or V2
1266 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx*
1267 * 111111111122222222223333
1268 * 0123456789012345678901234567890123
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001269 * For both the commands, a valid command must have atleast
1270 * first 34 length of data.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001271 */
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001272 if (total_len < 34) {
1273 hdd_err("Invalid command (total_len=%d)", total_len);
1274 return -EINVAL;
1275 }
1276
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001277 if (command[33])
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001278 ret = hdd_parse_sendactionframe_v1(adapter, command);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001279 else
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001280 ret = hdd_parse_sendactionframe_v2(adapter, command, total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001281
1282 return ret;
1283}
1284
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001285/**
1286 * hdd_parse_channellist() - HDD Parse channel list
1287 * @pValue: Pointer to input channel list
1288 * @ChannelList: Pointer to local output array to record
Jeff Johnson560dc562017-03-17 15:19:31 -07001289 * channel list
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001290 * @pNumChannels: Pointer to number of roam scan channels
1291 *
1292 * This function parses the channel list passed in the format
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001293 * SETROAMSCANCHANNELS<space><Number of channels><space>Channel 1<space>
1294 * Channel 2<space>Channel N
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001295 * if the Number of channels (N) does not match with the actual number
1296 * of channels passed then take the minimum of N and count of
1297 * (Ch1, Ch2, ...Ch M). For example, if SETROAMSCANCHANNELS 3 36 40 44 48,
1298 * only 36, 40 and 44 shall be taken. If SETROAMSCANCHANNELS 5 36 40 44 48,
1299 * ignore 5 and take 36, 40, 44 and 48. This function does not take care of
1300 * removing duplicate channels from the list
1301 *
1302 * Return: 0 for success non-zero for failure
1303 */
1304static int
1305hdd_parse_channellist(const uint8_t *pValue, uint8_t *pChannelList,
1306 uint8_t *pNumChannels)
1307{
1308 const uint8_t *inPtr = pValue;
1309 int tempInt;
1310 int j = 0;
1311 int v = 0;
1312 char buf[32];
1313
1314 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
1315 /* no argument after the command */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001316 if (NULL == inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001317 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001318 else if (SPACE_ASCII_VALUE != *inPtr) /* no space after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001319 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001320
1321 /* remove empty spaces */
1322 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
1323 inPtr++;
1324
1325 /* no argument followed by spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001326 if ('\0' == *inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001327 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001328
1329 /* get the first argument ie the number of channels */
1330 v = sscanf(inPtr, "%31s ", buf);
1331 if (1 != v)
1332 return -EINVAL;
1333
1334 v = kstrtos32(buf, 10, &tempInt);
1335 if ((v < 0) ||
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001336 (tempInt <= 0) || (tempInt > WNI_CFG_VALID_CHANNEL_LIST_LEN))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001337 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001338
1339 *pNumChannels = tempInt;
1340
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001341 hdd_debug("Number of channels are: %d", *pNumChannels);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001342
1343 for (j = 0; j < (*pNumChannels); j++) {
1344 /*
1345 * inPtr pointing to the beginning of first space after number
1346 * of channels
1347 */
1348 inPtr = strpbrk(inPtr, " ");
1349 /* no channel list after the number of channels argument */
1350 if (NULL == inPtr) {
1351 if (0 != j) {
1352 *pNumChannels = j;
1353 return 0;
1354 } else {
1355 return -EINVAL;
1356 }
1357 }
1358
1359 /* remove empty space */
1360 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
1361 inPtr++;
1362
1363 /*
1364 * no channel list after the number of channels
1365 * argument and spaces
1366 */
1367 if ('\0' == *inPtr) {
1368 if (0 != j) {
1369 *pNumChannels = j;
1370 return 0;
1371 } else {
1372 return -EINVAL;
1373 }
1374 }
1375
1376 v = sscanf(inPtr, "%31s ", buf);
1377 if (1 != v)
1378 return -EINVAL;
1379
1380 v = kstrtos32(buf, 10, &tempInt);
1381 if ((v < 0) ||
1382 (tempInt <= 0) ||
1383 (tempInt > WNI_CFG_CURRENT_CHANNEL_STAMAX)) {
1384 return -EINVAL;
1385 }
1386 pChannelList[j] = tempInt;
1387
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001388 hdd_debug("Channel %d added to preferred channel list",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001389 pChannelList[j]);
1390 }
1391
1392 return 0;
1393}
1394
1395/**
1396 * hdd_parse_set_roam_scan_channels_v1() - parse version 1 of the
1397 * SETROAMSCANCHANNELS command
1398 * @adapter: Adapter upon which the command was received
1399 * @command: ASCII text command that was received
1400 *
1401 * This function parses the v1 SETROAMSCANCHANNELS command with the format
1402 *
1403 * SETROAMSCANCHANNELS N C1 C2 ... Cn
1404 *
1405 * Where "N" is the ASCII representation of the number of channels and
1406 * C1 thru Cn is the ASCII representation of the channels. For example
1407 *
1408 * SETROAMSCANCHANNELS 4 36 40 44 48
1409 *
1410 * Return: 0 for success non-zero for failure
1411 */
1412static int
1413hdd_parse_set_roam_scan_channels_v1(hdd_adapter_t *adapter,
1414 const char *command)
1415{
1416 uint8_t channel_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
1417 uint8_t num_chan = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301418 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001419 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1420 int ret;
1421
1422 ret = hdd_parse_channellist(command, channel_list, &num_chan);
1423 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001424 hdd_err("Failed to parse channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001425 goto exit;
1426 }
1427
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301428 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001429 TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL,
1430 adapter->sessionId, num_chan));
1431
1432 if (num_chan > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001433 hdd_err("number of channels (%d) supported exceeded max (%d)",
1434 num_chan, WNI_CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001435 ret = -EINVAL;
1436 goto exit;
1437 }
1438
1439 status =
1440 sme_change_roam_scan_channel_list(hdd_ctx->hHal,
1441 adapter->sessionId,
1442 channel_list, num_chan);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301443 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001444 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001445 ret = -EINVAL;
1446 goto exit;
1447 }
1448exit:
1449 return ret;
1450}
1451
1452/**
1453 * hdd_parse_set_roam_scan_channels_v2() - parse version 2 of the
1454 * SETROAMSCANCHANNELS command
1455 * @adapter: Adapter upon which the command was received
1456 * @command: Command that was received, ASCII command
Jeff Johnson560dc562017-03-17 15:19:31 -07001457 * followed by binary data
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001458 *
1459 * This function parses the v2 SETROAMSCANCHANNELS command with the format
1460 *
1461 * SETROAMSCANCHANNELS [N][C1][C2][Cn]
1462 *
1463 * The command begins with SETROAMSCANCHANNELS followed by a space, but
1464 * what follows the space is an array of u08 parameters. For example
1465 *
1466 * SETROAMSCANCHANNELS [0x04 0x24 0x28 0x2c 0x30]
1467 *
1468 * Return: 0 for success non-zero for failure
1469 */
1470static int
1471hdd_parse_set_roam_scan_channels_v2(hdd_adapter_t *adapter,
1472 const char *command)
1473{
1474 const uint8_t *value;
1475 uint8_t channel_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
1476 uint8_t channel;
1477 uint8_t num_chan;
1478 int i;
1479 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301480 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001481 int ret = 0;
1482
1483 /* array of values begins after "SETROAMSCANCHANNELS " */
1484 value = command + 20;
1485
1486 num_chan = *value++;
1487 if (num_chan > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001488 hdd_err("number of channels (%d) supported exceeded max (%d)",
1489 num_chan, WNI_CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001490 ret = -EINVAL;
1491 goto exit;
1492 }
1493
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301494 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001495 TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL,
1496 adapter->sessionId, num_chan));
1497
1498 for (i = 0; i < num_chan; i++) {
1499 channel = *value++;
1500 if (channel > WNI_CFG_CURRENT_CHANNEL_STAMAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001501 hdd_err("index %d invalid channel %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001502 i, channel);
1503 ret = -EINVAL;
1504 goto exit;
1505 }
1506 channel_list[i] = channel;
1507 }
1508 status =
1509 sme_change_roam_scan_channel_list(hdd_ctx->hHal,
1510 adapter->sessionId,
1511 channel_list, num_chan);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301512 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001513 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001514 ret = -EINVAL;
1515 goto exit;
1516 }
1517exit:
1518 return ret;
1519}
1520
1521/**
1522 * hdd_parse_set_roam_scan_channels() - parse the
1523 * SETROAMSCANCHANNELS command
1524 * @adapter: Adapter upon which the command was received
1525 * @command: Command that was received
1526 *
1527 * There are two different versions of the SETROAMSCANCHANNELS command.
1528 * Version 1 of the command contains a parameter list that is ASCII
1529 * characters whereas version 2 contains a binary payload. Determine
1530 * if a version 1 or a version 2 command is being parsed by examining
1531 * the parameters, and then dispatch the parser that is appropriate for
1532 * the command.
1533 *
1534 * Return: 0 for success non-zero for failure
1535 */
1536static int
1537hdd_parse_set_roam_scan_channels(hdd_adapter_t *adapter, const char *command)
1538{
1539 const char *cursor;
1540 char ch;
1541 bool v1;
1542 int ret;
1543
1544 /* start after "SETROAMSCANCHANNELS " */
1545 cursor = command + 20;
1546
1547 /* assume we have a version 1 command until proven otherwise */
1548 v1 = true;
1549
1550 /* v1 params will only contain ASCII digits and space */
1551 while ((ch = *cursor++) && v1) {
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001552 if (!(isdigit(ch) || isspace(ch)))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001553 v1 = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001554 }
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001555
1556 if (v1)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001557 ret = hdd_parse_set_roam_scan_channels_v1(adapter, command);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07001558 else
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001559 ret = hdd_parse_set_roam_scan_channels_v2(adapter, command);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001560
1561 return ret;
1562}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001563
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08001564#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001565/**
1566 * hdd_parse_plm_cmd() - HDD Parse Plm command
1567 * @pValue: Pointer to input data
1568 * @pPlmRequest:Pointer to output struct tpSirPlmReq
1569 *
1570 * This function parses the plm command passed in the format
1571 * CCXPLMREQ<space><enable><space><dialog_token><space>
1572 * <meas_token><space><num_of_bursts><space><burst_int><space>
1573 * <measu duration><space><burst_len><space><desired_tx_pwr>
1574 * <space><multcast_addr><space><number_of_channels>
1575 * <space><channel_numbers>
1576 *
1577 * Return: 0 for success non-zero for failure
1578 */
Jeff Johnsonf731b302016-10-05 16:00:55 -07001579static QDF_STATUS hdd_parse_plm_cmd(uint8_t *pValue, tSirPlmReq *pPlmRequest)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001580{
1581 uint8_t *cmdPtr = NULL;
1582 int count, content = 0, ret = 0;
1583 char buf[32];
1584
1585 /* move to argument list */
1586 cmdPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
1587 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301588 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001589
1590 /* no space after the command */
1591 if (SPACE_ASCII_VALUE != *cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301592 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001593
1594 /* remove empty spaces */
1595 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1596 cmdPtr++;
1597
1598 /* START/STOP PLM req */
1599 ret = sscanf(cmdPtr, "%31s ", buf);
1600 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301601 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001602
1603 ret = kstrtos32(buf, 10, &content);
1604 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301605 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001606
1607 pPlmRequest->enable = content;
1608 cmdPtr = strpbrk(cmdPtr, " ");
1609
1610 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301611 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001612
1613 /* remove empty spaces */
1614 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1615 cmdPtr++;
1616
1617 /* Dialog token of radio meas req containing meas reqIE */
1618 ret = sscanf(cmdPtr, "%31s ", buf);
1619 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301620 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001621
1622 ret = kstrtos32(buf, 10, &content);
1623 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301624 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001625
1626 pPlmRequest->diag_token = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001627 hdd_debug("diag token %d", pPlmRequest->diag_token);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001628 cmdPtr = strpbrk(cmdPtr, " ");
1629
1630 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301631 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001632
1633 /* remove empty spaces */
1634 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1635 cmdPtr++;
1636
1637 /* measurement token of meas req IE */
1638 ret = sscanf(cmdPtr, "%31s ", buf);
1639 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301640 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001641
1642 ret = kstrtos32(buf, 10, &content);
1643 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301644 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001645
1646 pPlmRequest->meas_token = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001647 hdd_debug("meas token %d", pPlmRequest->meas_token);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001648
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001649 hdd_debug("PLM req %s", pPlmRequest->enable ? "START" : "STOP");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001650 if (pPlmRequest->enable) {
1651
1652 cmdPtr = strpbrk(cmdPtr, " ");
1653
1654 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301655 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001656
1657 /* remove empty spaces */
1658 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1659 cmdPtr++;
1660
1661 /* total number of bursts after which STA stops sending */
1662 ret = sscanf(cmdPtr, "%31s ", buf);
1663 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301664 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001665
1666 ret = kstrtos32(buf, 10, &content);
1667 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301668 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001669
1670 if (content < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301671 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001672
1673 pPlmRequest->numBursts = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001674 hdd_debug("num burst %d", pPlmRequest->numBursts);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001675 cmdPtr = strpbrk(cmdPtr, " ");
1676
1677 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301678 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001679
1680 /* remove empty spaces */
1681 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1682 cmdPtr++;
1683
1684 /* burst interval in seconds */
1685 ret = sscanf(cmdPtr, "%31s ", buf);
1686 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301687 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001688
1689 ret = kstrtos32(buf, 10, &content);
1690 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301691 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001692
1693 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301694 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001695
1696 pPlmRequest->burstInt = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001697 hdd_debug("burst Int %d", pPlmRequest->burstInt);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001698 cmdPtr = strpbrk(cmdPtr, " ");
1699
1700 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301701 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001702
1703 /* remove empty spaces */
1704 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1705 cmdPtr++;
1706
1707 /* Meas dur in TU's,STA goes off-ch and transmit PLM bursts */
1708 ret = sscanf(cmdPtr, "%31s ", buf);
1709 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301710 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001711
1712 ret = kstrtos32(buf, 10, &content);
1713 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301714 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001715
1716 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301717 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001718
1719 pPlmRequest->measDuration = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001720 hdd_debug("measDur %d", pPlmRequest->measDuration);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001721 cmdPtr = strpbrk(cmdPtr, " ");
1722
1723 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301724 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001725
1726 /* remove empty spaces */
1727 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1728 cmdPtr++;
1729
1730 /* burst length of PLM bursts */
1731 ret = sscanf(cmdPtr, "%31s ", buf);
1732 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301733 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001734
1735 ret = kstrtos32(buf, 10, &content);
1736 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301737 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001738
1739 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301740 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001741
1742 pPlmRequest->burstLen = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001743 hdd_debug("burstLen %d", pPlmRequest->burstLen);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001744 cmdPtr = strpbrk(cmdPtr, " ");
1745
1746 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301747 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001748
1749 /* remove empty spaces */
1750 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1751 cmdPtr++;
1752
1753 /* desired tx power for transmission of PLM bursts */
1754 ret = sscanf(cmdPtr, "%31s ", buf);
1755 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301756 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001757
1758 ret = kstrtos32(buf, 10, &content);
1759 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301760 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001761
1762 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301763 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001764
1765 pPlmRequest->desiredTxPwr = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001766 hdd_debug("desiredTxPwr %d",
1767 pPlmRequest->desiredTxPwr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001768
Anurag Chouhan6d760662016-02-20 16:05:43 +05301769 for (count = 0; count < QDF_MAC_ADDR_SIZE; count++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001770 cmdPtr = strpbrk(cmdPtr, " ");
1771
1772 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301773 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001774
1775 /* remove empty spaces */
1776 while ((SPACE_ASCII_VALUE == *cmdPtr)
1777 && ('\0' != *cmdPtr))
1778 cmdPtr++;
1779
1780 ret = sscanf(cmdPtr, "%31s ", buf);
1781 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301782 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001783
1784 ret = kstrtos32(buf, 16, &content);
1785 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301786 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001787
Srinivas Girigowda5146dee2015-11-18 21:46:48 -08001788 pPlmRequest->mac_addr.bytes[count] = content;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001789 }
1790
Srinivas Girigowda5146dee2015-11-18 21:46:48 -08001791 hdd_debug("MC addr " MAC_ADDRESS_STR,
1792 MAC_ADDR_ARRAY(pPlmRequest->mac_addr.bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001793
1794 cmdPtr = strpbrk(cmdPtr, " ");
1795
1796 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301797 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001798
1799 /* remove empty spaces */
1800 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1801 cmdPtr++;
1802
1803 /* number of channels */
1804 ret = sscanf(cmdPtr, "%31s ", buf);
1805 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301806 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001807
1808 ret = kstrtos32(buf, 10, &content);
1809 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301810 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001811
1812 if (content < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301813 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001814
Srinivas Girigowda0fb6cc42016-08-26 14:53:59 -07001815 content = QDF_MIN(content, WNI_CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001816 pPlmRequest->plmNumCh = content;
Srinivas Girigowda0fb6cc42016-08-26 14:53:59 -07001817 hdd_debug("numch: %d", pPlmRequest->plmNumCh);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001818
1819 /* Channel numbers */
1820 for (count = 0; count < pPlmRequest->plmNumCh; count++) {
1821 cmdPtr = strpbrk(cmdPtr, " ");
1822
1823 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301824 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001825
1826 /* remove empty spaces */
1827 while ((SPACE_ASCII_VALUE == *cmdPtr)
1828 && ('\0' != *cmdPtr))
1829 cmdPtr++;
1830
1831 ret = sscanf(cmdPtr, "%31s ", buf);
1832 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301833 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001834
1835 ret = kstrtos32(buf, 10, &content);
Srinivas Girigowda0fb6cc42016-08-26 14:53:59 -07001836 if (ret < 0 || content <= 0 ||
1837 content > WNI_CFG_CURRENT_CHANNEL_STAMAX)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301838 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001839
1840 pPlmRequest->plmChList[count] = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001841 hdd_debug(" ch- %d", pPlmRequest->plmChList[count]);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001842 }
1843 }
1844 /* If PLM START */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301845 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001846}
1847#endif
1848
1849#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
1850static void wlan_hdd_ready_to_extwow(void *callbackContext, bool is_success)
1851{
1852 hdd_context_t *hdd_ctx = (hdd_context_t *) callbackContext;
1853 int rc;
1854
1855 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301856 if (rc)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001857 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001858 hdd_ctx->ext_wow_should_suspend = is_success;
1859 complete(&hdd_ctx->ready_to_extwow);
1860}
1861
1862static int hdd_enable_ext_wow(hdd_adapter_t *adapter,
1863 tpSirExtWoWParams arg_params)
1864{
1865 tSirExtWoWParams params;
Jeff Johnson17d62672017-03-27 08:00:11 -07001866 QDF_STATUS qdf_ret_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001867 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1868 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
1869 int rc;
1870
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301871 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001872
1873 INIT_COMPLETION(hdd_ctx->ready_to_extwow);
1874
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301875 qdf_ret_status = sme_configure_ext_wow(hHal, &params,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001876 &wlan_hdd_ready_to_extwow,
1877 hdd_ctx);
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301878 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001879 hdd_err("sme_configure_ext_wow returned failure %d",
1880 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001881 return -EPERM;
1882 }
1883
1884 rc = wait_for_completion_timeout(&hdd_ctx->ready_to_extwow,
1885 msecs_to_jiffies(WLAN_WAIT_TIME_READY_TO_EXTWOW));
1886 if (!rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001887 hdd_err("Failed to get ready to extwow");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001888 return -EPERM;
1889 }
1890
Jeff Johnson17d62672017-03-27 08:00:11 -07001891 if (!hdd_ctx->ext_wow_should_suspend) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001892 hdd_err("Received ready to ExtWoW failure");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001893 return -EPERM;
1894 }
1895
Jeff Johnson17d62672017-03-27 08:00:11 -07001896 if (hdd_ctx->config->extWowGotoSuspend) {
1897 hdd_info("Received ready to ExtWoW. Going to suspend");
1898
1899 rc = wlan_hdd_cfg80211_suspend_wlan(hdd_ctx->wiphy, NULL);
1900 if (rc < 0) {
1901 hdd_err("wlan_hdd_cfg80211_suspend_wlan failed, error = %d",
1902 rc);
1903 return rc;
1904 }
1905 rc = wlan_hdd_bus_suspend();
1906 if (rc) {
1907 hdd_err("wlan_hdd_bus_suspend failed, status = %d",
1908 rc);
1909 wlan_hdd_cfg80211_resume_wlan(hdd_ctx->wiphy);
1910 return rc;
1911 }
1912 }
1913
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001914 return 0;
1915}
1916
1917static int hdd_enable_ext_wow_parser(hdd_adapter_t *adapter, int vdev_id,
1918 int value)
1919{
1920 tSirExtWoWParams params;
1921 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1922 int rc;
1923
1924 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301925 if (rc)
1926 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001927
1928 if (value < EXT_WOW_TYPE_APP_TYPE1 ||
1929 value > EXT_WOW_TYPE_APP_TYPE1_2) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08001930 hdd_err("Invalid type: %d", value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001931 return -EINVAL;
1932 }
1933
1934 if (value == EXT_WOW_TYPE_APP_TYPE1 &&
1935 hdd_ctx->is_extwow_app_type1_param_set)
1936 params.type = value;
1937 else if (value == EXT_WOW_TYPE_APP_TYPE2 &&
1938 hdd_ctx->is_extwow_app_type2_param_set)
1939 params.type = value;
1940 else if (value == EXT_WOW_TYPE_APP_TYPE1_2 &&
1941 hdd_ctx->is_extwow_app_type1_param_set &&
1942 hdd_ctx->is_extwow_app_type2_param_set)
1943 params.type = value;
1944 else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001945 hdd_err("Set app params before enable it value %d",
1946 value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001947 return -EINVAL;
1948 }
1949
1950 params.vdev_id = vdev_id;
1951 params.wakeup_pin_num = hdd_ctx->config->extWowApp1WakeupPinNumber |
1952 (hdd_ctx->config->extWowApp2WakeupPinNumber
1953 << 8);
1954
1955 return hdd_enable_ext_wow(adapter, &params);
1956}
1957
1958static int hdd_set_app_type1_params(tHalHandle hHal,
1959 tpSirAppType1Params arg_params)
1960{
1961 tSirAppType1Params params;
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301962 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001963
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301964 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001965
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301966 qdf_ret_status = sme_configure_app_type1_params(hHal, &params);
1967 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001968 hdd_err("sme_configure_app_type1_params returned failure %d",
1969 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001970 return -EPERM;
1971 }
1972
1973 return 0;
1974}
1975
1976static int hdd_set_app_type1_parser(hdd_adapter_t *adapter,
1977 char *arg, int len)
1978{
1979 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1980 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
1981 char id[20], password[20];
1982 tSirAppType1Params params;
Srinivas Girigowda04209912015-11-24 12:11:13 -08001983 int rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001984
1985 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301986 if (rc)
1987 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001988
1989 if (2 != sscanf(arg, "%8s %16s", id, password)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001990 hdd_err("Invalid Number of arguments");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001991 return -EINVAL;
1992 }
1993
1994 memset(&params, 0, sizeof(tSirAppType1Params));
1995 params.vdev_id = adapter->sessionId;
Anurag Chouhanc5548422016-02-24 18:33:27 +05301996 qdf_copy_macaddr(&params.wakee_mac_addr, &adapter->macAddressCurrent);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001997
1998 params.id_length = strlen(id);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301999 qdf_mem_copy(params.identification_id, id, params.id_length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002000 params.pass_length = strlen(password);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302001 qdf_mem_copy(params.password, password, params.pass_length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002002
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002003 hdd_debug("%d %pM %.8s %u %.16s %u",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002004 params.vdev_id, params.wakee_mac_addr.bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002005 params.identification_id, params.id_length,
2006 params.password, params.pass_length);
2007
2008 return hdd_set_app_type1_params(hHal, &params);
2009}
2010
2011static int hdd_set_app_type2_params(tHalHandle hHal,
2012 tpSirAppType2Params arg_params)
2013{
2014 tSirAppType2Params params;
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05302015 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002016
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302017 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002018
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05302019 qdf_ret_status = sme_configure_app_type2_params(hHal, &params);
2020 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002021 hdd_err("sme_configure_app_type2_params returned failure %d",
2022 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002023 return -EPERM;
2024 }
2025
2026 return 0;
2027}
2028
2029static int hdd_set_app_type2_parser(hdd_adapter_t *adapter,
2030 char *arg, int len)
2031{
2032 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2033 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
2034 char mac_addr[20], rc4_key[20];
Anurag Chouhan6d760662016-02-20 16:05:43 +05302035 unsigned int gateway_mac[QDF_MAC_ADDR_SIZE];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002036 tSirAppType2Params params;
2037 int ret;
2038
2039 ret = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302040 if (ret)
2041 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002042
2043 memset(&params, 0, sizeof(tSirAppType2Params));
2044
Bhargav Shahf4fd97d2015-07-08 10:21:37 +05302045 ret = sscanf(arg, "%17s %16s %x %x %x %u %u %hu %hu %u %u %u %u %u %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002046 mac_addr, rc4_key, (unsigned int *)&params.ip_id,
2047 (unsigned int *)&params.ip_device_ip,
2048 (unsigned int *)&params.ip_server_ip,
2049 (unsigned int *)&params.tcp_seq,
2050 (unsigned int *)&params.tcp_ack_seq,
Bhargav Shahf4fd97d2015-07-08 10:21:37 +05302051 (uint16_t *)&params.tcp_src_port,
2052 (uint16_t *)&params.tcp_dst_port,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002053 (unsigned int *)&params.keepalive_init,
2054 (unsigned int *)&params.keepalive_min,
2055 (unsigned int *)&params.keepalive_max,
2056 (unsigned int *)&params.keepalive_inc,
2057 (unsigned int *)&params.tcp_tx_timeout_val,
2058 (unsigned int *)&params.tcp_rx_timeout_val);
2059
2060 if (ret != 15 && ret != 7) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002061 hdd_err("Invalid Number of arguments");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002062 return -EINVAL;
2063 }
2064
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002065 if (6 != sscanf(mac_addr, "%02x:%02x:%02x:%02x:%02x:%02x",
2066 &gateway_mac[0], &gateway_mac[1], &gateway_mac[2],
2067 &gateway_mac[3], &gateway_mac[4], &gateway_mac[5])) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002068 hdd_err("Invalid MacAddress Input %s", mac_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002069 return -EINVAL;
2070 }
2071
2072 if (params.tcp_src_port > WLAN_HDD_MAX_TCP_PORT ||
2073 params.tcp_dst_port > WLAN_HDD_MAX_TCP_PORT) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002074 hdd_err("Invalid TCP Port Number");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002075 return -EINVAL;
2076 }
2077
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302078 qdf_mem_copy(&params.gateway_mac.bytes, (uint8_t *) &gateway_mac,
Anurag Chouhan6d760662016-02-20 16:05:43 +05302079 QDF_MAC_ADDR_SIZE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002080
2081 params.rc4_key_len = strlen(rc4_key);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302082 qdf_mem_copy(params.rc4_key, rc4_key, params.rc4_key_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002083
2084 params.vdev_id = adapter->sessionId;
2085 params.tcp_src_port = (params.tcp_src_port != 0) ?
2086 params.tcp_src_port : hdd_ctx->config->extWowApp2TcpSrcPort;
2087 params.tcp_dst_port = (params.tcp_dst_port != 0) ?
2088 params.tcp_dst_port : hdd_ctx->config->extWowApp2TcpDstPort;
2089 params.keepalive_init = (params.keepalive_init != 0) ?
2090 params.keepalive_init : hdd_ctx->config->
2091 extWowApp2KAInitPingInterval;
2092 params.keepalive_min =
2093 (params.keepalive_min != 0) ?
2094 params.keepalive_min :
2095 hdd_ctx->config->extWowApp2KAMinPingInterval;
2096 params.keepalive_max =
2097 (params.keepalive_max != 0) ?
2098 params.keepalive_max :
2099 hdd_ctx->config->extWowApp2KAMaxPingInterval;
2100 params.keepalive_inc =
2101 (params.keepalive_inc != 0) ?
2102 params.keepalive_inc :
2103 hdd_ctx->config->extWowApp2KAIncPingInterval;
2104 params.tcp_tx_timeout_val =
2105 (params.tcp_tx_timeout_val != 0) ?
2106 params.tcp_tx_timeout_val :
2107 hdd_ctx->config->extWowApp2TcpTxTimeout;
2108 params.tcp_rx_timeout_val =
2109 (params.tcp_rx_timeout_val != 0) ?
2110 params.tcp_rx_timeout_val :
2111 hdd_ctx->config->extWowApp2TcpRxTimeout;
2112
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002113 hdd_debug("%pM %.16s %u %u %u %u %u %u %u %u %u %u %u %u %u",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002114 gateway_mac, rc4_key, params.ip_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002115 params.ip_device_ip, params.ip_server_ip, params.tcp_seq,
2116 params.tcp_ack_seq, params.tcp_src_port, params.tcp_dst_port,
2117 params.keepalive_init, params.keepalive_min,
2118 params.keepalive_max, params.keepalive_inc,
2119 params.tcp_tx_timeout_val, params.tcp_rx_timeout_val);
2120
2121 return hdd_set_app_type2_params(hHal, &params);
2122}
2123#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
2124
2125/**
2126 * hdd_parse_setmaxtxpower_command() - HDD Parse MAXTXPOWER command
2127 * @pValue: Pointer to MAXTXPOWER command
2128 * @pDbm: Pointer to tx power
2129 *
2130 * This function parses the MAXTXPOWER command passed in the format
2131 * MAXTXPOWER<space>X(Tx power in dbm)
2132 *
2133 * For example input commands:
2134 * 1) MAXTXPOWER -8 -> This is translated into set max TX power to -8 dbm
2135 * 2) MAXTXPOWER -23 -> This is translated into set max TX power to -23 dbm
2136 *
2137 * Return: 0 for success non-zero for failure
2138 */
2139static int hdd_parse_setmaxtxpower_command(uint8_t *pValue, int *pTxPower)
2140{
2141 uint8_t *inPtr = pValue;
2142 int tempInt;
2143 int v = 0;
2144 *pTxPower = 0;
2145
2146 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2147 /* no argument after the command */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002148 if (NULL == inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002149 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002150 else if (SPACE_ASCII_VALUE != *inPtr) /* no space after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002151 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002152
2153 /* remove empty spaces */
2154 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2155 inPtr++;
2156
2157 /* no argument followed by spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002158 if ('\0' == *inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002159 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002160
2161 v = kstrtos32(inPtr, 10, &tempInt);
2162
2163 /* Range checking for passed parameter */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002164 if ((tempInt < HDD_MIN_TX_POWER) || (tempInt > HDD_MAX_TX_POWER))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002165 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002166
2167 *pTxPower = tempInt;
2168
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002169 hdd_debug("SETMAXTXPOWER: %d", *pTxPower);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002170
2171 return 0;
2172} /* End of hdd_parse_setmaxtxpower_command */
2173
2174static int hdd_get_dwell_time(struct hdd_config *pCfg, uint8_t *command,
2175 char *extra, uint8_t n, uint8_t *len)
2176{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002177 if (!pCfg || !command || !extra || !len) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002178 hdd_err("argument passed for GETDWELLTIME is incorrect");
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002179 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002180 }
2181
2182 if (strncmp(command, "GETDWELLTIME ACTIVE MAX", 23) == 0) {
2183 *len = scnprintf(extra, n, "GETDWELLTIME ACTIVE MAX %u\n",
2184 (int)pCfg->nActiveMaxChnTime);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002185 return 0;
Jeff Johnson68755312017-02-10 11:46:55 -08002186 }
2187 if (strncmp(command, "GETDWELLTIME ACTIVE MIN", 23) == 0) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002188 *len = scnprintf(extra, n, "GETDWELLTIME ACTIVE MIN %u\n",
2189 (int)pCfg->nActiveMinChnTime);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002190 return 0;
Jeff Johnson68755312017-02-10 11:46:55 -08002191 }
2192 if (strncmp(command, "GETDWELLTIME PASSIVE MAX", 24) == 0) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002193 *len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MAX %u\n",
2194 (int)pCfg->nPassiveMaxChnTime);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002195 return 0;
Jeff Johnson68755312017-02-10 11:46:55 -08002196 }
2197 if (strncmp(command, "GETDWELLTIME PASSIVE MIN", 24) == 0) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002198 *len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MIN %u\n",
2199 (int)pCfg->nPassiveMinChnTime);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002200 return 0;
Jeff Johnson68755312017-02-10 11:46:55 -08002201 }
2202 if (strncmp(command, "GETDWELLTIME", 12) == 0) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002203 *len = scnprintf(extra, n, "GETDWELLTIME %u \n",
2204 (int)pCfg->nActiveMaxChnTime);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002205 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002206 }
2207
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002208 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002209}
2210
2211static int hdd_set_dwell_time(hdd_adapter_t *adapter, uint8_t *command)
2212{
2213 tHalHandle hHal;
2214 struct hdd_config *pCfg;
2215 uint8_t *value = command;
2216 tSmeConfigParams smeConfig;
2217 int val = 0, temp = 0;
2218
2219 pCfg = (WLAN_HDD_GET_CTX(adapter))->config;
2220 hHal = WLAN_HDD_GET_HAL_CTX(adapter);
2221 if (!pCfg || !hHal) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002222 hdd_err("argument passed for SETDWELLTIME is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002223 return -EINVAL;
2224 }
2225
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302226 qdf_mem_zero(&smeConfig, sizeof(smeConfig));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002227 sme_get_config_param(hHal, &smeConfig);
2228
2229 if (strncmp(command, "SETDWELLTIME ACTIVE MAX", 23) == 0) {
2230 value = value + 24;
2231 temp = kstrtou32(value, 10, &val);
2232 if (temp != 0 || val < CFG_ACTIVE_MAX_CHANNEL_TIME_MIN ||
2233 val > CFG_ACTIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002234 hdd_err("argument passed for SETDWELLTIME ACTIVE MAX is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002235 return -EFAULT;
2236 }
2237 pCfg->nActiveMaxChnTime = val;
2238 smeConfig.csrConfig.nActiveMaxChnTime = val;
2239 sme_update_config(hHal, &smeConfig);
2240 } else if (strncmp(command, "SETDWELLTIME ACTIVE MIN", 23) == 0) {
2241 value = value + 24;
2242 temp = kstrtou32(value, 10, &val);
2243 if (temp != 0 || val < CFG_ACTIVE_MIN_CHANNEL_TIME_MIN ||
2244 val > CFG_ACTIVE_MIN_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002245 hdd_err("argument passed for SETDWELLTIME ACTIVE MIN is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002246 return -EFAULT;
2247 }
2248 pCfg->nActiveMinChnTime = val;
2249 smeConfig.csrConfig.nActiveMinChnTime = val;
2250 sme_update_config(hHal, &smeConfig);
2251 } else if (strncmp(command, "SETDWELLTIME PASSIVE MAX", 24) == 0) {
2252 value = value + 25;
2253 temp = kstrtou32(value, 10, &val);
2254 if (temp != 0 || val < CFG_PASSIVE_MAX_CHANNEL_TIME_MIN ||
2255 val > CFG_PASSIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002256 hdd_err("argument passed for SETDWELLTIME PASSIVE MAX is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002257 return -EFAULT;
2258 }
2259 pCfg->nPassiveMaxChnTime = val;
2260 smeConfig.csrConfig.nPassiveMaxChnTime = val;
2261 sme_update_config(hHal, &smeConfig);
2262 } else if (strncmp(command, "SETDWELLTIME PASSIVE MIN", 24) == 0) {
2263 value = value + 25;
2264 temp = kstrtou32(value, 10, &val);
2265 if (temp != 0 || val < CFG_PASSIVE_MIN_CHANNEL_TIME_MIN ||
2266 val > CFG_PASSIVE_MIN_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002267 hdd_err("argument passed for SETDWELLTIME PASSIVE MIN is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002268 return -EFAULT;
2269 }
2270 pCfg->nPassiveMinChnTime = val;
2271 smeConfig.csrConfig.nPassiveMinChnTime = val;
2272 sme_update_config(hHal, &smeConfig);
2273 } else if (strncmp(command, "SETDWELLTIME", 12) == 0) {
2274 value = value + 13;
2275 temp = kstrtou32(value, 10, &val);
2276 if (temp != 0 || val < CFG_ACTIVE_MAX_CHANNEL_TIME_MIN ||
2277 val > CFG_ACTIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002278 hdd_err("argument passed for SETDWELLTIME is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002279 return -EFAULT;
2280 }
2281 pCfg->nActiveMaxChnTime = val;
2282 smeConfig.csrConfig.nActiveMaxChnTime = val;
2283 sme_update_config(hHal, &smeConfig);
2284 } else {
2285 return -EINVAL;
2286 }
2287
2288 return 0;
2289}
2290
Jeff Johnson253c0c22017-01-23 16:59:38 -08002291struct link_status_priv {
2292 uint8_t link_status;
2293};
2294
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002295static void hdd_get_link_status_cb(uint8_t status, void *context)
2296{
Jeff Johnson253c0c22017-01-23 16:59:38 -08002297 struct hdd_request *request;
2298 struct link_status_priv *priv;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002299
Jeff Johnson253c0c22017-01-23 16:59:38 -08002300 request = hdd_request_get(context);
2301 if (!request) {
2302 hdd_err("Obsolete request");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002303 return;
2304 }
2305
Jeff Johnson253c0c22017-01-23 16:59:38 -08002306 priv = hdd_request_priv(request);
2307 priv->link_status = status;
2308 hdd_request_complete(request);
2309 hdd_request_put(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002310}
2311
2312/**
2313 * wlan_hdd_get_link_status() - get link status
2314 * @pAdapter: pointer to the adapter
2315 *
2316 * This function sends a request to query the link status and waits
2317 * on a timer to invoke the callback. if the callback is invoked then
2318 * latest link status shall be returned or otherwise cached value
2319 * will be returned.
2320 *
2321 * Return: On success, link status shall be returned.
2322 * On error or not associated, link status 0 will be returned.
2323 */
2324static int wlan_hdd_get_link_status(hdd_adapter_t *adapter)
2325{
2326
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002327 hdd_station_ctx_t *pHddStaCtx =
2328 WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302329 QDF_STATUS hstatus;
Jeff Johnson253c0c22017-01-23 16:59:38 -08002330 int ret;
2331 void *cookie;
2332 struct hdd_request *request;
2333 struct link_status_priv *priv;
2334 static const struct hdd_request_params params = {
2335 .priv_size = sizeof(*priv),
2336 .timeout_ms = WLAN_WAIT_TIME_LINK_STATUS,
2337 };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002338
Prashanth Bhatta9e143052015-12-04 11:56:47 -08002339 if (cds_is_driver_recovering()) {
2340 hdd_warn("Recovery in Progress. State: 0x%x Ignore!!!",
2341 cds_get_driver_state());
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002342 return 0;
2343 }
2344
Krunal Sonibe766b02016-03-10 13:00:44 -08002345 if ((QDF_STA_MODE != adapter->device_mode) &&
2346 (QDF_P2P_CLIENT_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002347 hdd_warn("Unsupported in mode %s(%d)",
2348 hdd_device_mode_to_string(adapter->device_mode),
2349 adapter->device_mode);
2350 return 0;
2351 }
2352
2353 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
2354 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
2355 /* If not associated, then expected link status return
2356 * value is 0
2357 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002358 hdd_warn("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002359 return 0;
2360 }
2361
Jeff Johnson253c0c22017-01-23 16:59:38 -08002362 request = hdd_request_alloc(&params);
2363 if (!request) {
2364 hdd_err("Request allocation failure");
2365 return 0;
2366 }
2367 cookie = hdd_request_cookie(request);
2368
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002369 hstatus = sme_get_link_status(WLAN_HDD_GET_HAL_CTX(adapter),
2370 hdd_get_link_status_cb,
Jeff Johnson253c0c22017-01-23 16:59:38 -08002371 cookie, adapter->sessionId);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302372 if (QDF_STATUS_SUCCESS != hstatus) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002373 hdd_err("Unable to retrieve link status");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002374 /* return a cached value */
2375 } else {
2376 /* request is sent -- wait for the response */
Jeff Johnson253c0c22017-01-23 16:59:38 -08002377 ret = hdd_request_wait_for_response(request);
2378 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002379 hdd_err("SME timed out while retrieving link status");
Jeff Johnson253c0c22017-01-23 16:59:38 -08002380 /* return a cached value */
2381 } else {
2382 /* update the adapter with the fresh results */
2383 priv = hdd_request_priv(request);
2384 adapter->linkStatus = priv->link_status;
2385 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002386 }
2387
Jeff Johnson253c0c22017-01-23 16:59:38 -08002388 /*
2389 * either we never sent a request, we sent a request and
2390 * received a response or we sent a request and timed out.
2391 * regardless we are done with the request.
2392 */
2393 hdd_request_put(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002394
2395 /* either callback updated adapter stats or it has cached data */
2396 return adapter->linkStatus;
2397}
2398
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002399static void hdd_tx_fail_ind_callback(uint8_t *MacAddr, uint8_t seqNo)
2400{
2401 int payload_len;
2402 struct sk_buff *skb;
2403 struct nlmsghdr *nlh;
2404 uint8_t *data;
2405
2406 payload_len = ETH_ALEN;
2407
Ryan Hsu5e2e2052016-04-28 10:19:38 -07002408 if (0 == cesium_pid || cesium_nl_srv_sock == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002409 hdd_err("cesium process not registered");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002410 return;
2411 }
2412
2413 skb = nlmsg_new(payload_len, GFP_ATOMIC);
2414 if (skb == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002415 hdd_err("nlmsg_new() failed for msg size[%d]",
2416 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002417 return;
2418 }
2419
2420 nlh = nlmsg_put(skb, cesium_pid, seqNo, 0, payload_len, NLM_F_REQUEST);
2421
2422 if (NULL == nlh) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002423 hdd_err("nlmsg_put() failed for msg size[%d]",
2424 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002425
2426 kfree_skb(skb);
2427 return;
2428 }
2429
2430 data = nlmsg_data(nlh);
2431 memcpy(data, MacAddr, ETH_ALEN);
2432
2433 if (nlmsg_unicast(cesium_nl_srv_sock, skb, cesium_pid) < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002434 hdd_err("nlmsg_unicast() failed for msg size[%d]",
2435 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002436 }
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002437}
2438
2439
2440/**
2441 * hdd_ParseuserParams - return a pointer to the next argument
2442 * @pValue: Input argument string
2443 * @ppArg: Output pointer to the next argument
2444 *
2445 * This function parses argument stream and finds the pointer
2446 * to the next argument
2447 *
2448 * Return: 0 if the next argument found; -EINVAL otherwise
2449 */
2450static int hdd_parse_user_params(uint8_t *pValue, uint8_t **ppArg)
2451{
2452 uint8_t *pVal;
2453
2454 pVal = strnchr(pValue, strlen(pValue), ' ');
2455
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002456 if (NULL == pVal) /* no argument remains */
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002457 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002458 else if (SPACE_ASCII_VALUE != *pVal)/* no space after the current arg */
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002459 return -EINVAL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002460
2461 pVal++;
2462
2463 /* remove empty spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002464 while ((SPACE_ASCII_VALUE == *pVal) && ('\0' != *pVal))
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002465 pVal++;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002466
2467 /* no argument followed by spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002468 if ('\0' == *pVal)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002469 return -EINVAL;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002470
2471 *ppArg = pVal;
2472
2473 return 0;
2474}
2475
2476/**
2477 * hdd_parse_ibsstx_fail_event_params - Parse params
2478 * for SETIBSSTXFAILEVENT
2479 * @pValue: Input ibss tx fail event argument
2480 * @tx_fail_count: (Output parameter) Tx fail counter
2481 * @pid: (Output parameter) PID
2482 *
2483 * Return: 0 if the parsing succeeds; -EINVAL otherwise
2484 */
2485static int hdd_parse_ibsstx_fail_event_params(uint8_t *pValue,
2486 uint8_t *tx_fail_count,
2487 uint16_t *pid)
2488{
2489 uint8_t *param = NULL;
2490 int ret;
2491
2492 ret = hdd_parse_user_params(pValue, &param);
2493
2494 if (0 == ret && NULL != param) {
2495 if (1 != sscanf(param, "%hhu", tx_fail_count)) {
2496 ret = -EINVAL;
2497 goto done;
2498 }
2499 } else {
2500 goto done;
2501 }
2502
2503 if (0 == *tx_fail_count) {
2504 *pid = 0;
2505 goto done;
2506 }
2507
2508 pValue = param;
2509 pValue++;
2510
2511 ret = hdd_parse_user_params(pValue, &param);
2512
2513 if (0 == ret) {
2514 if (1 != sscanf(param, "%hu", pid)) {
2515 ret = -EINVAL;
2516 goto done;
2517 }
2518 } else {
2519 goto done;
2520 }
2521
2522done:
2523 return ret;
2524}
2525
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08002526#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002527/**
2528 * hdd_parse_ese_beacon_req() - Parse ese beacon request
2529 * @pValue: Pointer to data
2530 * @pEseBcnReq: Output pointer to store parsed ie information
2531 *
2532 * This function parses the ese beacon request passed in the format
2533 * CCXBEACONREQ<space><Number of fields><space><Measurement token>
2534 * <space>Channel 1<space>Scan Mode <space>Meas Duration<space>Channel N
2535 * <space>Scan Mode N<space>Meas Duration N
2536 *
2537 * If the Number of bcn req fields (N) does not match with the
2538 * actual number of fields passed then take N.
2539 * <Meas Token><Channel><Scan Mode> and <Meas Duration> are treated
2540 * as one pair. For example, CCXBEACONREQ 2 1 1 1 30 2 44 0 40.
2541 * This function does not take care of removing duplicate channels from the
2542 * list
2543 *
2544 * Return: 0 for success non-zero for failure
2545 */
2546static int hdd_parse_ese_beacon_req(uint8_t *pValue,
2547 tCsrEseBeaconReq *pEseBcnReq)
2548{
2549 uint8_t *inPtr = pValue;
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002550 uint8_t input = 0;
2551 uint32_t tempInt = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002552 int j = 0, i = 0, v = 0;
2553 char buf[32];
2554
2555 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002556 if (NULL == inPtr) /* no argument after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002557 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002558 else if (SPACE_ASCII_VALUE != *inPtr) /* no space after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002559 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002560
2561 /* remove empty spaces */
2562 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2563 inPtr++;
2564
2565 /* no argument followed by spaces */
2566 if ('\0' == *inPtr)
2567 return -EINVAL;
2568
Srinivas Girigowda476deeb2016-07-19 16:21:29 -07002569 /* Getting the first argument ie Number of IE fields */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002570 v = sscanf(inPtr, "%31s ", buf);
2571 if (1 != v)
2572 return -EINVAL;
2573
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002574 v = kstrtou8(buf, 10, &input);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002575 if (v < 0)
2576 return -EINVAL;
2577
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002578 input = QDF_MIN(input, SIR_ESE_MAX_MEAS_IE_REQS);
2579 pEseBcnReq->numBcnReqIe = input;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002580
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002581 hdd_debug("Number of Bcn Req Ie fields: %d", pEseBcnReq->numBcnReqIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002582
2583 for (j = 0; j < (pEseBcnReq->numBcnReqIe); j++) {
2584 for (i = 0; i < 4; i++) {
2585 /*
2586 * inPtr pointing to the beginning of 1st space
2587 * after number of ie fields
2588 */
2589 inPtr = strpbrk(inPtr, " ");
2590 /* no ie data after the number of ie fields argument */
2591 if (NULL == inPtr)
2592 return -EINVAL;
2593
2594 /* remove empty space */
2595 while ((SPACE_ASCII_VALUE == *inPtr)
2596 && ('\0' != *inPtr))
2597 inPtr++;
2598
2599 /*
2600 * no ie data after the number of ie fields
2601 * argument and spaces
2602 */
2603 if ('\0' == *inPtr)
2604 return -EINVAL;
2605
2606 v = sscanf(inPtr, "%31s ", buf);
2607 if (1 != v)
2608 return -EINVAL;
2609
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002610 v = kstrtou32(buf, 10, &tempInt);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002611 if (v < 0)
2612 return -EINVAL;
2613
2614 switch (i) {
2615 case 0: /* Measurement token */
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002616 if (!tempInt) {
2617 hdd_err("Invalid Measurement Token: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002618 tempInt);
2619 return -EINVAL;
2620 }
2621 pEseBcnReq->bcnReq[j].measurementToken =
2622 tempInt;
2623 break;
2624
2625 case 1: /* Channel number */
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002626 if (!tempInt ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002627 (tempInt >
2628 WNI_CFG_CURRENT_CHANNEL_STAMAX)) {
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002629 hdd_err("Invalid Channel Number: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002630 tempInt);
2631 return -EINVAL;
2632 }
2633 pEseBcnReq->bcnReq[j].channel = tempInt;
2634 break;
2635
2636 case 2: /* Scan mode */
2637 if ((tempInt < eSIR_PASSIVE_SCAN)
2638 || (tempInt > eSIR_BEACON_TABLE)) {
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002639 hdd_err("Invalid Scan Mode: %u Expected{0|1|2}",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002640 tempInt);
2641 return -EINVAL;
2642 }
2643 pEseBcnReq->bcnReq[j].scanMode = tempInt;
2644 break;
2645
2646 case 3: /* Measurement duration */
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002647 if ((!tempInt
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002648 && (pEseBcnReq->bcnReq[j].scanMode !=
2649 eSIR_BEACON_TABLE)) ||
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002650 (pEseBcnReq->bcnReq[j].scanMode ==
2651 eSIR_BEACON_TABLE)) {
2652 hdd_err("Invalid Measurement Duration: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002653 tempInt);
2654 return -EINVAL;
2655 }
2656 pEseBcnReq->bcnReq[j].measurementDuration =
2657 tempInt;
2658 break;
2659 }
2660 }
2661 }
2662
2663 for (j = 0; j < pEseBcnReq->numBcnReqIe; j++) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002664 hdd_debug("Index: %d Measurement Token: %u Channel: %u Scan Mode: %u Measurement Duration: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002665 j,
2666 pEseBcnReq->bcnReq[j].measurementToken,
2667 pEseBcnReq->bcnReq[j].channel,
2668 pEseBcnReq->bcnReq[j].scanMode,
2669 pEseBcnReq->bcnReq[j].measurementDuration);
2670 }
2671
2672 return 0;
2673}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002674
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002675/**
2676 * hdd_parse_get_cckm_ie() - HDD Parse and fetch the CCKM IE
2677 * @pValue: Pointer to input data
2678 * @pCckmIe: Pointer to output cckm Ie
2679 * @pCckmIeLen: Pointer to output cckm ie length
2680 *
2681 * This function parses the SETCCKM IE command
2682 * SETCCKMIE<space><ie data>
2683 *
2684 * Return: 0 for success non-zero for failure
2685 */
2686static int hdd_parse_get_cckm_ie(uint8_t *pValue, uint8_t **pCckmIe,
2687 uint8_t *pCckmIeLen)
2688{
2689 uint8_t *inPtr = pValue;
2690 uint8_t *dataEnd;
2691 int j = 0;
2692 int i = 0;
2693 uint8_t tempByte = 0;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002694
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002695 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2696 /* no argument after the command */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002697 if (NULL == inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002698 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002699 else if (SPACE_ASCII_VALUE != *inPtr) /* no space after the command */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002700 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002701
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002702 /* remove empty spaces */
2703 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2704 inPtr++;
2705 /* no argument followed by spaces */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002706 if ('\0' == *inPtr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002707 return -EINVAL;
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002708
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002709 /* find the length of data */
2710 dataEnd = inPtr;
2711 while (('\0' != *dataEnd)) {
2712 dataEnd++;
2713 ++(*pCckmIeLen);
2714 }
2715 if (*pCckmIeLen <= 0)
2716 return -EINVAL;
2717 /*
2718 * Allocate the number of bytes based on the number of input characters
2719 * whether it is even or odd.
2720 * if the number of input characters are even, then we need N / 2 byte.
2721 * if the number of input characters are odd, then we need do
2722 * (N + 1) / 2 to compensate rounding off.
2723 * For example, if N = 18, then (18 + 1) / 2 = 9 bytes are enough.
2724 * If N = 19, then we need 10 bytes, hence (19 + 1) / 2 = 10 bytes
2725 */
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302726 *pCckmIe = qdf_mem_malloc((*pCckmIeLen + 1) / 2);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002727 if (NULL == *pCckmIe) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002728 hdd_err("qdf_mem_malloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002729 return -ENOMEM;
2730 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002731 /*
2732 * the buffer received from the upper layer is character buffer,
2733 * we need to prepare the buffer taking 2 characters in to a U8 hex
2734 * decimal number for example 7f0000f0...form a buffer to contain
2735 * 7f in 0th location, 00 in 1st and f0 in 3rd location
2736 */
2737 for (i = 0, j = 0; j < *pCckmIeLen; j += 2) {
2738 tempByte = (hex_to_bin(inPtr[j]) << 4) |
2739 (hex_to_bin(inPtr[j + 1]));
2740 (*pCckmIe)[i++] = tempByte;
2741 }
2742 *pCckmIeLen = i;
2743 return 0;
2744}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08002745#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002746
2747int wlan_hdd_set_mc_rate(hdd_adapter_t *pAdapter, int targetRate)
2748{
2749 tSirRateUpdateInd rateUpdate = {0};
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302750 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002751 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
2752 struct hdd_config *pConfig = NULL;
2753
2754 if (pHddCtx == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002755 hdd_err("HDD context is null");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002756 return -EINVAL;
2757 }
Krunal Sonibe766b02016-03-10 13:00:44 -08002758 if ((QDF_IBSS_MODE != pAdapter->device_mode) &&
2759 (QDF_SAP_MODE != pAdapter->device_mode) &&
2760 (QDF_STA_MODE != pAdapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002761 hdd_err("Received SETMCRATE cmd in invalid mode %s(%d)",
2762 hdd_device_mode_to_string(pAdapter->device_mode),
2763 pAdapter->device_mode);
2764 hdd_err("SETMCRATE cmd is allowed only in STA, IBSS or SOFTAP mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002765 return -EINVAL;
2766 }
2767 pConfig = pHddCtx->config;
2768 rateUpdate.nss = (pConfig->enable2x2 == 0) ? 0 : 1;
2769 rateUpdate.dev_mode = pAdapter->device_mode;
2770 rateUpdate.mcastDataRate24GHz = targetRate;
2771 rateUpdate.mcastDataRate24GHzTxFlag = 1;
2772 rateUpdate.mcastDataRate5GHz = targetRate;
2773 rateUpdate.bcastDataRate = -1;
Anurag Chouhanc5548422016-02-24 18:33:27 +05302774 qdf_copy_macaddr(&rateUpdate.bssid, &pAdapter->macAddressCurrent);
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002775 hdd_debug("MC Target rate %d, mac = %pM, dev_mode %s(%d)",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002776 rateUpdate.mcastDataRate24GHz, rateUpdate.bssid.bytes,
2777 hdd_device_mode_to_string(pAdapter->device_mode),
2778 pAdapter->device_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002779 status = sme_send_rate_update_ind(pHddCtx->hHal, &rateUpdate);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302780 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002781 hdd_err("SETMCRATE failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002782 return -EFAULT;
2783 }
2784 return 0;
2785}
2786
2787static int drv_cmd_p2p_dev_addr(hdd_adapter_t *adapter,
2788 hdd_context_t *hdd_ctx,
2789 uint8_t *command,
2790 uint8_t command_len,
2791 hdd_priv_data_t *priv_data)
2792{
2793 int ret = 0;
2794
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302795 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002796 TRACE_CODE_HDD_P2P_DEV_ADDR_IOCTL,
2797 adapter->sessionId,
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07002798 (unsigned int)(*(hdd_ctx->p2pDeviceAddress.bytes + 2)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002799 << 24 | *(hdd_ctx->p2pDeviceAddress.bytes
2800 + 3) << 16 | *(hdd_ctx->
2801 p2pDeviceAddress.bytes + 4) << 8 |
2802 *(hdd_ctx->p2pDeviceAddress.bytes +
2803 5))));
2804
2805 if (copy_to_user(priv_data->buf, hdd_ctx->p2pDeviceAddress.bytes,
2806 sizeof(tSirMacAddr))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002807 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002808 ret = -EFAULT;
2809 }
2810
2811 return ret;
2812}
2813
2814/**
2815 * drv_cmd_p2p_set_noa() - Handler for P2P_SET_NOA driver command
2816 * @adapter: Adapter on which the command was received
2817 * @hdd_ctx: HDD global context
2818 * @command: Entire driver command received from userspace
2819 * @command_len: Length of @command
2820 * @priv_data: Pointer to ioctl private data structure
2821 *
2822 * This is a trivial command hander function which simply forwards the
2823 * command to the actual command processor within the P2P module.
2824 *
2825 * Return: 0 on success, non-zero on failure
2826 */
2827static int drv_cmd_p2p_set_noa(hdd_adapter_t *adapter,
2828 hdd_context_t *hdd_ctx,
2829 uint8_t *command,
2830 uint8_t command_len,
2831 hdd_priv_data_t *priv_data)
2832{
2833 return hdd_set_p2p_noa(adapter->dev, command);
2834}
2835
2836/**
2837 * drv_cmd_p2p_set_ps() - Handler for P2P_SET_PS driver command
2838 * @adapter: Adapter on which the command was received
2839 * @hdd_ctx: HDD global context
2840 * @command: Entire driver command received from userspace
2841 * @command_len: Length of @command
2842 * @priv_data: Pointer to ioctl private data structure
2843 *
2844 * This is a trivial command hander function which simply forwards the
2845 * command to the actual command processor within the P2P module.
2846 *
2847 * Return: 0 on success, non-zero on failure
2848 */
2849static int drv_cmd_p2p_set_ps(hdd_adapter_t *adapter,
2850 hdd_context_t *hdd_ctx,
2851 uint8_t *command,
2852 uint8_t command_len,
2853 hdd_priv_data_t *priv_data)
2854{
2855 return hdd_set_p2p_opps(adapter->dev, command);
2856}
2857
2858static int drv_cmd_set_band(hdd_adapter_t *adapter,
2859 hdd_context_t *hdd_ctx,
2860 uint8_t *command,
2861 uint8_t command_len,
2862 hdd_priv_data_t *priv_data)
2863{
2864 int ret = 0;
2865
2866 uint8_t *ptr = command;
2867
2868 /* Change band request received */
2869
2870 /*
2871 * First 8 bytes will have "SETBAND " and
2872 * 9 byte will have band setting value
2873 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002874 hdd_debug("SetBandCommand Info comm %s UL %d, TL %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002875 command, priv_data->used_len,
2876 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002877
2878 /* Change band request received */
2879 ret = hdd_set_band_helper(adapter->dev, ptr);
2880
2881 return ret;
2882}
2883
2884static int drv_cmd_set_wmmps(hdd_adapter_t *adapter,
2885 hdd_context_t *hdd_ctx,
2886 uint8_t *command,
2887 uint8_t command_len,
2888 hdd_priv_data_t *priv_data)
2889{
2890 return hdd_wmmps_helper(adapter, command);
2891}
2892
2893static int drv_cmd_country(hdd_adapter_t *adapter,
2894 hdd_context_t *hdd_ctx,
2895 uint8_t *command,
2896 uint8_t command_len,
2897 hdd_priv_data_t *priv_data)
2898{
2899 int ret = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302900 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002901 unsigned long rc;
2902 char *country_code;
2903
2904 country_code = command + 8;
2905
2906 INIT_COMPLETION(adapter->change_country_code);
2907
2908 status = sme_change_country_code(hdd_ctx->hHal,
2909 wlan_hdd_change_country_code_callback,
2910 country_code,
2911 adapter,
2912 hdd_ctx->pcds_context,
2913 eSIR_TRUE,
2914 eSIR_TRUE);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302915 if (status == QDF_STATUS_SUCCESS) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002916 rc = wait_for_completion_timeout(
2917 &adapter->change_country_code,
2918 msecs_to_jiffies(WLAN_WAIT_TIME_COUNTRY));
2919 if (!rc)
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002920 hdd_err("SME while setting country code timed out");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002921 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002922 hdd_err("SME Change Country code fail, status %d",
2923 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002924 ret = -EINVAL;
2925 }
2926
2927 return ret;
2928}
2929
2930static int drv_cmd_set_roam_trigger(hdd_adapter_t *adapter,
2931 hdd_context_t *hdd_ctx,
2932 uint8_t *command,
2933 uint8_t command_len,
2934 hdd_priv_data_t *priv_data)
2935{
2936 int ret = 0;
2937 uint8_t *value = command;
2938 int8_t rssi = 0;
2939 uint8_t lookUpThreshold = CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_DEFAULT;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302940 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002941
2942 /* Move pointer to ahead of SETROAMTRIGGER<delimiter> */
2943 value = value + command_len + 1;
2944
2945 /* Convert the value from ascii to integer */
2946 ret = kstrtos8(value, 10, &rssi);
2947 if (ret < 0) {
2948 /*
2949 * If the input value is greater than max value of datatype,
2950 * then also kstrtou8 fails
2951 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002952 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
2953 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN,
2954 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002955 ret = -EINVAL;
2956 goto exit;
2957 }
2958
2959 lookUpThreshold = abs(rssi);
2960
2961 if ((lookUpThreshold < CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN)
2962 || (lookUpThreshold > CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002963 hdd_err("Neighbor lookup threshold value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002964 lookUpThreshold,
2965 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN,
2966 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX);
2967 ret = -EINVAL;
2968 goto exit;
2969 }
2970
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302971 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002972 TRACE_CODE_HDD_SETROAMTRIGGER_IOCTL,
2973 adapter->sessionId, lookUpThreshold));
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08002974 hdd_debug("Received Command to Set Roam trigger (Neighbor lookup threshold) = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002975 lookUpThreshold);
2976
2977 hdd_ctx->config->nNeighborLookupRssiThreshold = lookUpThreshold;
2978 status = sme_set_neighbor_lookup_rssi_threshold(hdd_ctx->hHal,
2979 adapter->sessionId,
2980 lookUpThreshold);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302981 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002982 hdd_err("Failed to set roam trigger, try again");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002983 ret = -EPERM;
2984 goto exit;
2985 }
2986
2987exit:
2988 return ret;
2989}
2990
2991static int drv_cmd_get_roam_trigger(hdd_adapter_t *adapter,
2992 hdd_context_t *hdd_ctx,
2993 uint8_t *command,
2994 uint8_t command_len,
2995 hdd_priv_data_t *priv_data)
2996{
2997 int ret = 0;
2998 uint8_t lookUpThreshold =
2999 sme_get_neighbor_lookup_rssi_threshold(hdd_ctx->hHal);
3000 int rssi = (-1) * lookUpThreshold;
3001 char extra[32];
3002 uint8_t len = 0;
3003
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303004 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003005 TRACE_CODE_HDD_GETROAMTRIGGER_IOCTL,
3006 adapter->sessionId, lookUpThreshold));
3007
3008 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303009 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003010 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003011 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003012 ret = -EFAULT;
3013 }
3014
3015 return ret;
3016}
3017
3018static int drv_cmd_set_roam_scan_period(hdd_adapter_t *adapter,
3019 hdd_context_t *hdd_ctx,
3020 uint8_t *command,
3021 uint8_t command_len,
3022 hdd_priv_data_t *priv_data)
3023{
3024 int ret = 0;
3025 uint8_t *value = command;
3026 uint8_t roamScanPeriod = 0;
3027 uint16_t neighborEmptyScanRefreshPeriod =
3028 CFG_EMPTY_SCAN_REFRESH_PERIOD_DEFAULT;
3029
3030 /* input refresh period is in terms of seconds */
3031
3032 /* Move pointer to ahead of SETROAMSCANPERIOD<delimiter> */
3033 value = value + command_len + 1;
3034
3035 /* Convert the value from ascii to integer */
3036 ret = kstrtou8(value, 10, &roamScanPeriod);
3037 if (ret < 0) {
3038 /*
3039 * If the input value is greater than max value of datatype,
3040 * then also kstrtou8 fails
3041 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003042 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
3043 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000),
3044 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003045 ret = -EINVAL;
3046 goto exit;
3047 }
3048
3049 if ((roamScanPeriod < (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000))
3050 || (roamScanPeriod > (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003051 hdd_err("Roam scan period value %d is out of range (Min: %d Max: %d)",
3052 roamScanPeriod,
3053 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000),
3054 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003055 ret = -EINVAL;
3056 goto exit;
3057 }
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303058 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003059 TRACE_CODE_HDD_SETROAMSCANPERIOD_IOCTL,
3060 adapter->sessionId, roamScanPeriod));
3061 neighborEmptyScanRefreshPeriod = roamScanPeriod * 1000;
3062
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003063 hdd_debug("Received Command to Set roam scan period (Empty Scan refresh period) = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003064 roamScanPeriod);
3065
3066 hdd_ctx->config->nEmptyScanRefreshPeriod =
3067 neighborEmptyScanRefreshPeriod;
3068 sme_update_empty_scan_refresh_period(hdd_ctx->hHal,
3069 adapter->sessionId,
3070 neighborEmptyScanRefreshPeriod);
3071
3072exit:
3073 return ret;
3074}
3075
3076static int drv_cmd_get_roam_scan_period(hdd_adapter_t *adapter,
3077 hdd_context_t *hdd_ctx,
3078 uint8_t *command,
3079 uint8_t command_len,
3080 hdd_priv_data_t *priv_data)
3081{
3082 int ret = 0;
3083 uint16_t nEmptyScanRefreshPeriod =
3084 sme_get_empty_scan_refresh_period(hdd_ctx->hHal);
3085 char extra[32];
3086 uint8_t len = 0;
3087
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303088 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003089 TRACE_CODE_HDD_GETROAMSCANPERIOD_IOCTL,
3090 adapter->sessionId,
3091 nEmptyScanRefreshPeriod));
3092 len = scnprintf(extra, sizeof(extra), "%s %d",
3093 "GETROAMSCANPERIOD",
3094 (nEmptyScanRefreshPeriod / 1000));
3095 /* Returned value is in units of seconds */
Anurag Chouhan6d760662016-02-20 16:05:43 +05303096 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003097 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003098 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003099 ret = -EFAULT;
3100 }
3101
3102 return ret;
3103}
3104
3105static int drv_cmd_set_roam_scan_refresh_period(hdd_adapter_t *adapter,
3106 hdd_context_t *hdd_ctx,
3107 uint8_t *command,
3108 uint8_t command_len,
3109 hdd_priv_data_t *priv_data)
3110{
3111 int ret = 0;
3112 uint8_t *value = command;
3113 uint8_t roamScanRefreshPeriod = 0;
3114 uint16_t neighborScanRefreshPeriod =
3115 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_DEFAULT;
3116
3117 /* input refresh period is in terms of seconds */
3118 /* Move pointer to ahead of SETROAMSCANREFRESHPERIOD<delimiter> */
3119 value = value + command_len + 1;
3120
3121 /* Convert the value from ascii to integer */
3122 ret = kstrtou8(value, 10, &roamScanRefreshPeriod);
3123 if (ret < 0) {
3124 /*
3125 * If the input value is greater than max value of datatype,
3126 * then also kstrtou8 fails
3127 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003128 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
3129 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN / 1000,
3130 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX / 1000);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003131 ret = -EINVAL;
3132 goto exit;
3133 }
3134
3135 if ((roamScanRefreshPeriod <
3136 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN / 1000))
3137 || (roamScanRefreshPeriod >
3138 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX / 1000))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003139 hdd_err("Neighbor scan results refresh period value %d is out of range (Min: %d Max: %d)",
3140 roamScanRefreshPeriod,
3141 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN
3142 / 1000),
3143 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX
3144 / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003145 ret = -EINVAL;
3146 goto exit;
3147 }
3148 neighborScanRefreshPeriod = roamScanRefreshPeriod * 1000;
3149
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003150 hdd_debug("Received Command to Set roam scan refresh period (Scan refresh period) = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003151 roamScanRefreshPeriod);
3152
3153 hdd_ctx->config->nNeighborResultsRefreshPeriod =
3154 neighborScanRefreshPeriod;
3155 sme_set_neighbor_scan_refresh_period(hdd_ctx->hHal,
3156 adapter->sessionId,
3157 neighborScanRefreshPeriod);
3158
3159exit:
3160 return ret;
3161}
3162
3163static int drv_cmd_get_roam_scan_refresh_period(hdd_adapter_t *adapter,
3164 hdd_context_t *hdd_ctx,
3165 uint8_t *command,
3166 uint8_t command_len,
3167 hdd_priv_data_t *priv_data)
3168{
3169 int ret = 0;
3170 uint16_t value =
3171 sme_get_neighbor_scan_refresh_period(hdd_ctx->hHal);
3172 char extra[32];
3173 uint8_t len = 0;
3174
3175 len = scnprintf(extra, sizeof(extra), "%s %d",
3176 "GETROAMSCANREFRESHPERIOD",
3177 (value / 1000));
3178 /* Returned value is in units of seconds */
Anurag Chouhan6d760662016-02-20 16:05:43 +05303179 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003180 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003181 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003182 ret = -EFAULT;
3183 }
3184
3185 return ret;
3186}
3187
3188static int drv_cmd_set_roam_mode(hdd_adapter_t *adapter,
3189 hdd_context_t *hdd_ctx,
3190 uint8_t *command,
3191 uint8_t command_len,
3192 hdd_priv_data_t *priv_data)
3193{
3194 int ret = 0;
3195 uint8_t *value = command;
3196 uint8_t roamMode = CFG_LFR_FEATURE_ENABLED_DEFAULT;
3197
Deepak Dhamdherea2785822016-11-17 01:17:45 -08003198 if (!adapter->fast_roaming_allowed) {
3199 hdd_err("Roaming is always disabled on this interface");
3200 goto exit;
3201 }
3202
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003203 /* Move pointer to ahead of SETROAMMODE<delimiter> */
3204 value = value + SIZE_OF_SETROAMMODE + 1;
3205
3206 /* Convert the value from ascii to integer */
3207 ret = kstrtou8(value, SIZE_OF_SETROAMMODE, &roamMode);
3208 if (ret < 0) {
3209 /*
3210 * If the input value is greater than max value of datatype,
3211 * then also kstrtou8 fails
3212 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003213 hdd_err("kstrtou8 failed range [%d - %d]",
3214 CFG_LFR_FEATURE_ENABLED_MIN,
3215 CFG_LFR_FEATURE_ENABLED_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003216 ret = -EINVAL;
3217 goto exit;
3218 }
3219 if ((roamMode < CFG_LFR_FEATURE_ENABLED_MIN) ||
3220 (roamMode > CFG_LFR_FEATURE_ENABLED_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003221 hdd_err("Roam Mode value %d is out of range (Min: %d Max: %d)",
3222 roamMode,
3223 CFG_LFR_FEATURE_ENABLED_MIN,
3224 CFG_LFR_FEATURE_ENABLED_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003225 ret = -EINVAL;
3226 goto exit;
3227 }
3228
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003229 hdd_debug("Received Command to Set Roam Mode = %d",
3230 roamMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003231 /*
3232 * Note that
3233 * SETROAMMODE 0 is to enable LFR while
3234 * SETROAMMODE 1 is to disable LFR, but
3235 * notify_is_fast_roam_ini_feature_enabled 0/1 is to
3236 * enable/disable. So, we have to invert the value
3237 * to call sme_update_is_fast_roam_ini_feature_enabled.
3238 */
3239 if (CFG_LFR_FEATURE_ENABLED_MIN == roamMode)
3240 roamMode = CFG_LFR_FEATURE_ENABLED_MAX; /* Roam enable */
3241 else
3242 roamMode = CFG_LFR_FEATURE_ENABLED_MIN; /* Roam disable */
3243
3244 hdd_ctx->config->isFastRoamIniFeatureEnabled = roamMode;
3245 if (roamMode) {
3246 hdd_ctx->config->isRoamOffloadScanEnabled = roamMode;
3247 sme_update_roam_scan_offload_enabled(
3248 (tHalHandle)(hdd_ctx->hHal),
3249 hdd_ctx->config->isRoamOffloadScanEnabled);
3250 sme_update_is_fast_roam_ini_feature_enabled(
3251 hdd_ctx->hHal,
3252 adapter->sessionId,
3253 roamMode);
3254 } else {
3255 sme_update_is_fast_roam_ini_feature_enabled(
3256 hdd_ctx->hHal,
3257 adapter->sessionId,
3258 roamMode);
3259 hdd_ctx->config->isRoamOffloadScanEnabled = roamMode;
3260 sme_update_roam_scan_offload_enabled(
3261 (tHalHandle)(hdd_ctx->hHal),
3262 hdd_ctx->config->isRoamOffloadScanEnabled);
3263 }
3264
3265
3266exit:
3267 return ret;
3268}
3269
3270static int drv_cmd_get_roam_mode(hdd_adapter_t *adapter,
3271 hdd_context_t *hdd_ctx,
3272 uint8_t *command,
3273 uint8_t command_len,
3274 hdd_priv_data_t *priv_data)
3275{
3276 int ret = 0;
3277 bool roamMode = sme_get_is_lfr_feature_enabled(hdd_ctx->hHal);
3278 char extra[32];
3279 uint8_t len = 0;
3280
3281 /*
3282 * roamMode value shall be inverted because the sementics is different.
3283 */
3284 if (CFG_LFR_FEATURE_ENABLED_MIN == roamMode)
3285 roamMode = CFG_LFR_FEATURE_ENABLED_MAX;
3286 else
3287 roamMode = CFG_LFR_FEATURE_ENABLED_MIN;
3288
3289 len = scnprintf(extra, sizeof(extra), "%s %d", command, roamMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303290 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003291 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003292 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003293 ret = -EFAULT;
3294 }
3295
3296 return ret;
3297}
3298
3299static int drv_cmd_set_roam_delta(hdd_adapter_t *adapter,
3300 hdd_context_t *hdd_ctx,
3301 uint8_t *command,
3302 uint8_t command_len,
3303 hdd_priv_data_t *priv_data)
3304{
3305 int ret = 0;
3306 uint8_t *value = command;
3307 uint8_t roamRssiDiff = CFG_ROAM_RSSI_DIFF_DEFAULT;
3308
3309 /* Move pointer to ahead of SETROAMDELTA<delimiter> */
3310 value = value + command_len + 1;
3311
3312 /* Convert the value from ascii to integer */
3313 ret = kstrtou8(value, 10, &roamRssiDiff);
3314 if (ret < 0) {
3315 /*
3316 * If the input value is greater than max value of datatype,
3317 * then also kstrtou8 fails
3318 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003319 hdd_err("kstrtou8 failed range [%d - %d]",
3320 CFG_ROAM_RSSI_DIFF_MIN,
3321 CFG_ROAM_RSSI_DIFF_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003322 ret = -EINVAL;
3323 goto exit;
3324 }
3325
3326 if ((roamRssiDiff < CFG_ROAM_RSSI_DIFF_MIN) ||
3327 (roamRssiDiff > CFG_ROAM_RSSI_DIFF_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003328 hdd_err("Roam rssi diff value %d is out of range (Min: %d Max: %d)",
3329 roamRssiDiff,
3330 CFG_ROAM_RSSI_DIFF_MIN,
3331 CFG_ROAM_RSSI_DIFF_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003332 ret = -EINVAL;
3333 goto exit;
3334 }
3335
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003336 hdd_debug("Received Command to Set roam rssi diff = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003337 roamRssiDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003338
3339 hdd_ctx->config->RoamRssiDiff = roamRssiDiff;
3340 sme_update_roam_rssi_diff(hdd_ctx->hHal,
3341 adapter->sessionId,
3342 roamRssiDiff);
3343
3344exit:
3345 return ret;
3346}
3347
3348static int drv_cmd_get_roam_delta(hdd_adapter_t *adapter,
3349 hdd_context_t *hdd_ctx,
3350 uint8_t *command,
3351 uint8_t command_len,
3352 hdd_priv_data_t *priv_data)
3353{
3354 int ret = 0;
3355 uint8_t roamRssiDiff =
3356 sme_get_roam_rssi_diff(hdd_ctx->hHal);
3357 char extra[32];
3358 uint8_t len = 0;
3359
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303360 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003361 TRACE_CODE_HDD_GETROAMDELTA_IOCTL,
3362 adapter->sessionId, roamRssiDiff));
3363
3364 len = scnprintf(extra, sizeof(extra), "%s %d",
3365 command, roamRssiDiff);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303366 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003367
3368 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003369 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003370 ret = -EFAULT;
3371 }
3372
3373 return ret;
3374}
3375
3376static int drv_cmd_get_band(hdd_adapter_t *adapter,
3377 hdd_context_t *hdd_ctx,
3378 uint8_t *command,
3379 uint8_t command_len,
3380 hdd_priv_data_t *priv_data)
3381{
3382 int ret = 0;
3383 int band = -1;
3384 char extra[32];
3385 uint8_t len = 0;
3386
3387 hdd_get_band_helper(hdd_ctx, &band);
3388
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303389 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003390 TRACE_CODE_HDD_GETBAND_IOCTL,
3391 adapter->sessionId, band));
3392
3393 len = scnprintf(extra, sizeof(extra), "%s %d", command, band);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303394 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003395
3396 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003397 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003398 ret = -EFAULT;
3399 }
3400
3401 return ret;
3402}
3403
3404static int drv_cmd_set_roam_scan_channels(hdd_adapter_t *adapter,
3405 hdd_context_t *hdd_ctx,
3406 uint8_t *command,
3407 uint8_t command_len,
3408 hdd_priv_data_t *priv_data)
3409{
3410 return hdd_parse_set_roam_scan_channels(adapter, command);
3411}
3412
3413static int drv_cmd_get_roam_scan_channels(hdd_adapter_t *adapter,
3414 hdd_context_t *hdd_ctx,
3415 uint8_t *command,
3416 uint8_t command_len,
3417 hdd_priv_data_t *priv_data)
3418{
3419 int ret = 0;
3420 uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
3421 uint8_t numChannels = 0;
3422 uint8_t j = 0;
3423 char extra[128] = { 0 };
3424 int len;
3425
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303426 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003427 sme_get_roam_scan_channel_list(hdd_ctx->hHal,
3428 ChannelList,
3429 &numChannels,
3430 adapter->sessionId)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003431 hdd_err("failed to get roam scan channel list");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003432 ret = -EFAULT;
3433 goto exit;
3434 }
3435
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303436 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003437 TRACE_CODE_HDD_GETROAMSCANCHANNELS_IOCTL,
3438 adapter->sessionId, numChannels));
3439 /*
3440 * output channel list is of the format
3441 * [Number of roam scan channels][Channel1][Channel2]...
3442 * copy the number of channels in the 0th index
3443 */
3444 len = scnprintf(extra, sizeof(extra), "%s %d", command,
3445 numChannels);
Selvaraj, Sridhar5cc4af42016-10-19 10:41:59 +05303446 for (j = 0; (j < numChannels) && len <= sizeof(extra); j++)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003447 len += scnprintf(extra + len, sizeof(extra) - len,
3448 " %d", ChannelList[j]);
3449
Anurag Chouhan6d760662016-02-20 16:05:43 +05303450 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003451 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003452 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003453 ret = -EFAULT;
3454 goto exit;
3455 }
3456
3457exit:
3458 return ret;
3459}
3460
3461static int drv_cmd_get_ccx_mode(hdd_adapter_t *adapter,
3462 hdd_context_t *hdd_ctx,
3463 uint8_t *command,
3464 uint8_t command_len,
3465 hdd_priv_data_t *priv_data)
3466{
3467 int ret = 0;
3468 bool eseMode = sme_get_is_ese_feature_enabled(hdd_ctx->hHal);
3469 char extra[32];
3470 uint8_t len = 0;
3471
3472 /*
3473 * Check if the features OKC/ESE/11R are supported simultaneously,
3474 * then this operation is not permitted (return FAILURE)
3475 */
3476 if (eseMode &&
3477 hdd_is_okc_mode_enabled(hdd_ctx) &&
3478 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003479 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003480 ret = -EPERM;
3481 goto exit;
3482 }
3483
3484 len = scnprintf(extra, sizeof(extra), "%s %d",
3485 "GETCCXMODE", eseMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303486 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003487 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003488 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003489 ret = -EFAULT;
3490 goto exit;
3491 }
3492
3493exit:
3494 return ret;
3495}
3496
3497static int drv_cmd_get_okc_mode(hdd_adapter_t *adapter,
3498 hdd_context_t *hdd_ctx,
3499 uint8_t *command,
3500 uint8_t command_len,
3501 hdd_priv_data_t *priv_data)
3502{
3503 int ret = 0;
3504 bool okcMode = hdd_is_okc_mode_enabled(hdd_ctx);
3505 char extra[32];
3506 uint8_t len = 0;
3507
3508 /*
3509 * Check if the features OKC/ESE/11R are supported simultaneously,
3510 * then this operation is not permitted (return FAILURE)
3511 */
3512 if (okcMode &&
3513 sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
3514 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003515 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003516 ret = -EPERM;
3517 goto exit;
3518 }
3519
3520 len = scnprintf(extra, sizeof(extra), "%s %d",
3521 "GETOKCMODE", okcMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303522 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003523
3524 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003525 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003526 ret = -EFAULT;
3527 goto exit;
3528 }
3529
3530exit:
3531 return ret;
3532}
3533
3534static int drv_cmd_get_fast_roam(hdd_adapter_t *adapter,
3535 hdd_context_t *hdd_ctx,
3536 uint8_t *command,
3537 uint8_t command_len,
3538 hdd_priv_data_t *priv_data)
3539{
3540 int ret = 0;
3541 bool lfrMode = sme_get_is_lfr_feature_enabled(hdd_ctx->hHal);
3542 char extra[32];
3543 uint8_t len = 0;
3544
3545 len = scnprintf(extra, sizeof(extra), "%s %d",
3546 "GETFASTROAM", lfrMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303547 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003548
3549 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003550 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003551 ret = -EFAULT;
3552 }
3553
3554 return ret;
3555}
3556
3557static int drv_cmd_get_fast_transition(hdd_adapter_t *adapter,
3558 hdd_context_t *hdd_ctx,
3559 uint8_t *command,
3560 uint8_t command_len,
3561 hdd_priv_data_t *priv_data)
3562{
3563 int ret = 0;
3564 bool ft = sme_get_is_ft_feature_enabled(hdd_ctx->hHal);
3565 char extra[32];
3566 uint8_t len = 0;
3567
3568 len = scnprintf(extra, sizeof(extra), "%s %d",
3569 "GETFASTTRANSITION", ft);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303570 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003571
3572 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003573 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003574 ret = -EFAULT;
3575 }
3576
3577 return ret;
3578}
3579
3580static int drv_cmd_set_roam_scan_channel_min_time(hdd_adapter_t *adapter,
3581 hdd_context_t *hdd_ctx,
3582 uint8_t *command,
3583 uint8_t command_len,
3584 hdd_priv_data_t *priv_data)
3585{
3586 int ret = 0;
3587 uint8_t *value = command;
3588 uint8_t minTime = CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_DEFAULT;
3589
3590 /* Move pointer to ahead of SETROAMSCANCHANNELMINTIME<delimiter> */
3591 value = value + command_len + 1;
3592
3593 /* Convert the value from ascii to integer */
3594 ret = kstrtou8(value, 10, &minTime);
3595 if (ret < 0) {
3596 /*
3597 * If the input value is greater than max value of datatype,
3598 * then also kstrtou8 fails
3599 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003600 hdd_err("kstrtou8 failed range [%d - %d]",
3601 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN,
3602 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003603 ret = -EINVAL;
3604 goto exit;
3605 }
3606
3607 if ((minTime < CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN) ||
3608 (minTime > CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003609 hdd_err("scan min channel time value %d is out of range (Min: %d Max: %d)",
3610 minTime,
3611 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN,
3612 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003613 ret = -EINVAL;
3614 goto exit;
3615 }
3616
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303617 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003618 TRACE_CODE_HDD_SETROAMSCANCHANNELMINTIME_IOCTL,
3619 adapter->sessionId, minTime));
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003620 hdd_debug("Received Command to change channel min time = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003621 minTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003622
3623 hdd_ctx->config->nNeighborScanMinChanTime = minTime;
3624 sme_set_neighbor_scan_min_chan_time(hdd_ctx->hHal,
3625 minTime,
3626 adapter->sessionId);
3627
3628exit:
3629 return ret;
3630}
3631
3632static int drv_cmd_send_action_frame(hdd_adapter_t *adapter,
3633 hdd_context_t *hdd_ctx,
3634 uint8_t *command,
3635 uint8_t command_len,
3636 hdd_priv_data_t *priv_data)
3637{
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07003638 return hdd_parse_sendactionframe(adapter, command,
3639 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003640}
3641
3642static int drv_cmd_get_roam_scan_channel_min_time(hdd_adapter_t *adapter,
3643 hdd_context_t *hdd_ctx,
3644 uint8_t *command,
3645 uint8_t command_len,
3646 hdd_priv_data_t *priv_data)
3647{
3648 int ret = 0;
3649 uint16_t val = sme_get_neighbor_scan_min_chan_time(hdd_ctx->hHal,
3650 adapter->sessionId);
3651 char extra[32];
3652 uint8_t len = 0;
3653
3654 /* value is interms of msec */
3655 len = scnprintf(extra, sizeof(extra), "%s %d",
3656 "GETROAMSCANCHANNELMINTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303657 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003658
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303659 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003660 TRACE_CODE_HDD_GETROAMSCANCHANNELMINTIME_IOCTL,
3661 adapter->sessionId, val));
3662
3663 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003664 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003665 ret = -EFAULT;
3666 }
3667
3668 return ret;
3669}
3670
3671static int drv_cmd_set_scan_channel_time(hdd_adapter_t *adapter,
3672 hdd_context_t *hdd_ctx,
3673 uint8_t *command,
3674 uint8_t command_len,
3675 hdd_priv_data_t *priv_data)
3676{
3677 int ret = 0;
3678 uint8_t *value = command;
3679 uint16_t maxTime = CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_DEFAULT;
3680
3681 /* Move pointer to ahead of SETSCANCHANNELTIME<delimiter> */
3682 value = value + command_len + 1;
3683
3684 /* Convert the value from ascii to integer */
3685 ret = kstrtou16(value, 10, &maxTime);
3686 if (ret < 0) {
3687 /*
3688 * If the input value is greater than max value of datatype,
3689 * then also kstrtou8 fails
3690 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003691 hdd_err("kstrtou16 failed range [%d - %d]",
3692 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN,
3693 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003694 ret = -EINVAL;
3695 goto exit;
3696 }
3697
3698 if ((maxTime < CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN) ||
3699 (maxTime > CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003700 hdd_err("lfr mode value %d is out of range (Min: %d Max: %d)",
3701 maxTime,
3702 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN,
3703 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003704 ret = -EINVAL;
3705 goto exit;
3706 }
3707
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003708 hdd_debug("Received Command to change channel max time = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003709 maxTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003710
3711 hdd_ctx->config->nNeighborScanMaxChanTime = maxTime;
3712 sme_set_neighbor_scan_max_chan_time(hdd_ctx->hHal,
3713 adapter->sessionId,
3714 maxTime);
3715
3716exit:
3717 return ret;
3718}
3719
3720static int drv_cmd_get_scan_channel_time(hdd_adapter_t *adapter,
3721 hdd_context_t *hdd_ctx,
3722 uint8_t *command,
3723 uint8_t command_len,
3724 hdd_priv_data_t *priv_data)
3725{
3726 int ret = 0;
3727 uint16_t val = sme_get_neighbor_scan_max_chan_time(hdd_ctx->hHal,
3728 adapter->sessionId);
3729 char extra[32];
3730 uint8_t len = 0;
3731
3732 /* value is interms of msec */
3733 len = scnprintf(extra, sizeof(extra), "%s %d",
3734 "GETSCANCHANNELTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303735 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003736
3737 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003738 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003739 ret = -EFAULT;
3740 }
3741
3742 return ret;
3743}
3744
3745static int drv_cmd_set_scan_home_time(hdd_adapter_t *adapter,
3746 hdd_context_t *hdd_ctx,
3747 uint8_t *command,
3748 uint8_t command_len,
3749 hdd_priv_data_t *priv_data)
3750{
3751 int ret = 0;
3752 uint8_t *value = command;
3753 uint16_t val = CFG_NEIGHBOR_SCAN_TIMER_PERIOD_DEFAULT;
3754
3755 /* Move pointer to ahead of SETSCANHOMETIME<delimiter> */
3756 value = value + command_len + 1;
3757
3758 /* Convert the value from ascii to integer */
3759 ret = kstrtou16(value, 10, &val);
3760 if (ret < 0) {
3761 /*
3762 * If the input value is greater than max value of datatype,
3763 * then also kstrtou8 fails
3764 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003765 hdd_err("kstrtou16 failed range [%d - %d]",
3766 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN,
3767 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003768 ret = -EINVAL;
3769 goto exit;
3770 }
3771
3772 if ((val < CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN) ||
3773 (val > CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003774 hdd_err("scan home time value %d is out of range (Min: %d Max: %d)",
3775 val,
3776 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN,
3777 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003778 ret = -EINVAL;
3779 goto exit;
3780 }
3781
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003782 hdd_debug("Received Command to change scan home time = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003783 val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003784
3785 hdd_ctx->config->nNeighborScanPeriod = val;
3786 sme_set_neighbor_scan_period(hdd_ctx->hHal,
3787 adapter->sessionId, val);
3788
3789exit:
3790 return ret;
3791}
3792
3793static int drv_cmd_get_scan_home_time(hdd_adapter_t *adapter,
3794 hdd_context_t *hdd_ctx,
3795 uint8_t *command,
3796 uint8_t command_len,
3797 hdd_priv_data_t *priv_data)
3798{
3799 int ret = 0;
3800 uint16_t val = sme_get_neighbor_scan_period(hdd_ctx->hHal,
3801 adapter->
3802 sessionId);
3803 char extra[32];
3804 uint8_t len = 0;
3805
3806 /* value is interms of msec */
3807 len = scnprintf(extra, sizeof(extra), "%s %d",
3808 "GETSCANHOMETIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303809 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003810
3811 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003812 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003813 ret = -EFAULT;
3814 }
3815
3816 return ret;
3817}
3818
3819static int drv_cmd_set_roam_intra_band(hdd_adapter_t *adapter,
3820 hdd_context_t *hdd_ctx,
3821 uint8_t *command,
3822 uint8_t command_len,
3823 hdd_priv_data_t *priv_data)
3824{
3825 int ret = 0;
3826 uint8_t *value = command;
3827 uint8_t val = CFG_ROAM_INTRA_BAND_DEFAULT;
3828
3829 /* Move pointer to ahead of SETROAMINTRABAND<delimiter> */
3830 value = value + command_len + 1;
3831
3832 /* Convert the value from ascii to integer */
3833 ret = kstrtou8(value, 10, &val);
3834 if (ret < 0) {
3835 /*
3836 * If the input value is greater than max value of datatype,
3837 * then also kstrtou8 fails
3838 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003839 hdd_err("kstrtou8 failed range [%d - %d]",
3840 CFG_ROAM_INTRA_BAND_MIN,
3841 CFG_ROAM_INTRA_BAND_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003842 ret = -EINVAL;
3843 goto exit;
3844 }
3845
3846 if ((val < CFG_ROAM_INTRA_BAND_MIN) ||
3847 (val > CFG_ROAM_INTRA_BAND_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003848 hdd_err("intra band mode value %d is out of range (Min: %d Max: %d)",
3849 val,
3850 CFG_ROAM_INTRA_BAND_MIN,
3851 CFG_ROAM_INTRA_BAND_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003852 ret = -EINVAL;
3853 goto exit;
3854 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003855 hdd_debug("Received Command to change intra band = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003856 val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003857
3858 hdd_ctx->config->nRoamIntraBand = val;
3859 sme_set_roam_intra_band(hdd_ctx->hHal, val);
3860
3861exit:
3862 return ret;
3863}
3864
3865static int drv_cmd_get_roam_intra_band(hdd_adapter_t *adapter,
3866 hdd_context_t *hdd_ctx,
3867 uint8_t *command,
3868 uint8_t command_len,
3869 hdd_priv_data_t *priv_data)
3870{
3871 int ret = 0;
3872 uint16_t val = sme_get_roam_intra_band(hdd_ctx->hHal);
3873 char extra[32];
3874 uint8_t len = 0;
3875
3876 /* value is interms of msec */
3877 len = scnprintf(extra, sizeof(extra), "%s %d",
3878 "GETROAMINTRABAND", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303879 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003880 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003881 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003882 ret = -EFAULT;
3883 }
3884
3885 return ret;
3886}
3887
3888static int drv_cmd_set_scan_n_probes(hdd_adapter_t *adapter,
3889 hdd_context_t *hdd_ctx,
3890 uint8_t *command,
3891 uint8_t command_len,
3892 hdd_priv_data_t *priv_data)
3893{
3894 int ret = 0;
3895 uint8_t *value = command;
3896 uint8_t nProbes = CFG_ROAM_SCAN_N_PROBES_DEFAULT;
3897
3898 /* Move pointer to ahead of SETSCANNPROBES<delimiter> */
3899 value = value + command_len + 1;
3900
3901 /* Convert the value from ascii to integer */
3902 ret = kstrtou8(value, 10, &nProbes);
3903 if (ret < 0) {
3904 /*
3905 * If the input value is greater than max value of datatype,
3906 * then also kstrtou8 fails
3907 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003908 hdd_err("kstrtou8 failed range [%d - %d]",
3909 CFG_ROAM_SCAN_N_PROBES_MIN,
3910 CFG_ROAM_SCAN_N_PROBES_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003911 ret = -EINVAL;
3912 goto exit;
3913 }
3914
3915 if ((nProbes < CFG_ROAM_SCAN_N_PROBES_MIN) ||
3916 (nProbes > CFG_ROAM_SCAN_N_PROBES_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003917 hdd_err("NProbes value %d is out of range (Min: %d Max: %d)",
3918 nProbes,
3919 CFG_ROAM_SCAN_N_PROBES_MIN,
3920 CFG_ROAM_SCAN_N_PROBES_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003921 ret = -EINVAL;
3922 goto exit;
3923 }
3924
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003925 hdd_debug("Received Command to Set nProbes = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003926 nProbes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003927
3928 hdd_ctx->config->nProbes = nProbes;
3929 sme_update_roam_scan_n_probes(hdd_ctx->hHal,
3930 adapter->sessionId, nProbes);
3931
3932exit:
3933 return ret;
3934}
3935
3936static int drv_cmd_get_scan_n_probes(hdd_adapter_t *adapter,
3937 hdd_context_t *hdd_ctx,
3938 uint8_t *command,
3939 uint8_t command_len,
3940 hdd_priv_data_t *priv_data)
3941{
3942 int ret = 0;
3943 uint8_t val = sme_get_roam_scan_n_probes(hdd_ctx->hHal);
3944 char extra[32];
3945 uint8_t len = 0;
3946
3947 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303948 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003949 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003950 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003951 ret = -EFAULT;
3952 }
3953
3954 return ret;
3955}
3956
3957static int drv_cmd_set_scan_home_away_time(hdd_adapter_t *adapter,
3958 hdd_context_t *hdd_ctx,
3959 uint8_t *command,
3960 uint8_t command_len,
3961 hdd_priv_data_t *priv_data)
3962{
3963 int ret = 0;
3964 uint8_t *value = command;
3965 uint16_t homeAwayTime = CFG_ROAM_SCAN_HOME_AWAY_TIME_DEFAULT;
3966
3967 /* input value is in units of msec */
3968
3969 /* Move pointer to ahead of SETSCANHOMEAWAYTIME<delimiter> */
3970 value = value + command_len + 1;
3971
3972 /* Convert the value from ascii to integer */
3973 ret = kstrtou16(value, 10, &homeAwayTime);
3974 if (ret < 0) {
3975 /*
3976 * If the input value is greater than max value of datatype,
3977 * then also kstrtou8 fails
3978 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003979 hdd_err("kstrtou8 failed range [%d - %d]",
3980 CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN,
3981 CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003982 ret = -EINVAL;
3983 goto exit;
3984 }
3985
3986 if ((homeAwayTime < CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN) ||
3987 (homeAwayTime > CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003988 hdd_err("homeAwayTime value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003989 homeAwayTime,
3990 CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN,
3991 CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX);
3992 ret = -EINVAL;
3993 goto exit;
3994 }
3995
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08003996 hdd_debug("Received Command to Set scan away time = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003997 homeAwayTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003998
3999 if (hdd_ctx->config->nRoamScanHomeAwayTime !=
4000 homeAwayTime) {
4001 hdd_ctx->config->nRoamScanHomeAwayTime = homeAwayTime;
4002 sme_update_roam_scan_home_away_time(hdd_ctx->hHal,
4003 adapter->sessionId,
4004 homeAwayTime,
4005 true);
4006 }
4007
4008exit:
4009 return ret;
4010}
4011
4012static int drv_cmd_get_scan_home_away_time(hdd_adapter_t *adapter,
4013 hdd_context_t *hdd_ctx,
4014 uint8_t *command,
4015 uint8_t command_len,
4016 hdd_priv_data_t *priv_data)
4017{
4018 int ret = 0;
4019 uint16_t val = sme_get_roam_scan_home_away_time(hdd_ctx->hHal);
4020 char extra[32];
4021 uint8_t len = 0;
4022
4023 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304024 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004025
4026 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004027 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004028 ret = -EFAULT;
4029 }
4030
4031 return ret;
4032}
4033
4034static int drv_cmd_reassoc(hdd_adapter_t *adapter,
4035 hdd_context_t *hdd_ctx,
4036 uint8_t *command,
4037 uint8_t command_len,
4038 hdd_priv_data_t *priv_data)
4039{
4040 return hdd_parse_reassoc(adapter, command);
4041}
4042
4043static int drv_cmd_set_wes_mode(hdd_adapter_t *adapter,
4044 hdd_context_t *hdd_ctx,
4045 uint8_t *command,
4046 uint8_t command_len,
4047 hdd_priv_data_t *priv_data)
4048{
4049 int ret = 0;
4050 uint8_t *value = command;
4051 uint8_t wesMode = CFG_ENABLE_WES_MODE_NAME_DEFAULT;
4052
4053 /* Move pointer to ahead of SETWESMODE<delimiter> */
4054 value = value + command_len + 1;
4055
4056 /* Convert the value from ascii to integer */
4057 ret = kstrtou8(value, 10, &wesMode);
4058 if (ret < 0) {
4059 /*
4060 * If the input value is greater than max value of datatype,
4061 * then also kstrtou8 fails
4062 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004063 hdd_err("kstrtou8 failed range [%d - %d]",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004064 CFG_ENABLE_WES_MODE_NAME_MIN,
4065 CFG_ENABLE_WES_MODE_NAME_MAX);
4066 ret = -EINVAL;
4067 goto exit;
4068 }
4069
4070 if ((wesMode < CFG_ENABLE_WES_MODE_NAME_MIN) ||
4071 (wesMode > CFG_ENABLE_WES_MODE_NAME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004072 hdd_err("WES Mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004073 wesMode,
4074 CFG_ENABLE_WES_MODE_NAME_MIN,
4075 CFG_ENABLE_WES_MODE_NAME_MAX);
4076 ret = -EINVAL;
4077 goto exit;
4078 }
4079
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004080 hdd_debug("Received Command to Set WES Mode rssi diff = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004081 wesMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004082
4083 hdd_ctx->config->isWESModeEnabled = wesMode;
4084 sme_update_wes_mode(hdd_ctx->hHal, wesMode, adapter->sessionId);
4085
4086exit:
4087 return ret;
4088}
4089
4090static int drv_cmd_get_wes_mode(hdd_adapter_t *adapter,
4091 hdd_context_t *hdd_ctx,
4092 uint8_t *command,
4093 uint8_t command_len,
4094 hdd_priv_data_t *priv_data)
4095{
4096 int ret = 0;
4097 bool wesMode = sme_get_wes_mode(hdd_ctx->hHal);
4098 char extra[32];
4099 uint8_t len = 0;
4100
4101 len = scnprintf(extra, sizeof(extra), "%s %d", command, wesMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304102 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004103 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004104 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004105 ret = -EFAULT;
4106 }
4107
4108 return ret;
4109}
4110
4111static int drv_cmd_set_opportunistic_rssi_diff(hdd_adapter_t *adapter,
4112 hdd_context_t *hdd_ctx,
4113 uint8_t *command,
4114 uint8_t command_len,
4115 hdd_priv_data_t *priv_data)
4116{
4117 int ret = 0;
4118 uint8_t *value = command;
4119 uint8_t nOpportunisticThresholdDiff =
4120 CFG_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF_DEFAULT;
4121
4122 /* Move pointer to ahead of SETOPPORTUNISTICRSSIDIFF<delimiter> */
4123 value = value + command_len + 1;
4124
4125 /* Convert the value from ascii to integer */
4126 ret = kstrtou8(value, 10, &nOpportunisticThresholdDiff);
4127 if (ret < 0) {
4128 /*
4129 * If the input value is greater than max value of datatype,
4130 * then also kstrtou8 fails
4131 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004132 hdd_err("kstrtou8 failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004133 ret = -EINVAL;
4134 goto exit;
4135 }
4136
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004137 hdd_debug("Received Command to Set Opportunistic Threshold diff = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004138 nOpportunisticThresholdDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004139
4140 sme_set_roam_opportunistic_scan_threshold_diff(hdd_ctx->hHal,
4141 adapter->sessionId,
4142 nOpportunisticThresholdDiff);
4143
4144exit:
4145 return ret;
4146}
4147
4148static int drv_cmd_get_opportunistic_rssi_diff(hdd_adapter_t *adapter,
4149 hdd_context_t *hdd_ctx,
4150 uint8_t *command,
4151 uint8_t command_len,
4152 hdd_priv_data_t *priv_data)
4153{
4154 int ret = 0;
4155 int8_t val = sme_get_roam_opportunistic_scan_threshold_diff(
4156 hdd_ctx->hHal);
4157 char extra[32];
4158 uint8_t len = 0;
4159
4160 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304161 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004162 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004163 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004164 ret = -EFAULT;
4165 }
4166
4167 return ret;
4168}
4169
4170static int drv_cmd_set_roam_rescan_rssi_diff(hdd_adapter_t *adapter,
4171 hdd_context_t *hdd_ctx,
4172 uint8_t *command,
4173 uint8_t command_len,
4174 hdd_priv_data_t *priv_data)
4175{
4176 int ret = 0;
4177 uint8_t *value = command;
4178 uint8_t nRoamRescanRssiDiff = CFG_ROAM_RESCAN_RSSI_DIFF_DEFAULT;
4179
4180 /* Move pointer to ahead of SETROAMRESCANRSSIDIFF<delimiter> */
4181 value = value + command_len + 1;
4182
4183 /* Convert the value from ascii to integer */
4184 ret = kstrtou8(value, 10, &nRoamRescanRssiDiff);
4185 if (ret < 0) {
4186 /*
4187 * If the input value is greater than max value of datatype,
4188 * then also kstrtou8 fails
4189 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004190 hdd_err("kstrtou8 failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004191 ret = -EINVAL;
4192 goto exit;
4193 }
4194
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004195 hdd_debug("Received Command to Set Roam Rescan RSSI Diff = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004196 nRoamRescanRssiDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004197
4198 sme_set_roam_rescan_rssi_diff(hdd_ctx->hHal,
4199 adapter->sessionId,
4200 nRoamRescanRssiDiff);
4201
4202exit:
4203 return ret;
4204}
4205
4206static int drv_cmd_get_roam_rescan_rssi_diff(hdd_adapter_t *adapter,
4207 hdd_context_t *hdd_ctx,
4208 uint8_t *command,
4209 uint8_t command_len,
4210 hdd_priv_data_t *priv_data)
4211{
4212 int ret = 0;
4213 uint8_t val = sme_get_roam_rescan_rssi_diff(hdd_ctx->hHal);
4214 char extra[32];
4215 uint8_t len = 0;
4216
4217 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304218 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004219 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004220 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004221 ret = -EFAULT;
4222 }
4223
4224 return ret;
4225}
4226
4227static int drv_cmd_set_fast_roam(hdd_adapter_t *adapter,
4228 hdd_context_t *hdd_ctx,
4229 uint8_t *command,
4230 uint8_t command_len,
4231 hdd_priv_data_t *priv_data)
4232{
4233 int ret = 0;
4234 uint8_t *value = command;
4235 uint8_t lfrMode = CFG_LFR_FEATURE_ENABLED_DEFAULT;
4236
Deepak Dhamdherea2785822016-11-17 01:17:45 -08004237 if (!adapter->fast_roaming_allowed) {
4238 hdd_err("Roaming is always disabled on this interface");
4239 goto exit;
4240 }
4241
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004242 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4243 value = value + command_len + 1;
4244
4245 /* Convert the value from ascii to integer */
4246 ret = kstrtou8(value, 10, &lfrMode);
4247 if (ret < 0) {
4248 /*
4249 * If the input value is greater than max value of datatype,
4250 * then also kstrtou8 fails
4251 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004252 hdd_err("kstrtou8 failed range [%d - %d]",
4253 CFG_LFR_FEATURE_ENABLED_MIN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004254 CFG_LFR_FEATURE_ENABLED_MAX);
4255 ret = -EINVAL;
4256 goto exit;
4257 }
4258
4259 if ((lfrMode < CFG_LFR_FEATURE_ENABLED_MIN) ||
4260 (lfrMode > CFG_LFR_FEATURE_ENABLED_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004261 hdd_err("lfr mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004262 lfrMode,
4263 CFG_LFR_FEATURE_ENABLED_MIN,
4264 CFG_LFR_FEATURE_ENABLED_MAX);
4265 ret = -EINVAL;
4266 goto exit;
4267 }
4268
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004269 hdd_debug("Received Command to change lfr mode = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004270 lfrMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004271
4272 hdd_ctx->config->isFastRoamIniFeatureEnabled = lfrMode;
4273 sme_update_is_fast_roam_ini_feature_enabled(hdd_ctx->hHal,
4274 adapter->
4275 sessionId,
4276 lfrMode);
4277
4278exit:
4279 return ret;
4280}
4281
4282static int drv_cmd_set_fast_transition(hdd_adapter_t *adapter,
4283 hdd_context_t *hdd_ctx,
4284 uint8_t *command,
4285 uint8_t command_len,
4286 hdd_priv_data_t *priv_data)
4287{
4288 int ret = 0;
4289 uint8_t *value = command;
4290 uint8_t ft = CFG_FAST_TRANSITION_ENABLED_NAME_DEFAULT;
4291
4292 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4293 value = value + command_len + 1;
4294
4295 /* Convert the value from ascii to integer */
4296 ret = kstrtou8(value, 10, &ft);
4297 if (ret < 0) {
4298 /*
4299 * If the input value is greater than max value of datatype,
4300 * then also kstrtou8 fails
4301 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004302 hdd_err("kstrtou8 failed range [%d - %d]",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004303 CFG_FAST_TRANSITION_ENABLED_NAME_MIN,
4304 CFG_FAST_TRANSITION_ENABLED_NAME_MAX);
4305 ret = -EINVAL;
4306 goto exit;
4307 }
4308
4309 if ((ft < CFG_FAST_TRANSITION_ENABLED_NAME_MIN) ||
4310 (ft > CFG_FAST_TRANSITION_ENABLED_NAME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004311 hdd_err("ft mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004312 ft,
4313 CFG_FAST_TRANSITION_ENABLED_NAME_MIN,
4314 CFG_FAST_TRANSITION_ENABLED_NAME_MAX);
4315 ret = -EINVAL;
4316 goto exit;
4317 }
4318
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004319 hdd_debug("Received Command to change ft mode = %d", ft);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004320
4321 hdd_ctx->config->isFastTransitionEnabled = ft;
4322 sme_update_fast_transition_enabled(hdd_ctx->hHal, ft);
4323
4324exit:
4325 return ret;
4326}
4327
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004328static int drv_cmd_fast_reassoc(hdd_adapter_t *adapter,
4329 hdd_context_t *hdd_ctx,
4330 uint8_t *command,
4331 uint8_t command_len,
4332 hdd_priv_data_t *priv_data)
4333{
4334 int ret = 0;
4335 uint8_t *value = command;
4336 uint8_t channel = 0;
4337 tSirMacAddr targetApBssid;
4338 uint32_t roamId = 0;
4339 tCsrRoamModifyProfileFields modProfileFields;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004340 tCsrHandoffRequest handoffInfo;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004341 hdd_station_ctx_t *pHddStaCtx;
4342
Krunal Sonibe766b02016-03-10 13:00:44 -08004343 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004344 hdd_warn("Unsupported in mode %s(%d)",
4345 hdd_device_mode_to_string(adapter->device_mode),
4346 adapter->device_mode);
4347 return -EINVAL;
4348 }
4349
4350 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
4351
4352 /* if not associated, no need to proceed with reassoc */
4353 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004354 hdd_warn("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004355 ret = -EINVAL;
4356 goto exit;
4357 }
4358
4359 ret = hdd_parse_reassoc_command_v1_data(value, targetApBssid,
4360 &channel);
4361 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004362 hdd_err("Failed to parse reassoc command data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004363 goto exit;
4364 }
4365
4366 /*
4367 * if the target bssid is same as currently associated AP,
4368 * issue reassoc to same AP
4369 */
Ankit Guptaa5076012016-09-14 11:32:19 -07004370 if (!qdf_mem_cmp(targetApBssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004371 pHddStaCtx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05304372 QDF_MAC_ADDR_SIZE)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004373 hdd_warn("Reassoc BSSID is same as currently associated AP bssid");
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304374 if (roaming_offload_enabled(hdd_ctx)) {
Naveen Rawat664a7cb2017-01-19 17:58:14 -08004375 hdd_wma_send_fastreassoc_cmd(adapter,
Padma, Santhosh Kumaraf9f08c2016-10-21 21:26:29 +05304376 targetApBssid,
4377 pHddStaCtx->conn_info.operationChannel);
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304378 } else {
4379 sme_get_modify_profile_fields(hdd_ctx->hHal,
4380 adapter->sessionId,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004381 &modProfileFields);
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304382 sme_roam_reassoc(hdd_ctx->hHal, adapter->sessionId,
4383 NULL, modProfileFields, &roamId, 1);
4384 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004385 return 0;
4386 }
4387
Padma, Santhosh Kumaraf9f08c2016-10-21 21:26:29 +05304388 /* Check channel number is a valid channel number */
4389 if (QDF_STATUS_SUCCESS !=
4390 wlan_hdd_validate_operation_channel(adapter, channel)) {
4391 hdd_err("Invalid Channel [%d]", channel);
4392 return -EINVAL;
4393 }
4394
Varun Reddy Yeturud351a6c2016-03-16 14:01:00 -07004395 if (roaming_offload_enabled(hdd_ctx)) {
Naveen Rawat664a7cb2017-01-19 17:58:14 -08004396 hdd_wma_send_fastreassoc_cmd(adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004397 targetApBssid, (int)channel);
4398 goto exit;
4399 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004400 /* Proceed with reassoc */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004401 handoffInfo.channel = channel;
4402 handoffInfo.src = FASTREASSOC;
Varun Reddy Yeturua66f9c52016-02-17 09:58:40 -08004403 qdf_mem_copy(handoffInfo.bssid.bytes, targetApBssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004404 sizeof(tSirMacAddr));
4405 sme_handoff_request(hdd_ctx->hHal, adapter->sessionId,
4406 &handoffInfo);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004407exit:
4408 return ret;
4409}
4410
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004411static int drv_cmd_set_roam_scan_control(hdd_adapter_t *adapter,
4412 hdd_context_t *hdd_ctx,
4413 uint8_t *command,
4414 uint8_t command_len,
4415 hdd_priv_data_t *priv_data)
4416{
4417 int ret = 0;
4418 uint8_t *value = command;
4419 uint8_t roamScanControl = 0;
4420
4421 /* Move pointer to ahead of SETROAMSCANCONTROL<delimiter> */
4422 value = value + command_len + 1;
4423
4424 /* Convert the value from ascii to integer */
4425 ret = kstrtou8(value, 10, &roamScanControl);
4426 if (ret < 0) {
4427 /*
4428 * If the input value is greater than max value of datatype,
4429 * then also kstrtou8 fails
4430 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004431 hdd_err("kstrtou8 failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004432 ret = -EINVAL;
4433 goto exit;
4434 }
4435
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004436 hdd_debug("Received Command to Set roam scan control = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004437 roamScanControl);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004438
4439 if (0 != roamScanControl) {
4440 ret = 0; /* return success but ignore param value "true" */
4441 goto exit;
4442 }
4443
4444 sme_set_roam_scan_control(hdd_ctx->hHal,
4445 adapter->sessionId,
4446 roamScanControl);
4447
4448exit:
4449 return ret;
4450}
4451
4452static int drv_cmd_set_okc_mode(hdd_adapter_t *adapter,
4453 hdd_context_t *hdd_ctx,
4454 uint8_t *command,
4455 uint8_t command_len,
4456 hdd_priv_data_t *priv_data)
4457{
4458 int ret = 0;
4459 uint8_t *value = command;
4460 uint8_t okcMode = CFG_OKC_FEATURE_ENABLED_DEFAULT;
4461
4462 /*
4463 * Check if the features OKC/ESE/11R are supported simultaneously,
4464 * then this operation is not permitted (return FAILURE)
4465 */
4466 if (sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
4467 hdd_is_okc_mode_enabled(hdd_ctx) &&
4468 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004469 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004470 ret = -EPERM;
4471 goto exit;
4472 }
4473
4474 /* Move pointer to ahead of SETOKCMODE<delimiter> */
4475 value = value + command_len + 1;
4476
4477 /* Convert the value from ascii to integer */
4478 ret = kstrtou8(value, 10, &okcMode);
4479 if (ret < 0) {
4480 /*
4481 * If the input value is greater than max value of datatype,
4482 * then also kstrtou8 fails
4483 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004484 hdd_err("kstrtou8 failed range [%d - %d]",
4485 CFG_OKC_FEATURE_ENABLED_MIN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004486 CFG_OKC_FEATURE_ENABLED_MAX);
4487 ret = -EINVAL;
4488 goto exit;
4489 }
4490
4491 if ((okcMode < CFG_OKC_FEATURE_ENABLED_MIN) ||
4492 (okcMode > CFG_OKC_FEATURE_ENABLED_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004493 hdd_err("Okc mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004494 okcMode,
4495 CFG_OKC_FEATURE_ENABLED_MIN,
4496 CFG_OKC_FEATURE_ENABLED_MAX);
4497 ret = -EINVAL;
4498 goto exit;
4499 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004500 hdd_debug("Received Command to change okc mode = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004501 okcMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004502
4503 hdd_ctx->config->isOkcIniFeatureEnabled = okcMode;
4504
4505exit:
4506 return ret;
4507}
4508
4509static int drv_cmd_get_roam_scan_control(hdd_adapter_t *adapter,
4510 hdd_context_t *hdd_ctx,
4511 uint8_t *command,
4512 uint8_t command_len,
4513 hdd_priv_data_t *priv_data)
4514{
4515 int ret = 0;
4516 bool roamScanControl = sme_get_roam_scan_control(hdd_ctx->hHal);
4517 char extra[32];
4518 uint8_t len = 0;
4519
4520 len = scnprintf(extra, sizeof(extra), "%s %d",
4521 command, roamScanControl);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304522 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004523 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004524 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004525 ret = -EFAULT;
4526 }
4527
4528 return ret;
4529}
4530
4531static int drv_cmd_bt_coex_mode(hdd_adapter_t *adapter,
4532 hdd_context_t *hdd_ctx,
4533 uint8_t *command,
4534 uint8_t command_len,
4535 hdd_priv_data_t *priv_data)
4536{
4537 int ret = 0;
4538 char *bcMode;
4539
4540 bcMode = command + 11;
4541 if ('1' == *bcMode) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004542 hdd_debug("BTCOEXMODE %d", *bcMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004543 hdd_ctx->btCoexModeSet = true;
4544 ret = wlan_hdd_scan_abort(adapter);
4545 if (ret < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004546 hdd_err("Failed to abort existing scan status: %d",
4547 ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004548 }
4549 } else if ('2' == *bcMode) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004550 hdd_debug("BTCOEXMODE %d", *bcMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004551 hdd_ctx->btCoexModeSet = false;
4552 }
4553
4554 return ret;
4555}
4556
4557static int drv_cmd_scan_active(hdd_adapter_t *adapter,
4558 hdd_context_t *hdd_ctx,
4559 uint8_t *command,
4560 uint8_t command_len,
4561 hdd_priv_data_t *priv_data)
4562{
4563 hdd_ctx->ioctl_scan_mode = eSIR_ACTIVE_SCAN;
4564 return 0;
4565}
4566
4567static int drv_cmd_scan_passive(hdd_adapter_t *adapter,
4568 hdd_context_t *hdd_ctx,
4569 uint8_t *command,
4570 uint8_t command_len,
4571 hdd_priv_data_t *priv_data)
4572{
4573 hdd_ctx->ioctl_scan_mode = eSIR_PASSIVE_SCAN;
4574 return 0;
4575}
4576
4577static int drv_cmd_get_dwell_time(hdd_adapter_t *adapter,
4578 hdd_context_t *hdd_ctx,
4579 uint8_t *command,
4580 uint8_t command_len,
4581 hdd_priv_data_t *priv_data)
4582{
4583 int ret = 0;
4584 struct hdd_config *pCfg =
4585 (WLAN_HDD_GET_CTX(adapter))->config;
4586 char extra[32];
4587 uint8_t len = 0;
4588
4589 memset(extra, 0, sizeof(extra));
4590 ret = hdd_get_dwell_time(pCfg, command, extra, sizeof(extra), &len);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304591 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004592 if (ret != 0 || copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004593 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004594 ret = -EFAULT;
4595 goto exit;
4596 }
4597 ret = len;
4598exit:
4599 return ret;
4600}
4601
4602static int drv_cmd_set_dwell_time(hdd_adapter_t *adapter,
4603 hdd_context_t *hdd_ctx,
4604 uint8_t *command,
4605 uint8_t command_len,
4606 hdd_priv_data_t *priv_data)
4607{
4608 return hdd_set_dwell_time(adapter, command);
4609}
4610
4611static int drv_cmd_miracast(hdd_adapter_t *adapter,
4612 hdd_context_t *hdd_ctx,
4613 uint8_t *command,
4614 uint8_t command_len,
4615 hdd_priv_data_t *priv_data)
4616{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304617 QDF_STATUS ret_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004618 int ret = 0;
4619 tHalHandle hHal;
4620 uint8_t filterType = 0;
4621 hdd_context_t *pHddCtx = NULL;
4622 uint8_t *value;
4623
4624 pHddCtx = WLAN_HDD_GET_CTX(adapter);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05304625 if (wlan_hdd_validate_context(pHddCtx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004626 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004627
4628 hHal = pHddCtx->hHal;
4629 value = command + 9;
4630
4631 /* Convert the value from ascii to integer */
4632 ret = kstrtou8(value, 10, &filterType);
4633 if (ret < 0) {
4634 /*
4635 * If the input value is greater than max value of datatype,
4636 * then also kstrtou8 fails
4637 */
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004638 hdd_err("kstrtou8 failed range");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004639 ret = -EINVAL;
4640 goto exit;
4641 }
4642 if ((filterType < WLAN_HDD_DRIVER_MIRACAST_CFG_MIN_VAL)
4643 || (filterType >
4644 WLAN_HDD_DRIVER_MIRACAST_CFG_MAX_VAL)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004645 hdd_err("Accepted Values are 0 to 2. 0-Disabled, 1-Source, 2-Sink");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004646 ret = -EINVAL;
4647 goto exit;
4648 }
4649 /* Filtertype value should be either 0-Disabled, 1-Source, 2-sink */
4650 pHddCtx->miracast_value = filterType;
4651
4652 ret_status = sme_set_miracast(hHal, filterType);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304653 if (QDF_STATUS_SUCCESS != ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004654 hdd_err("Failed to set miracast");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004655 return -EBUSY;
4656 }
4657
Tushnim Bhattacharyyade1070d2017-03-09 13:23:55 -08004658 if (policy_mgr_is_mcc_in_24G(hdd_ctx->hdd_psoc))
4659 return wlan_hdd_set_mas(adapter, filterType);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004660
4661exit:
4662 return ret;
4663}
4664
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004665/* Function header is left blank intentionally */
4666static int hdd_parse_set_ibss_oui_data_command(uint8_t *command, uint8_t *ie,
4667 int32_t *oui_length, int32_t limit)
4668{
4669 uint8_t len;
4670 uint8_t data;
4671
4672 while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) {
4673 command++;
4674 limit--;
4675 }
4676
4677 len = 2;
4678
4679 while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) &&
4680 (limit > 1)) {
4681 sscanf(command, "%02x", (unsigned int *)&data);
4682 ie[len++] = data;
4683 command += 2;
4684 limit -= 2;
4685 }
4686
4687 *oui_length = len - 2;
4688
4689 while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) {
4690 command++;
4691 limit--;
4692 }
4693
4694 while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) &&
4695 (limit > 1)) {
4696 sscanf(command, "%02x", (unsigned int *)&data);
4697 ie[len++] = data;
4698 command += 2;
4699 limit -= 2;
4700 }
4701
4702 ie[0] = IE_EID_VENDOR;
4703 ie[1] = len - 2;
4704
4705 return len;
4706}
4707
4708/**
4709 * drv_cmd_set_ibss_beacon_oui_data() - set ibss oui data command
4710 * @adapter: Pointer to adapter
4711 * @hdd_ctx: Pointer to HDD context
4712 * @command: Pointer to command string
4713 * @command_len : Command length
4714 * @priv_data : Pointer to priv data
4715 *
4716 * Return:
4717 * int status code
4718 */
4719static int drv_cmd_set_ibss_beacon_oui_data(hdd_adapter_t *adapter,
4720 hdd_context_t *hdd_ctx,
4721 uint8_t *command,
4722 uint8_t command_len,
4723 hdd_priv_data_t *priv_data)
4724{
4725 int i = 0;
4726 int status;
4727 int ret = 0;
4728 uint8_t *ibss_ie;
4729 int32_t oui_length = 0;
4730 uint32_t ibss_ie_length;
4731 uint8_t *value = command;
4732 tSirModifyIE ibssModifyIE;
4733 tCsrRoamProfile *pRoamProfile;
4734 hdd_wext_state_t *pWextState;
4735
4736
Krunal Sonibe766b02016-03-10 13:00:44 -08004737 if (QDF_IBSS_MODE != adapter->device_mode) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004738 hdd_debug("Device_mode %s(%d) not IBSS",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004739 hdd_device_mode_to_string(adapter->device_mode),
4740 adapter->device_mode);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004741 return ret;
4742 }
4743
4744 pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(adapter);
4745
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004746 hdd_debug("received command %s", ((char *)value));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004747
4748
4749 /* validate argument of command */
4750 if (strlen(value) <= command_len) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004751 hdd_err("No arguments in command length %zu",
4752 strlen(value));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004753 ret = -EFAULT;
4754 goto exit;
4755 }
4756
4757 /* moving to arguments of commands */
4758 value = value + command_len;
4759 command_len = strlen(value);
4760
4761 /* oui_data can't be less than 3 bytes */
4762 if (command_len < (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004763 hdd_err("Invalid SETIBSSBEACONOUIDATA command length %d",
4764 command_len);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004765 ret = -EFAULT;
4766 goto exit;
4767 }
4768
4769 ibss_ie = qdf_mem_malloc(command_len);
4770 if (!ibss_ie) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004771 hdd_err("Could not allocate memory for command length %d",
4772 command_len);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004773 ret = -ENOMEM;
4774 goto exit;
4775 }
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004776
4777 ibss_ie_length = hdd_parse_set_ibss_oui_data_command(value, ibss_ie,
4778 &oui_length,
4779 command_len);
4780 if (ibss_ie_length <= (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004781 hdd_err("Could not parse command %s return length %d",
4782 value, ibss_ie_length);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004783 ret = -EFAULT;
4784 qdf_mem_free(ibss_ie);
4785 goto exit;
4786 }
4787
4788 pRoamProfile = &pWextState->roamProfile;
4789
4790 qdf_copy_macaddr(&ibssModifyIE.bssid,
4791 pRoamProfile->BSSIDs.bssid);
4792
4793 ibssModifyIE.smeSessionId = adapter->sessionId;
4794 ibssModifyIE.notify = true;
4795 ibssModifyIE.ieID = IE_EID_VENDOR;
4796 ibssModifyIE.ieIDLen = ibss_ie_length;
4797 ibssModifyIE.ieBufferlength = ibss_ie_length;
4798 ibssModifyIE.pIEBuffer = ibss_ie;
4799 ibssModifyIE.oui_length = oui_length;
4800
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004801 hdd_warn("ibss_ie length %d oui_length %d ibss_ie:",
4802 ibss_ie_length, oui_length);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004803 while (i < ibssModifyIE.ieBufferlength)
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004804 hdd_warn("0x%x", ibss_ie[i++]);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004805
4806 /* Probe Bcn modification */
4807 sme_modify_add_ie(WLAN_HDD_GET_HAL_CTX(adapter),
4808 &ibssModifyIE, eUPDATE_IE_PROBE_BCN);
4809
4810 /* Populating probe resp frame */
4811 sme_modify_add_ie(WLAN_HDD_GET_HAL_CTX(adapter),
4812 &ibssModifyIE, eUPDATE_IE_PROBE_RESP);
4813
4814 qdf_mem_free(ibss_ie);
4815
4816 status = sme_send_cesium_enable_ind((tHalHandle)(hdd_ctx->hHal),
4817 adapter->sessionId);
4818 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004819 hdd_err("Could not send cesium enable indication %d",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004820 status);
4821 ret = -EINVAL;
4822 goto exit;
4823 }
4824
4825exit:
4826 return ret;
4827}
4828
4829static int drv_cmd_set_rmc_enable(hdd_adapter_t *adapter,
4830 hdd_context_t *hdd_ctx,
4831 uint8_t *command,
4832 uint8_t command_len,
4833 hdd_priv_data_t *priv_data)
4834{
4835 int ret = 0;
4836 uint8_t *value = command;
4837 uint8_t ucRmcEnable = 0;
4838 int status;
4839
Krunal Sonibe766b02016-03-10 13:00:44 -08004840 if ((QDF_IBSS_MODE != adapter->device_mode) &&
4841 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004842 hdd_err("Received SETRMCENABLE cmd in invalid mode %s(%d)",
4843 hdd_device_mode_to_string(adapter->device_mode),
4844 adapter->device_mode);
4845 hdd_err("SETRMCENABLE cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004846 ret = -EINVAL;
4847 goto exit;
4848 }
4849
4850 status = hdd_parse_setrmcenable_command(value, &ucRmcEnable);
4851 if (status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004852 hdd_err("Invalid SETRMCENABLE command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004853 ret = -EINVAL;
4854 goto exit;
4855 }
4856
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004857 hdd_debug("ucRmcEnable %d", ucRmcEnable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004858
4859 if (true == ucRmcEnable) {
4860 status = sme_enable_rmc((tHalHandle)
4861 (hdd_ctx->hHal),
4862 adapter->sessionId);
4863 } else if (false == ucRmcEnable) {
4864 status = sme_disable_rmc((tHalHandle)
4865 (hdd_ctx->hHal),
4866 adapter->sessionId);
4867 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004868 hdd_err("Invalid SETRMCENABLE command %d",
4869 ucRmcEnable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004870 ret = -EINVAL;
4871 goto exit;
4872 }
4873
4874 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004875 hdd_err("SETRMC %d failed status %d",
4876 ucRmcEnable, status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004877 ret = -EINVAL;
4878 goto exit;
4879 }
4880
4881exit:
4882 return ret;
4883}
4884
4885static int drv_cmd_set_rmc_action_period(hdd_adapter_t *adapter,
4886 hdd_context_t *hdd_ctx,
4887 uint8_t *command,
4888 uint8_t command_len,
4889 hdd_priv_data_t *priv_data)
4890{
4891 int ret = 0;
4892 uint8_t *value = command;
4893 uint32_t uActionPeriod = 0;
4894 int status;
4895
Krunal Sonibe766b02016-03-10 13:00:44 -08004896 if ((QDF_IBSS_MODE != adapter->device_mode) &&
4897 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004898 hdd_err("Received SETRMC cmd in invalid mode %s(%d)",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004899 hdd_device_mode_to_string(adapter->device_mode),
4900 adapter->device_mode);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004901 hdd_err("SETRMC cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004902 ret = -EINVAL;
4903 goto exit;
4904 }
4905
4906 status = hdd_parse_setrmcactionperiod_command(value, &uActionPeriod);
4907 if (status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004908 hdd_err("Invalid SETRMCACTIONPERIOD command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004909 ret = -EINVAL;
4910 goto exit;
4911 }
4912
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004913 hdd_debug("uActionPeriod %d",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004914 uActionPeriod);
4915
4916 if (sme_cfg_set_int(hdd_ctx->hHal,
4917 WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY,
4918 uActionPeriod)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004919 hdd_err("Could not set SETRMCACTIONPERIOD %d",
4920 uActionPeriod);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004921 ret = -EINVAL;
4922 goto exit;
4923 }
4924
4925 status = sme_send_rmc_action_period((tHalHandle)(hdd_ctx->hHal),
4926 adapter->sessionId);
4927 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004928 hdd_err("Could not send cesium enable indication %d",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004929 status);
4930 ret = -EINVAL;
4931 goto exit;
4932 }
4933
4934exit:
4935 return ret;
4936}
4937
4938static int drv_cmd_get_ibss_peer_info_all(hdd_adapter_t *adapter,
4939 hdd_context_t *hdd_ctx,
4940 uint8_t *command,
4941 uint8_t command_len,
4942 hdd_priv_data_t *priv_data)
4943{
4944 int ret = 0;
4945 int status = QDF_STATUS_SUCCESS;
4946 hdd_station_ctx_t *pHddStaCtx = NULL;
4947 char *extra = NULL;
4948 int idx = 0;
4949 int length = 0;
Rajeev Kumar94c9b452016-03-24 12:58:47 -07004950 uint8_t mac_addr[QDF_MAC_ADDR_SIZE];
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004951 uint32_t numOfBytestoPrint = 0;
4952
Krunal Sonibe766b02016-03-10 13:00:44 -08004953 if (QDF_IBSS_MODE != adapter->device_mode) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004954 hdd_warn("Unsupported in mode %s(%d)",
4955 hdd_device_mode_to_string(adapter->device_mode),
4956 adapter->device_mode);
4957 return -EINVAL;
4958 }
4959
4960 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08004961 hdd_debug("Received GETIBSSPEERINFOALL Command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004962
4963 /* Handle the command */
4964 status = hdd_cfg80211_get_ibss_peer_info_all(adapter);
4965 if (QDF_STATUS_SUCCESS == status) {
4966 /*
4967 * The variable extra needed to be allocated on the heap since
4968 * amount of memory required to copy the data for 32 devices
4969 * exceeds the size of 1024 bytes of default stack size. On
4970 * 64 bit devices, the default max stack size of 2048 bytes
4971 */
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07004972 extra = qdf_mem_malloc(WLAN_MAX_BUF_SIZE);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004973
4974 if (NULL == extra) {
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07004975 hdd_err("memory allocation failed");
4976 ret = -ENOMEM;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004977 goto exit;
4978 }
4979
4980 /* Copy number of stations */
4981 length = scnprintf(extra, WLAN_MAX_BUF_SIZE, "%d ",
Rajeev Kumar94c9b452016-03-24 12:58:47 -07004982 pHddStaCtx->ibss_peer_info.numPeers);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004983 numOfBytestoPrint = length;
Rajeev Kumar94c9b452016-03-24 12:58:47 -07004984 for (idx = 0; idx < pHddStaCtx->ibss_peer_info.numPeers;
4985 idx++) {
4986 int8_t rssi;
4987 uint32_t tx_rate;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004988
Rajeev Kumar94c9b452016-03-24 12:58:47 -07004989 qdf_mem_copy(mac_addr,
4990 pHddStaCtx->ibss_peer_info.peerInfoParams[idx].
4991 mac_addr, sizeof(mac_addr));
4992
4993 tx_rate =
4994 pHddStaCtx->ibss_peer_info.peerInfoParams[idx].
4995 txRate;
Sriram Madhvapathi85df7c72016-09-30 11:35:28 +05304996 /*
4997 * Only lower 3 bytes are rate info. Mask of the MSByte
4998 */
4999 tx_rate &= 0x00FFFFFF;
5000
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005001 rssi = pHddStaCtx->ibss_peer_info.peerInfoParams[idx].
5002 rssi;
5003
5004 length += scnprintf((extra + length),
5005 WLAN_MAX_BUF_SIZE - length,
5006 "%02x:%02x:%02x:%02x:%02x:%02x %d %d ",
5007 mac_addr[0], mac_addr[1], mac_addr[2],
5008 mac_addr[3], mac_addr[4], mac_addr[5],
5009 tx_rate, rssi);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005010 /*
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005011 * cdf_trace_msg has limitation of 512 bytes for the
5012 * print buffer. Hence printing the data in two chunks.
5013 * The first chunk will have the data for 16 devices
5014 * and the second chunk will have the rest.
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005015 */
5016 if (idx < NUM_OF_STA_DATA_TO_PRINT)
5017 numOfBytestoPrint = length;
5018 }
5019
5020 /*
5021 * Copy the data back into buffer, if the data to copy is
5022 * more than 512 bytes than we will split the data and do
5023 * it in two shots
5024 */
5025 if (copy_to_user(priv_data->buf, extra, numOfBytestoPrint)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005026 hdd_err("Copy into user data buffer failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005027 ret = -EFAULT;
5028 goto exit;
5029 }
5030
Srinivas Girigowda051a9b42017-03-21 15:44:29 -07005031 /* This overwrites the last space, which we already copied */
5032 extra[numOfBytestoPrint - 1] = '\0';
5033 hdd_debug("%s", extra);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005034
5035 if (length > numOfBytestoPrint) {
5036 if (copy_to_user
5037 (priv_data->buf + numOfBytestoPrint,
5038 extra + numOfBytestoPrint,
5039 length - numOfBytestoPrint + 1)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005040 hdd_err("Copy into user data buffer failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005041 ret = -EFAULT;
5042 goto exit;
5043 }
Srinivas Girigowda051a9b42017-03-21 15:44:29 -07005044 hdd_debug("%s", &extra[numOfBytestoPrint]);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005045 }
5046
5047 /* Free temporary buffer */
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07005048 qdf_mem_free(extra);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005049 } else {
5050 /* Command failed, log error */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005051 hdd_err("GETIBSSPEERINFOALL command failed with status code %d",
5052 status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005053 ret = -EINVAL;
5054 goto exit;
5055 }
5056 ret = 0;
5057
5058exit:
5059 return ret;
5060}
5061
5062/* Peer Info <Peer Addr> command */
5063static int drv_cmd_get_ibss_peer_info(hdd_adapter_t *adapter,
5064 hdd_context_t *hdd_ctx,
5065 uint8_t *command,
5066 uint8_t command_len,
5067 hdd_priv_data_t *priv_data)
5068{
5069 int ret = 0;
5070 uint8_t *value = command;
5071 QDF_STATUS status;
5072 hdd_station_ctx_t *pHddStaCtx = NULL;
5073 char extra[128] = { 0 };
5074 uint32_t length = 0;
5075 uint8_t staIdx = 0;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005076 struct qdf_mac_addr peerMacAddr;
5077
Krunal Sonibe766b02016-03-10 13:00:44 -08005078 if (QDF_IBSS_MODE != adapter->device_mode) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005079 hdd_warn("Unsupported in mode %s(%d)",
5080 hdd_device_mode_to_string(adapter->device_mode),
5081 adapter->device_mode);
5082 return -EINVAL;
5083 }
5084
5085 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5086
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005087 hdd_debug("Received GETIBSSPEERINFO Command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005088
5089 /* if there are no peers, no need to continue with the command */
5090 if (eConnectionState_IbssConnected !=
5091 pHddStaCtx->conn_info.connState) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005092 hdd_err("No IBSS Peers coalesced");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005093 ret = -EINVAL;
5094 goto exit;
5095 }
5096
5097 /* Parse the incoming command buffer */
5098 status = hdd_parse_get_ibss_peer_info(value, &peerMacAddr);
5099 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005100 hdd_err("Invalid GETIBSSPEERINFO command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005101 ret = -EINVAL;
5102 goto exit;
5103 }
5104
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005105 /* Get station index for the peer mac address and sanitize it */
Deepak Dhamdhere5872c8c2016-06-02 15:51:47 -07005106 hdd_get_peer_sta_id(pHddStaCtx, &peerMacAddr, &staIdx);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005107
Naveen Rawatc45d1622016-07-05 12:20:09 -07005108 if (staIdx > MAX_PEERS) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005109 hdd_err("Invalid StaIdx %d returned", staIdx);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005110 ret = -EINVAL;
5111 goto exit;
5112 }
5113
5114 /* Handle the command */
5115 status = hdd_cfg80211_get_ibss_peer_info(adapter, staIdx);
5116 if (QDF_STATUS_SUCCESS == status) {
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005117 uint32_t txRate =
5118 pHddStaCtx->ibss_peer_info.peerInfoParams[0].txRate;
Sriram Madhvapathi85df7c72016-09-30 11:35:28 +05305119 /* Only lower 3 bytes are rate info. Mask of the MSByte */
5120 txRate &= 0x00FFFFFF;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005121
5122 length = scnprintf(extra, sizeof(extra), "%d %d",
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005123 (int)txRate,
5124 (int)pHddStaCtx->ibss_peer_info.
5125 peerInfoParams[0].rssi);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005126
5127 /* Copy the data back into buffer */
5128 if (copy_to_user(priv_data->buf, &extra, length + 1)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005129 hdd_err("copy data to user buffer failed GETIBSSPEERINFO command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005130 ret = -EFAULT;
5131 goto exit;
5132 }
5133 } else {
5134 /* Command failed, log error */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005135 hdd_err("GETIBSSPEERINFO command failed with status code %d",
5136 status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005137 ret = -EINVAL;
5138 goto exit;
5139 }
5140
5141 /* Success ! */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005142 hdd_debug("%s", priv_data->buf);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005143 ret = 0;
5144
5145exit:
5146 return ret;
5147}
5148
5149static int drv_cmd_set_rmc_tx_rate(hdd_adapter_t *adapter,
5150 hdd_context_t *hdd_ctx,
5151 uint8_t *command,
5152 uint8_t command_len,
5153 hdd_priv_data_t *priv_data)
5154{
5155 int ret = 0;
5156 uint8_t *value = command;
5157 uint32_t uRate = 0;
5158 tTxrateinfoflags txFlags = 0;
5159 tSirRateUpdateInd rateUpdateParams = {0};
5160 int status;
5161 struct hdd_config *pConfig = hdd_ctx->config;
5162
Krunal Sonibe766b02016-03-10 13:00:44 -08005163 if ((QDF_IBSS_MODE != adapter->device_mode) &&
5164 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005165 hdd_err("Received SETRMCTXRATE cmd in invalid mode %s(%d)",
5166 hdd_device_mode_to_string(adapter->device_mode),
5167 adapter->device_mode);
5168 hdd_err("SETRMCTXRATE cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005169 ret = -EINVAL;
5170 goto exit;
5171 }
5172
5173 status = hdd_parse_setrmcrate_command(value, &uRate, &txFlags);
5174 if (status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005175 hdd_err("Invalid SETRMCTXRATE command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005176 ret = -EINVAL;
5177 goto exit;
5178 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005179 hdd_debug("uRate %d", uRate);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005180 /* -1 implies ignore this param */
5181 rateUpdateParams.ucastDataRate = -1;
5182
5183 /*
5184 * Fill the user specifieed RMC rate param
5185 * and the derived tx flags.
5186 */
5187 rateUpdateParams.nss = (pConfig->enable2x2 == 0) ? 0 : 1;
5188 rateUpdateParams.reliableMcastDataRate = uRate;
5189 rateUpdateParams.reliableMcastDataRateTxFlag = txFlags;
5190 rateUpdateParams.dev_mode = adapter->device_mode;
5191 rateUpdateParams.bcastDataRate = -1;
5192 memcpy(rateUpdateParams.bssid.bytes,
5193 adapter->macAddressCurrent.bytes,
5194 sizeof(rateUpdateParams.bssid));
5195 status = sme_send_rate_update_ind((tHalHandle) (hdd_ctx->hHal),
5196 &rateUpdateParams);
5197
5198exit:
5199 return ret;
5200}
5201
5202static int drv_cmd_set_ibss_tx_fail_event(hdd_adapter_t *adapter,
5203 hdd_context_t *hdd_ctx,
5204 uint8_t *command,
5205 uint8_t command_len,
5206 hdd_priv_data_t *priv_data)
5207{
5208 int ret = 0;
5209 char *value;
5210 uint8_t tx_fail_count = 0;
5211 uint16_t pid = 0;
5212
5213 value = command;
5214
5215 ret = hdd_parse_ibsstx_fail_event_params(value, &tx_fail_count, &pid);
5216
5217 if (0 != ret) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005218 hdd_err("Failed to parse SETIBSSTXFAILEVENT arguments");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005219 goto exit;
5220 }
5221
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005222 hdd_debug("tx_fail_cnt=%hhu, pid=%hu", tx_fail_count, pid);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005223
5224 if (0 == tx_fail_count) {
5225 /* Disable TX Fail Indication */
5226 if (QDF_STATUS_SUCCESS ==
5227 sme_tx_fail_monitor_start_stop_ind(hdd_ctx->hHal,
5228 tx_fail_count,
5229 NULL)) {
5230 cesium_pid = 0;
5231 } else {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005232 hdd_err("failed to disable TX Fail Event");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005233 ret = -EINVAL;
5234 }
5235 } else {
5236 if (QDF_STATUS_SUCCESS ==
5237 sme_tx_fail_monitor_start_stop_ind(hdd_ctx->hHal,
5238 tx_fail_count,
5239 (void *)hdd_tx_fail_ind_callback)) {
5240 cesium_pid = pid;
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005241 hdd_debug("Registered Cesium pid %u",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005242 cesium_pid);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005243 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005244 hdd_err("Failed to enable TX Fail Monitoring");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005245 ret = -EINVAL;
5246 }
5247 }
5248
5249exit:
5250 return ret;
5251}
5252
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08005253#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005254static int drv_cmd_set_ccx_roam_scan_channels(hdd_adapter_t *adapter,
5255 hdd_context_t *hdd_ctx,
5256 uint8_t *command,
5257 uint8_t command_len,
5258 hdd_priv_data_t *priv_data)
5259{
5260 int ret = 0;
5261 uint8_t *value = command;
5262 uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
5263 uint8_t numChannels = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305264 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005265
5266 ret = hdd_parse_channellist(value, ChannelList, &numChannels);
5267 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005268 hdd_err("Failed to parse channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005269 goto exit;
5270 }
5271 if (numChannels > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005272 hdd_err("number of channels (%d) supported exceeded max (%d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005273 numChannels,
5274 WNI_CFG_VALID_CHANNEL_LIST_LEN);
5275 ret = -EINVAL;
5276 goto exit;
5277 }
5278 status = sme_set_ese_roam_scan_channel_list(hdd_ctx->hHal,
5279 adapter->sessionId,
5280 ChannelList,
5281 numChannels);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305282 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005283 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005284 ret = -EINVAL;
5285 goto exit;
5286 }
5287
5288exit:
5289 return ret;
5290}
5291
5292static int drv_cmd_get_tsm_stats(hdd_adapter_t *adapter,
5293 hdd_context_t *hdd_ctx,
5294 uint8_t *command,
5295 uint8_t command_len,
5296 hdd_priv_data_t *priv_data)
5297{
5298 int ret = 0;
5299 uint8_t *value = command;
5300 char extra[128] = { 0 };
5301 int len = 0;
5302 uint8_t tid = 0;
5303 hdd_station_ctx_t *pHddStaCtx;
Jeff Johnsonc13bdf12017-01-25 16:28:19 -08005304 tAniTrafStrmMetrics tsm_metrics = {0};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005305
Krunal Sonibe766b02016-03-10 13:00:44 -08005306 if ((QDF_STA_MODE != adapter->device_mode) &&
5307 (QDF_P2P_CLIENT_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005308 hdd_warn("Unsupported in mode %s(%d)",
5309 hdd_device_mode_to_string(adapter->device_mode),
5310 adapter->device_mode);
5311 return -EINVAL;
5312 }
5313
5314 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5315
5316 /* if not associated, return error */
5317 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005318 hdd_err("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005319 ret = -EINVAL;
5320 goto exit;
5321 }
5322
5323 /* Move pointer to ahead of GETTSMSTATS<delimiter> */
5324 value = value + command_len + 1;
5325
5326 /* Convert the value from ascii to integer */
5327 ret = kstrtou8(value, 10, &tid);
5328 if (ret < 0) {
5329 /*
5330 * If the input value is greater than max value of datatype,
5331 * then also kstrtou8 fails
5332 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005333 hdd_err("kstrtou8 failed range [%d - %d]",
5334 TID_MIN_VALUE,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005335 TID_MAX_VALUE);
5336 ret = -EINVAL;
5337 goto exit;
5338 }
5339 if ((tid < TID_MIN_VALUE) || (tid > TID_MAX_VALUE)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005340 hdd_err("tid value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005341 tid, TID_MIN_VALUE, TID_MAX_VALUE);
5342 ret = -EINVAL;
5343 goto exit;
5344 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005345 hdd_debug("Received Command to get tsm stats tid = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005346 tid);
Jeff Johnsonc13bdf12017-01-25 16:28:19 -08005347 ret = hdd_get_tsm_stats(adapter, tid, &tsm_metrics);
5348 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005349 hdd_err("failed to get tsm stats");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005350 goto exit;
5351 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005352 hdd_debug(
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005353 "UplinkPktQueueDly(%d) UplinkPktQueueDlyHist[0](%d) UplinkPktQueueDlyHist[1](%d) UplinkPktQueueDlyHist[2](%d) UplinkPktQueueDlyHist[3](%d) UplinkPktTxDly(%u) UplinkPktLoss(%d) UplinkPktCount(%d) RoamingCount(%d) RoamingDly(%d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005354 tsm_metrics.UplinkPktQueueDly,
5355 tsm_metrics.UplinkPktQueueDlyHist[0],
5356 tsm_metrics.UplinkPktQueueDlyHist[1],
5357 tsm_metrics.UplinkPktQueueDlyHist[2],
5358 tsm_metrics.UplinkPktQueueDlyHist[3],
5359 tsm_metrics.UplinkPktTxDly,
5360 tsm_metrics.UplinkPktLoss,
5361 tsm_metrics.UplinkPktCount,
5362 tsm_metrics.RoamingCount,
5363 tsm_metrics.RoamingDly);
5364 /*
5365 * Output TSM stats is of the format
5366 * GETTSMSTATS [PktQueueDly]
5367 * [PktQueueDlyHist[0]]:[PktQueueDlyHist[1]] ...[RoamingDly]
5368 * eg., GETTSMSTATS 10 1:0:0:161 20 1 17 8 39800
5369 */
5370 len = scnprintf(extra,
5371 sizeof(extra),
5372 "%s %d %d:%d:%d:%d %u %d %d %d %d",
5373 command,
5374 tsm_metrics.UplinkPktQueueDly,
5375 tsm_metrics.UplinkPktQueueDlyHist[0],
5376 tsm_metrics.UplinkPktQueueDlyHist[1],
5377 tsm_metrics.UplinkPktQueueDlyHist[2],
5378 tsm_metrics.UplinkPktQueueDlyHist[3],
5379 tsm_metrics.UplinkPktTxDly,
5380 tsm_metrics.UplinkPktLoss,
5381 tsm_metrics.UplinkPktCount,
5382 tsm_metrics.RoamingCount,
5383 tsm_metrics.RoamingDly);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305384 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005385 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005386 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005387 ret = -EFAULT;
5388 goto exit;
5389 }
5390
5391exit:
5392 return ret;
5393}
5394
5395static int drv_cmd_set_cckm_ie(hdd_adapter_t *adapter,
5396 hdd_context_t *hdd_ctx,
5397 uint8_t *command,
5398 uint8_t command_len,
5399 hdd_priv_data_t *priv_data)
5400{
5401 int ret;
5402 uint8_t *value = command;
5403 uint8_t *cckmIe = NULL;
5404 uint8_t cckmIeLen = 0;
5405
5406 ret = hdd_parse_get_cckm_ie(value, &cckmIe, &cckmIeLen);
5407 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005408 hdd_err("Failed to parse cckm ie data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005409 goto exit;
5410 }
5411
5412 if (cckmIeLen > DOT11F_IE_RSN_MAX_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005413 hdd_err("CCKM Ie input length is more than max[%d]",
5414 DOT11F_IE_RSN_MAX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005415 if (NULL != cckmIe) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305416 qdf_mem_free(cckmIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005417 cckmIe = NULL;
5418 }
5419 ret = -EINVAL;
5420 goto exit;
5421 }
5422
5423 sme_set_cckm_ie(hdd_ctx->hHal, adapter->sessionId,
5424 cckmIe, cckmIeLen);
5425 if (NULL != cckmIe) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305426 qdf_mem_free(cckmIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005427 cckmIe = NULL;
5428 }
5429
5430exit:
5431 return ret;
5432}
5433
5434static int drv_cmd_ccx_beacon_req(hdd_adapter_t *adapter,
5435 hdd_context_t *hdd_ctx,
5436 uint8_t *command,
5437 uint8_t command_len,
5438 hdd_priv_data_t *priv_data)
5439{
5440 int ret;
5441 uint8_t *value = command;
5442 tCsrEseBeaconReq eseBcnReq;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305443 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005444
Krunal Sonibe766b02016-03-10 13:00:44 -08005445 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005446 hdd_warn("Unsupported in mode %s(%d)",
5447 hdd_device_mode_to_string(adapter->device_mode),
5448 adapter->device_mode);
5449 return -EINVAL;
5450 }
5451
5452 ret = hdd_parse_ese_beacon_req(value, &eseBcnReq);
5453 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005454 hdd_err("Failed to parse ese beacon req");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005455 goto exit;
5456 }
5457
5458 if (!hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005459 hdd_debug("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005460 hdd_indicate_ese_bcn_report_no_results(adapter,
5461 eseBcnReq.bcnReq[0].measurementToken,
5462 0x02, /* BIT(1) set for measurement done */
5463 0); /* no BSS */
5464 goto exit;
5465 }
5466
5467 status = sme_set_ese_beacon_request(hdd_ctx->hHal,
5468 adapter->sessionId,
5469 &eseBcnReq);
5470
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305471 if (QDF_STATUS_E_RESOURCES == status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005472 hdd_err("sme_set_ese_beacon_request failed (%d), a request already in progress",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005473 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005474 ret = -EBUSY;
5475 goto exit;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305476 } else if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005477 hdd_err("sme_set_ese_beacon_request failed (%d)",
5478 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005479 ret = -EINVAL;
5480 goto exit;
5481 }
5482
5483exit:
5484 return ret;
5485}
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005486
5487/**
5488 * drv_cmd_ccx_plm_req() - Set ESE PLM request
5489 * @adapter: Pointer to the HDD adapter
5490 * @hdd_ctx: Pointer to the HDD context
5491 * @command: Driver command string
5492 * @command_len: Driver command string length
5493 * @priv_data: Private data coming with the driver command. Unused here
5494 *
5495 * This function handles driver command that sets the ESE PLM request
5496 *
5497 * Return: 0 on success; negative errno otherwise
5498 */
5499static int drv_cmd_ccx_plm_req(hdd_adapter_t *adapter,
5500 hdd_context_t *hdd_ctx,
5501 uint8_t *command,
5502 uint8_t command_len,
5503 hdd_priv_data_t *priv_data)
5504{
5505 int ret = 0;
5506 uint8_t *value = command;
5507 QDF_STATUS status = QDF_STATUS_SUCCESS;
5508 tpSirPlmReq pPlmRequest = NULL;
5509
5510 pPlmRequest = qdf_mem_malloc(sizeof(tSirPlmReq));
5511 if (NULL == pPlmRequest) {
5512 ret = -ENOMEM;
5513 goto exit;
5514 }
5515
5516 status = hdd_parse_plm_cmd(value, pPlmRequest);
5517 if (QDF_STATUS_SUCCESS != status) {
5518 qdf_mem_free(pPlmRequest);
5519 pPlmRequest = NULL;
5520 ret = -EINVAL;
5521 goto exit;
5522 }
5523 pPlmRequest->sessionId = adapter->sessionId;
5524
5525 status = sme_set_plm_request(hdd_ctx->hHal, pPlmRequest);
5526 if (QDF_STATUS_SUCCESS != status) {
5527 qdf_mem_free(pPlmRequest);
5528 pPlmRequest = NULL;
5529 ret = -EINVAL;
5530 goto exit;
5531 }
5532
5533exit:
5534 return ret;
5535}
5536
5537/**
5538 * drv_cmd_set_ccx_mode() - Set ESE mode
5539 * @adapter: Pointer to the HDD adapter
5540 * @hdd_ctx: Pointer to the HDD context
5541 * @command: Driver command string
5542 * @command_len: Driver command string length
5543 * @priv_data: Private data coming with the driver command. Unused here
5544 *
5545 * This function handles driver command that sets ESE mode
5546 *
5547 * Return: 0 on success; negative errno otherwise
5548 */
5549static int drv_cmd_set_ccx_mode(hdd_adapter_t *adapter,
5550 hdd_context_t *hdd_ctx,
5551 uint8_t *command,
5552 uint8_t command_len,
5553 hdd_priv_data_t *priv_data)
5554{
5555 int ret = 0;
5556 uint8_t *value = command;
5557 uint8_t eseMode = CFG_ESE_FEATURE_ENABLED_DEFAULT;
5558
5559 /*
5560 * Check if the features OKC/ESE/11R are supported simultaneously,
5561 * then this operation is not permitted (return FAILURE)
5562 */
5563 if (sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
5564 hdd_is_okc_mode_enabled(hdd_ctx) &&
5565 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
5566 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
5567 ret = -EPERM;
5568 goto exit;
5569 }
5570
Deepak Dhamdherea2785822016-11-17 01:17:45 -08005571 if (!adapter->fast_roaming_allowed) {
5572 hdd_warn("Fast roaming is not allowed on this device hence this operation is not permitted!");
5573 ret = -EPERM;
5574 goto exit;
5575 }
5576
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005577 /* Move pointer to ahead of SETCCXMODE<delimiter> */
5578 value = value + command_len + 1;
5579
5580 /* Convert the value from ascii to integer */
5581 ret = kstrtou8(value, 10, &eseMode);
5582 if (ret < 0) {
5583 /*
5584 * If the input value is greater than max value of datatype,
5585 * then also kstrtou8 fails
5586 */
5587 hdd_err("kstrtou8 failed range [%d - %d]",
5588 CFG_ESE_FEATURE_ENABLED_MIN,
5589 CFG_ESE_FEATURE_ENABLED_MAX);
5590 ret = -EINVAL;
5591 goto exit;
5592 }
5593
5594 if ((eseMode < CFG_ESE_FEATURE_ENABLED_MIN) ||
5595 (eseMode > CFG_ESE_FEATURE_ENABLED_MAX)) {
5596 hdd_err("Ese mode value %d is out of range (Min: %d Max: %d)",
5597 eseMode,
5598 CFG_ESE_FEATURE_ENABLED_MIN,
5599 CFG_ESE_FEATURE_ENABLED_MAX);
5600 ret = -EINVAL;
5601 goto exit;
5602 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005603 hdd_debug("Received Command to change ese mode = %d", eseMode);
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005604
5605 hdd_ctx->config->isEseIniFeatureEnabled = eseMode;
5606 sme_update_is_ese_feature_enabled(hdd_ctx->hHal,
5607 adapter->sessionId,
5608 eseMode);
5609
5610exit:
5611 return ret;
5612}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08005613#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005614
5615static int drv_cmd_set_mc_rate(hdd_adapter_t *adapter,
5616 hdd_context_t *hdd_ctx,
5617 uint8_t *command,
5618 uint8_t command_len,
5619 hdd_priv_data_t *priv_data)
5620{
5621 int ret = 0;
5622 uint8_t *value = command;
5623 int targetRate;
5624
5625 /* input value is in units of hundred kbps */
5626
5627 /* Move pointer to ahead of SETMCRATE<delimiter> */
5628 value = value + command_len + 1;
5629
5630 /* Convert the value from ascii to integer, decimal base */
5631 ret = kstrtouint(value, 10, &targetRate);
5632
5633 ret = wlan_hdd_set_mc_rate(adapter, targetRate);
5634 return ret;
5635}
5636
5637static int drv_cmd_max_tx_power(hdd_adapter_t *adapter,
5638 hdd_context_t *hdd_ctx,
5639 uint8_t *command,
5640 uint8_t command_len,
5641 hdd_priv_data_t *priv_data)
5642{
5643 int ret = 0;
5644 int status;
5645 int txPower;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305646 QDF_STATUS qdf_status;
5647 QDF_STATUS smeStatus;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005648 uint8_t *value = command;
Anurag Chouhan6d760662016-02-20 16:05:43 +05305649 struct qdf_mac_addr bssid = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
5650 struct qdf_mac_addr selfMac = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005651 hdd_adapter_list_node_t *pAdapterNode = NULL;
5652 hdd_adapter_list_node_t *pNext = NULL;
5653
5654 status = hdd_parse_setmaxtxpower_command(value, &txPower);
5655 if (status) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005656 hdd_err("Invalid MAXTXPOWER command");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005657 ret = -EINVAL;
5658 goto exit;
5659 }
5660
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305661 qdf_status = hdd_get_front_adapter(hdd_ctx, &pAdapterNode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005662 while (NULL != pAdapterNode
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305663 && QDF_STATUS_SUCCESS == qdf_status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005664 adapter = pAdapterNode->pAdapter;
5665 /* Assign correct self MAC address */
Anurag Chouhanc5548422016-02-24 18:33:27 +05305666 qdf_copy_macaddr(&bssid,
Srinivas Girigowda97215232015-09-24 12:26:28 -07005667 &adapter->macAddressCurrent);
Anurag Chouhanc5548422016-02-24 18:33:27 +05305668 qdf_copy_macaddr(&selfMac,
Srinivas Girigowda97215232015-09-24 12:26:28 -07005669 &adapter->macAddressCurrent);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005670
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005671 hdd_debug("Device mode %d max tx power %d selfMac: "
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005672 MAC_ADDRESS_STR " bssId: " MAC_ADDRESS_STR " ",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005673 adapter->device_mode, txPower,
Srinivas Girigowda97215232015-09-24 12:26:28 -07005674 MAC_ADDR_ARRAY(selfMac.bytes),
5675 MAC_ADDR_ARRAY(bssid.bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005676
Srinivas Girigowda97215232015-09-24 12:26:28 -07005677 smeStatus = sme_set_max_tx_power(hdd_ctx->hHal,
5678 bssid, selfMac, txPower);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305679 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005680 hdd_err("Set max tx power failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005681 ret = -EINVAL;
5682 goto exit;
5683 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005684 hdd_debug("Set max tx power success");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305685 qdf_status = hdd_get_next_adapter(hdd_ctx, pAdapterNode,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005686 &pNext);
5687 pAdapterNode = pNext;
5688 }
5689
5690exit:
5691 return ret;
5692}
5693
5694static int drv_cmd_set_dfs_scan_mode(hdd_adapter_t *adapter,
5695 hdd_context_t *hdd_ctx,
5696 uint8_t *command,
5697 uint8_t command_len,
5698 hdd_priv_data_t *priv_data)
5699{
5700 int ret = 0;
5701 uint8_t *value = command;
5702 uint8_t dfsScanMode = CFG_ROAMING_DFS_CHANNEL_DEFAULT;
5703
5704 /* Move pointer to ahead of SETDFSSCANMODE<delimiter> */
5705 value = value + command_len + 1;
5706
5707 /* Convert the value from ascii to integer */
5708 ret = kstrtou8(value, 10, &dfsScanMode);
5709 if (ret < 0) {
5710 /*
5711 * If the input value is greater than max value of datatype,
5712 * then also kstrtou8 fails
5713 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005714 hdd_err("kstrtou8 failed range [%d - %d]",
5715 CFG_ROAMING_DFS_CHANNEL_MIN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005716 CFG_ROAMING_DFS_CHANNEL_MAX);
5717 ret = -EINVAL;
5718 goto exit;
5719 }
5720
5721 if ((dfsScanMode < CFG_ROAMING_DFS_CHANNEL_MIN) ||
5722 (dfsScanMode > CFG_ROAMING_DFS_CHANNEL_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005723 hdd_err("dfsScanMode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005724 dfsScanMode,
5725 CFG_ROAMING_DFS_CHANNEL_MIN,
5726 CFG_ROAMING_DFS_CHANNEL_MAX);
5727 ret = -EINVAL;
5728 goto exit;
5729 }
5730
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005731 hdd_debug("Received Command to Set DFS Scan Mode = %d",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005732 dfsScanMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005733
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005734 /* When DFS scanning is disabled, the DFS channels need to be
5735 * removed from the operation of device.
5736 */
5737 ret = wlan_hdd_disable_dfs_chan_scan(hdd_ctx, adapter,
5738 (dfsScanMode == CFG_ROAMING_DFS_CHANNEL_DISABLED));
5739 if (ret < 0) {
5740 /* Some conditions prevented it from disabling DFS channels */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005741 hdd_err("disable/enable DFS channel request was denied");
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005742 goto exit;
5743 }
5744
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005745 hdd_ctx->config->allowDFSChannelRoam = dfsScanMode;
5746 sme_update_dfs_scan_mode(hdd_ctx->hHal, adapter->sessionId,
5747 dfsScanMode);
5748
5749exit:
5750 return ret;
5751}
5752
5753static int drv_cmd_get_dfs_scan_mode(hdd_adapter_t *adapter,
5754 hdd_context_t *hdd_ctx,
5755 uint8_t *command,
5756 uint8_t command_len,
5757 hdd_priv_data_t *priv_data)
5758{
5759 int ret = 0;
5760 uint8_t dfsScanMode = sme_get_dfs_scan_mode(hdd_ctx->hHal);
5761 char extra[32];
5762 uint8_t len = 0;
5763
5764 len = scnprintf(extra, sizeof(extra), "%s %d", command, dfsScanMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305765 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005766 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005767 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005768 ret = -EFAULT;
5769 }
5770
5771 return ret;
5772}
5773
5774static int drv_cmd_get_link_status(hdd_adapter_t *adapter,
5775 hdd_context_t *hdd_ctx,
5776 uint8_t *command,
5777 uint8_t command_len,
5778 hdd_priv_data_t *priv_data)
5779{
5780 int ret = 0;
5781 int value = wlan_hdd_get_link_status(adapter);
5782 char extra[32];
5783 uint8_t len;
5784
5785 len = scnprintf(extra, sizeof(extra), "%s %d", command, value);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305786 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005787 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005788 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005789 ret = -EFAULT;
5790 }
5791
5792 return ret;
5793}
5794
5795#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
5796static int drv_cmd_enable_ext_wow(hdd_adapter_t *adapter,
5797 hdd_context_t *hdd_ctx,
5798 uint8_t *command,
5799 uint8_t command_len,
5800 hdd_priv_data_t *priv_data)
5801{
5802 uint8_t *value = command;
5803 int set_value;
5804
5805 /* Move pointer to ahead of ENABLEEXTWOW */
5806 value = value + command_len;
5807
Anurag Chouhan43e0c752016-09-03 16:17:02 +05305808 if (!(sscanf(value, "%d", &set_value))) {
5809 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
5810 ("No input identified"));
5811 return -EINVAL;
5812 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005813
5814 return hdd_enable_ext_wow_parser(adapter,
5815 adapter->sessionId,
5816 set_value);
5817}
5818
5819static int drv_cmd_set_app1_params(hdd_adapter_t *adapter,
5820 hdd_context_t *hdd_ctx,
5821 uint8_t *command,
5822 uint8_t command_len,
5823 hdd_priv_data_t *priv_data)
5824{
5825 int ret;
5826 uint8_t *value = command;
5827
5828 /* Move pointer to ahead of SETAPP1PARAMS */
5829 value = value + command_len;
5830
5831 ret = hdd_set_app_type1_parser(adapter,
5832 value, strlen(value));
5833 if (ret >= 0)
5834 hdd_ctx->is_extwow_app_type1_param_set = true;
5835
5836 return ret;
5837}
5838
5839static int drv_cmd_set_app2_params(hdd_adapter_t *adapter,
5840 hdd_context_t *hdd_ctx,
5841 uint8_t *command,
5842 uint8_t command_len,
5843 hdd_priv_data_t *priv_data)
5844{
5845 int ret;
5846 uint8_t *value = command;
5847
5848 /* Move pointer to ahead of SETAPP2PARAMS */
5849 value = value + command_len;
5850
5851 ret = hdd_set_app_type2_parser(adapter, value, strlen(value));
5852 if (ret >= 0)
5853 hdd_ctx->is_extwow_app_type2_param_set = true;
5854
5855 return ret;
5856}
5857#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
5858
5859#ifdef FEATURE_WLAN_TDLS
5860/**
5861 * drv_cmd_tdls_secondary_channel_offset() - secondary tdls off channel offset
5862 * @adapter: Pointer to the HDD adapter
5863 * @hdd_ctx: Pointer to the HDD context
5864 * @command: Driver command string
5865 * @command_len: Driver command string length
5866 * @priv_data: Private data coming with the driver command. Unused here
5867 *
5868 * This function handles driver command that sets the secondary tdls off channel
5869 * offset
5870 *
5871 * Return: 0 on success; negative errno otherwise
5872 */
5873static int drv_cmd_tdls_secondary_channel_offset(hdd_adapter_t *adapter,
5874 hdd_context_t *hdd_ctx,
5875 uint8_t *command,
5876 uint8_t command_len,
5877 hdd_priv_data_t *priv_data)
5878{
5879 int ret;
5880 uint8_t *value = command;
5881 int set_value;
5882
5883 /* Move pointer to point the string */
5884 value += command_len;
5885
5886 ret = sscanf(value, "%d", &set_value);
5887 if (ret != 1)
5888 return -EINVAL;
5889
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005890 hdd_debug("Tdls offchannel offset:%d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005891
5892 ret = hdd_set_tdls_secoffchanneloffset(hdd_ctx, set_value);
5893
5894 return ret;
5895}
5896
5897/**
5898 * drv_cmd_tdls_off_channel_mode() - set tdls off channel mode
5899 * @adapter: Pointer to the HDD adapter
5900 * @hdd_ctx: Pointer to the HDD context
5901 * @command: Driver command string
5902 * @command_len: Driver command string length
5903 * @priv_data: Private data coming with the driver command. Unused here
5904 *
5905 * This function handles driver command that sets tdls off channel mode
5906 *
5907 * Return: 0 on success; negative errno otherwise
5908 */
5909static int drv_cmd_tdls_off_channel_mode(hdd_adapter_t *adapter,
5910 hdd_context_t *hdd_ctx,
5911 uint8_t *command,
5912 uint8_t command_len,
5913 hdd_priv_data_t *priv_data)
5914{
5915 int ret;
5916 uint8_t *value = command;
5917 int set_value;
5918
5919 /* Move pointer to point the string */
5920 value += command_len;
5921
5922 ret = sscanf(value, "%d", &set_value);
5923 if (ret != 1)
5924 return -EINVAL;
5925
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005926 hdd_debug("Tdls offchannel mode:%d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005927
5928 ret = hdd_set_tdls_offchannelmode(adapter, set_value);
5929
5930 return ret;
5931}
5932
5933/**
5934 * drv_cmd_tdls_off_channel() - set tdls off channel number
5935 * @adapter: Pointer to the HDD adapter
5936 * @hdd_ctx: Pointer to the HDD context
5937 * @command: Driver command string
5938 * @command_len: Driver command string length
5939 * @priv_data: Private data coming with the driver command. Unused here
5940 *
5941 * This function handles driver command that sets tdls off channel number
5942 *
5943 * Return: 0 on success; negative errno otherwise
5944 */
5945static int drv_cmd_tdls_off_channel(hdd_adapter_t *adapter,
5946 hdd_context_t *hdd_ctx,
5947 uint8_t *command,
5948 uint8_t command_len,
5949 hdd_priv_data_t *priv_data)
5950{
5951 int ret;
5952 uint8_t *value = command;
5953 int set_value;
5954
5955 /* Move pointer to point the string */
5956 value += command_len;
5957
5958 ret = sscanf(value, "%d", &set_value);
5959 if (ret != 1)
5960 return -EINVAL;
5961
Krishna Kumaar Natarajan4d090352015-10-26 18:30:53 -07005962 if (CDS_IS_DFS_CH(set_value)) {
5963 hdd_err("DFS channel %d is passed for hdd_set_tdls_offchannel",
5964 set_value);
5965 return -EINVAL;
5966 }
5967
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08005968 hdd_debug("Tdls offchannel num: %d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005969
5970 ret = hdd_set_tdls_offchannel(hdd_ctx, set_value);
5971
5972 return ret;
5973}
5974
5975/**
5976 * drv_cmd_tdls_scan() - set tdls scan type
5977 * @adapter: Pointer to the HDD adapter
5978 * @hdd_ctx: Pointer to the HDD context
5979 * @command: Driver command string
5980 * @command_len: Driver command string length
5981 * @priv_data: Private data coming with the driver command. Unused here
5982 *
5983 * This function handles driver command that sets tdls scan type
5984 *
5985 * Return: 0 on success; negative errno otherwise
5986 */
5987static int drv_cmd_tdls_scan(hdd_adapter_t *adapter,
5988 hdd_context_t *hdd_ctx,
5989 uint8_t *command,
5990 uint8_t command_len,
5991 hdd_priv_data_t *priv_data)
5992{
5993 int ret;
5994 uint8_t *value = command;
5995 int set_value;
5996
5997 /* Move pointer to point the string */
5998 value += command_len;
5999
6000 ret = sscanf(value, "%d", &set_value);
6001 if (ret != 1)
6002 return -EINVAL;
6003
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006004 hdd_debug("Tdls scan type val: %d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006005
6006 ret = hdd_set_tdls_scan_type(hdd_ctx, set_value);
6007
6008 return ret;
6009}
6010#endif
6011
6012static int drv_cmd_get_rssi(hdd_adapter_t *adapter,
6013 hdd_context_t *hdd_ctx,
6014 uint8_t *command,
6015 uint8_t command_len,
6016 hdd_priv_data_t *priv_data)
6017{
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006018 int ret = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006019 int8_t rssi = 0;
6020 char extra[32];
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006021
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006022 uint8_t len = 0;
6023
6024 wlan_hdd_get_rssi(adapter, &rssi);
6025
6026 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
Anurag Chouhan6d760662016-02-20 16:05:43 +05306027 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006028
6029 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006030 hdd_err("Failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006031 ret = -EFAULT;
6032 }
6033
6034 return ret;
6035}
6036
6037static int drv_cmd_get_linkspeed(hdd_adapter_t *adapter,
6038 hdd_context_t *hdd_ctx,
6039 uint8_t *command,
6040 uint8_t command_len,
6041 hdd_priv_data_t *priv_data)
6042{
6043 int ret;
6044 uint32_t link_speed = 0;
6045 char extra[32];
6046 uint8_t len = 0;
6047
6048 ret = wlan_hdd_get_link_speed(adapter, &link_speed);
6049 if (0 != ret)
6050 return ret;
6051
6052 len = scnprintf(extra, sizeof(extra), "%s %d", command, link_speed);
Anurag Chouhan6d760662016-02-20 16:05:43 +05306053 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006054 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006055 hdd_err("Failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006056 ret = -EFAULT;
6057 }
6058
6059 return ret;
6060}
6061
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006062/**
6063 * hdd_set_rx_filter() - set RX filter
6064 * @adapter: Pointer to adapter
6065 * @action: Filter action
6066 * @pattern: Address pattern
6067 *
6068 * Address pattern is most significant byte of address for example
6069 * 0x01 for IPV4 multicast address
6070 * 0x33 for IPV6 multicast address
6071 * 0xFF for broadcast address
6072 *
6073 * Return: 0 for success, non-zero for failure
6074 */
6075static int hdd_set_rx_filter(hdd_adapter_t *adapter, bool action,
6076 uint8_t pattern)
6077{
6078 int ret;
Frank Liuf95e8132016-09-29 19:01:30 +08006079 uint8_t i, j;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006080 tHalHandle handle;
6081 tSirRcvFltMcAddrList *filter;
6082 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
6083
6084 ret = wlan_hdd_validate_context(hdd_ctx);
6085 if (0 != ret)
6086 return ret;
6087
6088 handle = hdd_ctx->hHal;
6089
6090 if (NULL == handle) {
6091 hdd_err("HAL Handle is NULL");
6092 return -EINVAL;
6093 }
6094
Mukul Sharma3a1ab302017-01-15 19:02:37 +05306095 if (!hdd_ctx->config->fEnableMCAddrList) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006096 hdd_warn("mc addr ini is disabled");
Mukul Sharma3a1ab302017-01-15 19:02:37 +05306097 return -EINVAL;
6098 }
6099
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006100 /*
6101 * If action is false it means start dropping packets
6102 * Set addr_filter_pattern which will be used when sending
6103 * MC/BC address list to target
6104 */
6105 if (!action)
6106 adapter->addr_filter_pattern = pattern;
6107 else
6108 adapter->addr_filter_pattern = 0;
6109
Krunal Sonibe766b02016-03-10 13:00:44 -08006110 if (((adapter->device_mode == QDF_STA_MODE) ||
6111 (adapter->device_mode == QDF_P2P_CLIENT_MODE)) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006112 adapter->mc_addr_list.mc_cnt &&
6113 hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
6114
6115
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306116 filter = qdf_mem_malloc(sizeof(*filter));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006117 if (NULL == filter) {
6118 hdd_err("Could not allocate Memory");
6119 return -ENOMEM;
6120 }
6121 filter->action = action;
Frank Liuf95e8132016-09-29 19:01:30 +08006122 for (i = 0, j = 0; i < adapter->mc_addr_list.mc_cnt; i++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006123 if (!memcmp(adapter->mc_addr_list.addr[i],
6124 &pattern, 1)) {
Frank Liuf95e8132016-09-29 19:01:30 +08006125 memcpy(filter->multicastAddr[j].bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006126 adapter->mc_addr_list.addr[i],
6127 sizeof(adapter->mc_addr_list.addr[i]));
Frank Liuf95e8132016-09-29 19:01:30 +08006128
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006129 hdd_debug("%s RX filter : addr ="
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006130 MAC_ADDRESS_STR,
6131 action ? "setting" : "clearing",
Frank Liuf95e8132016-09-29 19:01:30 +08006132 MAC_ADDR_ARRAY(filter->multicastAddr[j].bytes));
6133 j++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006134 }
6135 }
Frank Liuf95e8132016-09-29 19:01:30 +08006136 filter->ulMulticastAddrCnt = j;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006137 /* Set rx filter */
6138 sme_8023_multicast_list(handle, adapter->sessionId, filter);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306139 qdf_mem_free(filter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006140 } else {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006141 hdd_debug("mode %d mc_cnt %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006142 adapter->device_mode, adapter->mc_addr_list.mc_cnt);
6143 }
6144
6145 return 0;
6146}
6147
6148/**
6149 * hdd_driver_rxfilter_comand_handler() - RXFILTER driver command handler
6150 * @command: Pointer to input string driver command
6151 * @adapter: Pointer to adapter
6152 * @action: Action to enable/disable filtering
6153 *
6154 * If action == false
6155 * Start filtering out data packets based on type
6156 * RXFILTER-REMOVE 0 -> Start filtering out unicast data packets
6157 * RXFILTER-REMOVE 1 -> Start filtering out broadcast data packets
6158 * RXFILTER-REMOVE 2 -> Start filtering out IPV4 mcast data packets
6159 * RXFILTER-REMOVE 3 -> Start filtering out IPV6 mcast data packets
6160 *
6161 * if action == true
6162 * Stop filtering data packets based on type
6163 * RXFILTER-ADD 0 -> Stop filtering unicast data packets
6164 * RXFILTER-ADD 1 -> Stop filtering broadcast data packets
6165 * RXFILTER-ADD 2 -> Stop filtering IPV4 mcast data packets
6166 * RXFILTER-ADD 3 -> Stop filtering IPV6 mcast data packets
6167 *
6168 * Current implementation only supports IPV4 address filtering by
6169 * selectively allowing IPV4 multicast data packest based on
6170 * address list received in .ndo_set_rx_mode
6171 *
6172 * Return: 0 for success, non-zero for failure
6173 */
6174static int hdd_driver_rxfilter_comand_handler(uint8_t *command,
6175 hdd_adapter_t *adapter,
6176 bool action)
6177{
6178 int ret = 0;
6179 uint8_t *value;
6180 uint8_t type;
6181
6182 value = command;
6183 /* Skip space after RXFILTER-REMOVE OR RXFILTER-ADD based on action */
6184 if (!action)
6185 value = command + 16;
6186 else
6187 value = command + 13;
6188 ret = kstrtou8(value, 10, &type);
6189 if (ret < 0) {
6190 hdd_err("kstrtou8 failed invalid input value %d", type);
6191 return -EINVAL;
6192 }
6193
6194 switch (type) {
6195 case 2:
6196 /* Set rx filter for IPV4 multicast data packets */
6197 ret = hdd_set_rx_filter(adapter, action, 0x01);
6198 break;
6199 default:
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006200 hdd_warn("Unsupported RXFILTER type %d", type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006201 break;
6202 }
6203
6204 return ret;
6205}
6206
6207/**
6208 * drv_cmd_rx_filter_remove() - RXFILTER REMOVE driver command handler
6209 * @adapter: Pointer to network adapter
6210 * @hdd_ctx: Pointer to hdd context
6211 * @command: Pointer to input command
6212 * @command_len: Command length
6213 * @priv_data: Pointer to private data in command
6214 */
6215static int drv_cmd_rx_filter_remove(hdd_adapter_t *adapter,
6216 hdd_context_t *hdd_ctx,
6217 uint8_t *command,
6218 uint8_t command_len,
6219 hdd_priv_data_t *priv_data)
6220{
6221 return hdd_driver_rxfilter_comand_handler(command, adapter, false);
6222}
6223
6224/**
6225 * drv_cmd_rx_filter_add() - RXFILTER ADD driver command handler
6226 * @adapter: Pointer to network adapter
6227 * @hdd_ctx: Pointer to hdd context
6228 * @command: Pointer to input command
6229 * @command_len: Command length
6230 * @priv_data: Pointer to private data in command
6231 */
6232static int drv_cmd_rx_filter_add(hdd_adapter_t *adapter,
6233 hdd_context_t *hdd_ctx,
6234 uint8_t *command,
6235 uint8_t command_len,
6236 hdd_priv_data_t *priv_data)
6237{
6238 return hdd_driver_rxfilter_comand_handler(command, adapter, true);
6239}
6240
Archana Ramachandran393f3792015-11-13 17:13:21 -08006241/**
6242 * hdd_parse_setantennamode_command() - HDD Parse SETANTENNAMODE
6243 * command
6244 * @value: Pointer to SETANTENNAMODE command
6245 * @mode: Pointer to antenna mode
6246 * @reason: Pointer to reason for set antenna mode
6247 *
6248 * This function parses the SETANTENNAMODE command passed in the format
6249 * SETANTENNAMODE<space>mode
6250 *
6251 * Return: 0 for success non-zero for failure
6252 */
6253static int hdd_parse_setantennamode_command(const uint8_t *value)
6254{
6255 const uint8_t *in_ptr = value;
6256 int tmp, v;
6257 char arg1[32];
6258
6259 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
6260
6261 /* no argument after the command */
6262 if (NULL == in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006263 hdd_err("No argument after the command");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006264 return -EINVAL;
6265 }
6266
6267 /* no space after the command */
6268 if (SPACE_ASCII_VALUE != *in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006269 hdd_err("No space after the command");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006270 return -EINVAL;
6271 }
6272
6273 /* remove empty spaces */
6274 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
6275 in_ptr++;
6276
6277 /* no argument followed by spaces */
6278 if ('\0' == *in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006279 hdd_err("No argument followed by spaces");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006280 return -EINVAL;
6281 }
6282
6283 /* get the argument i.e. antenna mode */
6284 v = sscanf(in_ptr, "%31s ", arg1);
6285 if (1 != v) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006286 hdd_err("argument retrieval from cmd string failed");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006287 return -EINVAL;
6288 }
6289
6290 v = kstrtos32(arg1, 10, &tmp);
6291 if (v < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006292 hdd_err("argument string to int conversion failed");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006293 return -EINVAL;
6294 }
6295
6296 return tmp;
6297}
6298
6299/**
6300 * hdd_is_supported_chain_mask_2x2() - Verify if supported chain
6301 * mask is 2x2 mode
6302 * @hdd_ctx: Pointer to hdd contex
6303 *
6304 * Return: true if supported chain mask 2x2 else false
6305 */
6306static bool hdd_is_supported_chain_mask_2x2(hdd_context_t *hdd_ctx)
6307{
6308 /*
6309 * Revisit and the update logic to determine the number
6310 * of TX/RX chains supported in the system when
6311 * antenna sharing per band chain mask support is
6312 * brought in
6313 */
6314 return (hdd_ctx->config->enable2x2 == 0x01) ? true : false;
6315}
6316
6317/**
6318 * hdd_is_supported_chain_mask_1x1() - Verify if the supported
6319 * chain mask is 1x1
6320 * @hdd_ctx: Pointer to hdd contex
6321 *
6322 * Return: true if supported chain mask 1x1 else false
6323 */
6324static bool hdd_is_supported_chain_mask_1x1(hdd_context_t *hdd_ctx)
6325{
6326 /*
6327 * Revisit and update the logic to determine the number
6328 * of TX/RX chains supported in the system when
6329 * antenna sharing per band chain mask support is
6330 * brought in
6331 */
6332 return (!hdd_ctx->config->enable2x2) ? true : false;
6333}
6334
6335/**
6336 * drv_cmd_set_antenna_mode() - SET ANTENNA MODE driver command
6337 * handler
6338 * @adapter: Pointer to network adapter
6339 * @hdd_ctx: Pointer to hdd context
6340 * @command: Pointer to input command
6341 * @command_len: Command length
6342 * @priv_data: Pointer to private data in command
6343 */
6344static int drv_cmd_set_antenna_mode(hdd_adapter_t *adapter,
6345 hdd_context_t *hdd_ctx,
6346 uint8_t *command,
6347 uint8_t command_len,
6348 hdd_priv_data_t *priv_data)
6349{
6350 struct sir_antenna_mode_param params;
6351 QDF_STATUS status;
6352 int ret = 0;
6353 int mode;
6354 uint8_t *value = command;
6355 uint8_t smps_mode;
6356 uint8_t smps_enable;
6357
6358 if (((1 << QDF_STA_MODE) != hdd_ctx->concurrency_mode) ||
6359 (hdd_ctx->no_of_active_sessions[QDF_STA_MODE] > 1)) {
6360 hdd_err("Operation invalid in non sta or concurrent mode");
6361 ret = -EPERM;
6362 goto exit;
6363 }
6364
6365 mode = hdd_parse_setantennamode_command(value);
6366 if (mode < 0) {
6367 hdd_err("Invalid SETANTENNA command");
6368 ret = mode;
6369 goto exit;
6370 }
6371
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006372 hdd_debug("Processing antenna mode switch to: %d", mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006373
6374 if (hdd_ctx->current_antenna_mode == mode) {
6375 hdd_err("System already in the requested mode");
6376 ret = 0;
6377 goto exit;
6378 }
6379
6380 if ((HDD_ANTENNA_MODE_2X2 == mode) &&
6381 (!hdd_is_supported_chain_mask_2x2(hdd_ctx))) {
6382 hdd_err("System does not support 2x2 mode");
6383 ret = -EPERM;
6384 goto exit;
6385 }
6386
6387 if ((HDD_ANTENNA_MODE_1X1 == mode) &&
6388 hdd_is_supported_chain_mask_1x1(hdd_ctx)) {
6389 hdd_err("System only supports 1x1 mode");
6390 ret = 0;
6391 goto exit;
6392 }
6393
6394 switch (mode) {
6395 case HDD_ANTENNA_MODE_1X1:
6396 params.num_rx_chains = 1;
6397 params.num_tx_chains = 1;
6398 break;
6399 case HDD_ANTENNA_MODE_2X2:
6400 params.num_rx_chains = 2;
6401 params.num_tx_chains = 2;
6402 break;
6403 default:
6404 hdd_err("unsupported antenna mode");
6405 ret = -EINVAL;
6406 goto exit;
6407 }
6408
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006409 /* Check TDLS status and update antenna mode */
6410 if ((QDF_STA_MODE == adapter->device_mode) &&
Tushnim Bhattacharyyade1070d2017-03-09 13:23:55 -08006411 policy_mgr_is_sta_active_connection_exists(
6412 hdd_ctx->hdd_psoc)) {
Archana Ramachandran2ad7de22016-04-22 16:53:25 -07006413 ret = wlan_hdd_tdls_antenna_switch(hdd_ctx, adapter,
6414 mode);
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006415 if (0 != ret)
6416 goto exit;
6417 }
6418
Archana Ramachandran393f3792015-11-13 17:13:21 -08006419 params.set_antenna_mode_resp =
6420 (void *)wlan_hdd_soc_set_antenna_mode_cb;
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006421 hdd_debug("Set antenna mode rx chains: %d tx chains: %d",
Archana Ramachandran393f3792015-11-13 17:13:21 -08006422 params.num_rx_chains,
6423 params.num_tx_chains);
6424
6425
6426 INIT_COMPLETION(hdd_ctx->set_antenna_mode_cmpl);
6427 status = sme_soc_set_antenna_mode(hdd_ctx->hHal, &params);
6428 if (QDF_STATUS_SUCCESS != status) {
6429 hdd_err("set antenna mode failed status : %d", status);
6430 ret = -EFAULT;
6431 goto exit;
6432 }
6433
6434 ret = wait_for_completion_timeout(
6435 &hdd_ctx->set_antenna_mode_cmpl,
6436 msecs_to_jiffies(WLAN_WAIT_TIME_ANTENNA_MODE_REQ));
6437 if (!ret) {
6438 ret = -EFAULT;
6439 hdd_err("send set antenna mode timed out");
6440 goto exit;
6441 }
6442
6443 /* Update SME SMPS config */
6444 if (HDD_ANTENNA_MODE_1X1 == mode) {
6445 smps_enable = true;
6446 smps_mode = HDD_SMPS_MODE_STATIC;
6447 } else {
6448 smps_enable = false;
6449 smps_mode = HDD_SMPS_MODE_DISABLED;
6450 }
6451
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006452 hdd_debug("Update SME SMPS enable: %d mode: %d",
Archana Ramachandran393f3792015-11-13 17:13:21 -08006453 smps_enable, smps_mode);
6454 status = sme_update_mimo_power_save(
6455 hdd_ctx->hHal, smps_enable, smps_mode, false);
6456 if (QDF_STATUS_SUCCESS != status) {
6457 hdd_err("Update SMPS config failed enable: %d mode: %d status: %d",
6458 smps_enable, smps_mode, status);
6459 ret = -EFAULT;
6460 goto exit;
6461 }
6462
Archana Ramachandran393f3792015-11-13 17:13:21 -08006463 hdd_ctx->current_antenna_mode = mode;
Archana Ramachandran5041b252016-04-25 14:29:25 -07006464 /* Update the user requested nss in the mac context.
6465 * This will be used in tdls protocol engine to form tdls
6466 * Management frames.
6467 */
6468 sme_update_user_configured_nss(
6469 hdd_ctx->hHal,
6470 hdd_ctx->current_antenna_mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006471
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006472 hdd_debug("Successfully switched to mode: %d x %d",
Archana Ramachandran5041b252016-04-25 14:29:25 -07006473 hdd_ctx->current_antenna_mode,
6474 hdd_ctx->current_antenna_mode);
6475 ret = 0;
Archana Ramachandran393f3792015-11-13 17:13:21 -08006476exit:
Kabilan Kannanff89f742016-08-15 18:14:10 -07006477#ifdef FEATURE_WLAN_TDLS
6478 /* Reset tdls NSS flags */
6479 if (hdd_ctx->tdls_nss_switch_in_progress &&
6480 hdd_ctx->tdls_nss_teardown_complete) {
6481 hdd_ctx->tdls_nss_switch_in_progress = false;
6482 hdd_ctx->tdls_nss_teardown_complete = false;
6483 }
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006484 hdd_debug("tdls_nss_switch_in_progress: %d tdls_nss_teardown_complete: %d",
Kabilan Kannanff89f742016-08-15 18:14:10 -07006485 hdd_ctx->tdls_nss_switch_in_progress,
6486 hdd_ctx->tdls_nss_teardown_complete);
6487#endif
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006488 hdd_debug("Set antenna status: %d current mode: %d",
Archana Ramachandran393f3792015-11-13 17:13:21 -08006489 ret, hdd_ctx->current_antenna_mode);
6490 return ret;
6491
6492}
6493
6494/**
6495 * drv_cmd_get_antenna_mode() - GET ANTENNA MODE driver command
6496 * handler
6497 * @adapter: Pointer to hdd adapter
6498 * @hdd_ctx: Pointer to hdd context
6499 * @command: Pointer to input command
6500 * @command_len: length of the command
6501 * @priv_data: private data coming with the driver command
6502 *
6503 * Return: 0 for success non-zero for failure
6504 */
6505static inline int drv_cmd_get_antenna_mode(hdd_adapter_t *adapter,
6506 hdd_context_t *hdd_ctx,
6507 uint8_t *command,
6508 uint8_t command_len,
6509 hdd_priv_data_t *priv_data)
6510{
6511 uint32_t antenna_mode = 0;
6512 char extra[32];
6513 uint8_t len = 0;
6514
6515 antenna_mode = hdd_ctx->current_antenna_mode;
6516 len = scnprintf(extra, sizeof(extra), "%s %d", command,
6517 antenna_mode);
6518 len = QDF_MIN(priv_data->total_len, len + 1);
6519 if (copy_to_user(priv_data->buf, &extra, len)) {
6520 hdd_err("Failed to copy data to user buffer");
6521 return -EFAULT;
6522 }
6523
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006524 hdd_debug("Get antenna mode: %d", antenna_mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006525
6526 return 0;
6527}
6528
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006529/*
6530 * dummy (no-op) hdd driver command handler
6531 */
6532static int drv_cmd_dummy(hdd_adapter_t *adapter,
6533 hdd_context_t *hdd_ctx,
6534 uint8_t *command,
6535 uint8_t command_len,
6536 hdd_priv_data_t *priv_data)
6537{
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006538 hdd_debug("%s: Ignoring driver command \"%s\"",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006539 adapter->dev->name, command);
6540 return 0;
6541}
6542
6543/*
6544 * handler for any unsupported wlan hdd driver command
6545 */
6546static int drv_cmd_invalid(hdd_adapter_t *adapter,
6547 hdd_context_t *hdd_ctx,
6548 uint8_t *command,
6549 uint8_t command_len,
6550 hdd_priv_data_t *priv_data)
6551{
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306552 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006553 TRACE_CODE_HDD_UNSUPPORTED_IOCTL,
6554 adapter->sessionId, 0));
6555
6556 hdd_warn("%s: Unsupported driver command \"%s\"",
6557 adapter->dev->name, command);
6558
6559 return -ENOTSUPP;
6560}
6561
6562/**
6563 * drv_cmd_set_fcc_channel() - handle fcc constraint request
6564 * @adapter: HDD adapter
6565 * @hdd_ctx: HDD context
6566 * @command: command ptr, SET_FCC_CHANNEL 0/1 is the command
6567 * @command_len: command len
6568 * @priv_data: private data
6569 *
6570 * Return: status
6571 */
6572static int drv_cmd_set_fcc_channel(hdd_adapter_t *adapter,
6573 hdd_context_t *hdd_ctx,
6574 uint8_t *command,
6575 uint8_t command_len,
6576 hdd_priv_data_t *priv_data)
6577{
6578 uint8_t *value;
6579 uint8_t fcc_constraint;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306580 QDF_STATUS status;
Amar Singhal83a047a2016-05-19 15:56:11 -07006581 bool scan_pending;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006582 int ret = 0;
6583
6584 /*
6585 * this command would be called by user-space when it detects WLAN
6586 * ON after airplane mode is set. When APM is set, WLAN turns off.
6587 * But it can be turned back on. Otherwise; when APM is turned back
6588 * off, WLAN would turn back on. So at that point the command is
6589 * expected to come down. 0 means disable, 1 means enable. The
6590 * constraint is removed when parameter 1 is set or different
6591 * country code is set
6592 */
6593
6594 value = command + command_len + 1;
6595
6596 ret = kstrtou8(value, 10, &fcc_constraint);
6597 if ((ret < 0) || (fcc_constraint > 1)) {
6598 /*
6599 * If the input value is greater than max value of datatype,
6600 * then also it is a failure
6601 */
6602 hdd_err("value out of range");
6603 return -EINVAL;
6604 }
Sandeep Puligillad0004212017-02-26 18:34:56 -08006605#ifndef NAPIER_SCAN
6606 /* This code will be removed*/
Amar Singhal83a047a2016-05-19 15:56:11 -07006607 scan_pending = !qdf_list_empty(&hdd_ctx->hdd_scan_req_q);
Sandeep Puligillad0004212017-02-26 18:34:56 -08006608#else
6609 scan_pending = ucfg_scan_get_pdev_status(hdd_ctx->hdd_pdev);
6610#endif
Amar Singhal83a047a2016-05-19 15:56:11 -07006611 status = sme_handle_set_fcc_channel(hdd_ctx->hHal, !fcc_constraint,
6612 scan_pending);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306613 if (status != QDF_STATUS_SUCCESS) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006614 hdd_err("sme disable fn. returned err");
6615 ret = -EPERM;
6616 }
6617
6618 return ret;
6619}
6620
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306621/**
6622 * hdd_parse_set_channel_switch_command() - Parse and validate CHANNEL_SWITCH
6623 * command
6624 * @value: Pointer to the command
6625 * @chan_number: Pointer to the channel number
6626 * @chan_bw: Pointer to the channel bandwidth
6627 *
6628 * Parses and provides the channel number and channel width from the input
6629 * command which is expected to be of the format: CHANNEL_SWITCH <CH> <BW>
6630 * <CH> is channel number to move (where 1 = channel 1, 149 = channel 149, ...)
6631 * <BW> is bandwidth to move (where 20 = BW 20, 40 = BW 40, 80 = BW 80)
6632 *
6633 * Return: 0 for success, non-zero for failure
6634 */
6635static int hdd_parse_set_channel_switch_command(uint8_t *value,
6636 uint32_t *chan_number,
6637 uint32_t *chan_bw)
6638{
6639 const uint8_t *in_ptr = value;
6640 int ret;
6641
6642 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
6643
6644 /* no argument after the command */
6645 if (NULL == in_ptr) {
6646 hdd_err("No argument after the command");
6647 return -EINVAL;
6648 }
6649
6650 /* no space after the command */
6651 if (SPACE_ASCII_VALUE != *in_ptr) {
6652 hdd_err("No space after the command ");
6653 return -EINVAL;
6654 }
6655
6656 /* remove empty spaces and move the next argument */
6657 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
6658 in_ptr++;
6659
6660 /* no argument followed by spaces */
6661 if ('\0' == *in_ptr) {
6662 hdd_err("No argument followed by spaces");
6663 return -EINVAL;
6664 }
6665
6666 /* get the two arguments: channel number and bandwidth */
6667 ret = sscanf(in_ptr, "%u %u", chan_number, chan_bw);
6668 if (ret != 2) {
6669 hdd_err("Arguments retrieval from cmd string failed");
6670 return -EINVAL;
6671 }
6672
6673 return 0;
6674}
6675
6676/**
6677 * drv_cmd_set_channel_switch() - Switch SAP/P2P-GO operating channel
6678 * @adapter: HDD adapter
6679 * @hdd_ctx: HDD context
6680 * @command: Pointer to the input command CHANNEL_SWITCH
6681 * @command_len: Command len
6682 * @priv_data: Private data
6683 *
6684 * Handles private IOCTL CHANNEL_SWITCH command to switch the operating channel
6685 * of SAP/P2P-GO
6686 *
6687 * Return: 0 for success, non-zero for failure
6688 */
6689static int drv_cmd_set_channel_switch(hdd_adapter_t *adapter,
6690 hdd_context_t *hdd_ctx,
6691 uint8_t *command,
6692 uint8_t command_len,
6693 hdd_priv_data_t *priv_data)
6694{
6695 struct net_device *dev = adapter->dev;
6696 int status;
6697 uint32_t chan_number = 0, chan_bw = 0;
6698 uint8_t *value = command;
Kiran Kumar Lokere13644672016-02-29 15:40:10 -08006699 enum phy_ch_width width;
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306700
Krunal Sonibe766b02016-03-10 13:00:44 -08006701 if ((adapter->device_mode != QDF_P2P_GO_MODE) &&
6702 (adapter->device_mode != QDF_SAP_MODE)) {
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306703 hdd_err("IOCTL CHANNEL_SWITCH not supported for mode %d",
6704 adapter->device_mode);
6705 return -EINVAL;
6706 }
6707
6708 status = hdd_parse_set_channel_switch_command(value,
6709 &chan_number, &chan_bw);
6710 if (status) {
6711 hdd_err("Invalid CHANNEL_SWITCH command");
6712 return status;
6713 }
6714
6715 if ((chan_bw != 20) && (chan_bw != 40) && (chan_bw != 80)) {
6716 hdd_err("BW %d is not allowed for CHANNEL_SWITCH", chan_bw);
6717 return -EINVAL;
6718 }
6719
6720 if (chan_bw == 80)
6721 width = CH_WIDTH_80MHZ;
6722 else if (chan_bw == 40)
6723 width = CH_WIDTH_40MHZ;
6724 else
6725 width = CH_WIDTH_20MHZ;
6726
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006727 hdd_debug("CH:%d BW:%d", chan_number, chan_bw);
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306728
6729 status = hdd_softap_set_channel_change(dev, chan_number, width);
6730 if (status) {
6731 hdd_err("Set channel change fail");
6732 return status;
6733 }
6734
6735 return 0;
6736}
6737
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006738/*
6739 * The following table contains all supported WLAN HDD
6740 * IOCTL driver commands and the handler for each of them.
6741 */
Srinivas Girigowda91a6b632017-03-25 13:57:14 -07006742static const struct hdd_drv_cmd hdd_drv_cmds[] = {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006743 {"P2P_DEV_ADDR", drv_cmd_p2p_dev_addr},
6744 {"P2P_SET_NOA", drv_cmd_p2p_set_noa},
6745 {"P2P_SET_PS", drv_cmd_p2p_set_ps},
6746 {"SETBAND", drv_cmd_set_band},
6747 {"SETWMMPS", drv_cmd_set_wmmps},
6748 {"COUNTRY", drv_cmd_country},
6749 {"SETSUSPENDMODE", drv_cmd_dummy},
6750 {"SET_AP_WPS_P2P_IE", drv_cmd_dummy},
6751 {"BTCOEXSCAN", drv_cmd_dummy},
6752 {"RXFILTER", drv_cmd_dummy},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006753 {"SETROAMTRIGGER", drv_cmd_set_roam_trigger},
6754 {"GETROAMTRIGGER", drv_cmd_get_roam_trigger},
6755 {"SETROAMSCANPERIOD", drv_cmd_set_roam_scan_period},
6756 {"GETROAMSCANPERIOD", drv_cmd_get_roam_scan_period},
6757 {"SETROAMSCANREFRESHPERIOD", drv_cmd_set_roam_scan_refresh_period},
6758 {"GETROAMSCANREFRESHPERIOD", drv_cmd_get_roam_scan_refresh_period},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006759 {"SETROAMMODE", drv_cmd_set_roam_mode},
6760 {"GETROAMMODE", drv_cmd_get_roam_mode},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006761 {"SETROAMDELTA", drv_cmd_set_roam_delta},
6762 {"GETROAMDELTA", drv_cmd_get_roam_delta},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006763 {"GETBAND", drv_cmd_get_band},
6764 {"SETROAMSCANCHANNELS", drv_cmd_set_roam_scan_channels},
6765 {"GETROAMSCANCHANNELS", drv_cmd_get_roam_scan_channels},
6766 {"GETCCXMODE", drv_cmd_get_ccx_mode},
6767 {"GETOKCMODE", drv_cmd_get_okc_mode},
6768 {"GETFASTROAM", drv_cmd_get_fast_roam},
6769 {"GETFASTTRANSITION", drv_cmd_get_fast_transition},
6770 {"SETROAMSCANCHANNELMINTIME", drv_cmd_set_roam_scan_channel_min_time},
6771 {"SENDACTIONFRAME", drv_cmd_send_action_frame},
6772 {"GETROAMSCANCHANNELMINTIME", drv_cmd_get_roam_scan_channel_min_time},
6773 {"SETSCANCHANNELTIME", drv_cmd_set_scan_channel_time},
6774 {"GETSCANCHANNELTIME", drv_cmd_get_scan_channel_time},
6775 {"SETSCANHOMETIME", drv_cmd_set_scan_home_time},
6776 {"GETSCANHOMETIME", drv_cmd_get_scan_home_time},
6777 {"SETROAMINTRABAND", drv_cmd_set_roam_intra_band},
6778 {"GETROAMINTRABAND", drv_cmd_get_roam_intra_band},
6779 {"SETSCANNPROBES", drv_cmd_set_scan_n_probes},
6780 {"GETSCANNPROBES", drv_cmd_get_scan_n_probes},
6781 {"SETSCANHOMEAWAYTIME", drv_cmd_set_scan_home_away_time},
6782 {"GETSCANHOMEAWAYTIME", drv_cmd_get_scan_home_away_time},
6783 {"REASSOC", drv_cmd_reassoc},
6784 {"SETWESMODE", drv_cmd_set_wes_mode},
6785 {"GETWESMODE", drv_cmd_get_wes_mode},
6786 {"SETOPPORTUNISTICRSSIDIFF", drv_cmd_set_opportunistic_rssi_diff},
6787 {"GETOPPORTUNISTICRSSIDIFF", drv_cmd_get_opportunistic_rssi_diff},
6788 {"SETROAMRESCANRSSIDIFF", drv_cmd_set_roam_rescan_rssi_diff},
6789 {"GETROAMRESCANRSSIDIFF", drv_cmd_get_roam_rescan_rssi_diff},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006790 {"SETFASTROAM", drv_cmd_set_fast_roam},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006791 {"SETFASTTRANSITION", drv_cmd_set_fast_transition},
6792 {"FASTREASSOC", drv_cmd_fast_reassoc},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006793 {"SETROAMSCANCONTROL", drv_cmd_set_roam_scan_control},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006794 {"SETOKCMODE", drv_cmd_set_okc_mode},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006795 {"GETROAMSCANCONTROL", drv_cmd_get_roam_scan_control},
6796 {"BTCOEXMODE", drv_cmd_bt_coex_mode},
6797 {"SCAN-ACTIVE", drv_cmd_scan_active},
6798 {"SCAN-PASSIVE", drv_cmd_scan_passive},
6799 {"GETDWELLTIME", drv_cmd_get_dwell_time},
6800 {"SETDWELLTIME", drv_cmd_set_dwell_time},
6801 {"MIRACAST", drv_cmd_miracast},
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08006802 {"SETIBSSBEACONOUIDATA", drv_cmd_set_ibss_beacon_oui_data},
6803 {"SETRMCENABLE", drv_cmd_set_rmc_enable},
6804 {"SETRMCACTIONPERIOD", drv_cmd_set_rmc_action_period},
6805 {"GETIBSSPEERINFOALL", drv_cmd_get_ibss_peer_info_all},
6806 {"GETIBSSPEERINFO", drv_cmd_get_ibss_peer_info},
6807 {"SETRMCTXRATE", drv_cmd_set_rmc_tx_rate},
6808 {"SETIBSSTXFAILEVENT", drv_cmd_set_ibss_tx_fail_event},
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08006809#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006810 {"SETCCXROAMSCANCHANNELS", drv_cmd_set_ccx_roam_scan_channels},
6811 {"GETTSMSTATS", drv_cmd_get_tsm_stats},
6812 {"SETCCKMIE", drv_cmd_set_cckm_ie},
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07006813 {"CCXBEACONREQ", drv_cmd_ccx_beacon_req},
6814 {"CCXPLMREQ", drv_cmd_ccx_plm_req},
6815 {"SETCCXMODE", drv_cmd_set_ccx_mode},
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08006816#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006817 {"SETMCRATE", drv_cmd_set_mc_rate},
6818 {"MAXTXPOWER", drv_cmd_max_tx_power},
6819 {"SETDFSSCANMODE", drv_cmd_set_dfs_scan_mode},
6820 {"GETDFSSCANMODE", drv_cmd_get_dfs_scan_mode},
6821 {"GETLINKSTATUS", drv_cmd_get_link_status},
6822#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
6823 {"ENABLEEXTWOW", drv_cmd_enable_ext_wow},
6824 {"SETAPP1PARAMS", drv_cmd_set_app1_params},
6825 {"SETAPP2PARAMS", drv_cmd_set_app2_params},
6826#endif
6827#ifdef FEATURE_WLAN_TDLS
6828 {"TDLSSECONDARYCHANNELOFFSET", drv_cmd_tdls_secondary_channel_offset},
6829 {"TDLSOFFCHANNELMODE", drv_cmd_tdls_off_channel_mode},
6830 {"TDLSOFFCHANNEL", drv_cmd_tdls_off_channel},
6831 {"TDLSSCAN", drv_cmd_tdls_scan},
6832#endif
6833 {"RSSI", drv_cmd_get_rssi},
6834 {"LINKSPEED", drv_cmd_get_linkspeed},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006835 {"RXFILTER-REMOVE", drv_cmd_rx_filter_remove},
6836 {"RXFILTER-ADD", drv_cmd_rx_filter_add},
6837 {"SET_FCC_CHANNEL", drv_cmd_set_fcc_channel},
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306838 {"CHANNEL_SWITCH", drv_cmd_set_channel_switch},
Archana Ramachandran393f3792015-11-13 17:13:21 -08006839 {"SETANTENNAMODE", drv_cmd_set_antenna_mode},
6840 {"GETANTENNAMODE", drv_cmd_get_antenna_mode},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006841};
6842
6843/**
6844 * hdd_drv_cmd_process() - chooses and runs the proper
6845 * handler based on the input command
6846 * @adapter: Pointer to the hdd adapter
6847 * @cmd: Pointer to the driver command
6848 * @priv_data: Pointer to the data associated with the command
6849 *
6850 * This function parses the input hdd driver command and runs
6851 * the proper handler
6852 *
6853 * Return: 0 for success non-zero for failure
6854 */
6855static int hdd_drv_cmd_process(hdd_adapter_t *adapter,
6856 uint8_t *cmd,
6857 hdd_priv_data_t *priv_data)
6858{
6859 hdd_context_t *hdd_ctx;
6860 int i;
6861 const int cmd_num_total = ARRAY_SIZE(hdd_drv_cmds);
6862 uint8_t *cmd_i = NULL;
6863 hdd_drv_cmd_handler_t handler = NULL;
6864 int len = 0;
6865
6866 if (!adapter || !cmd || !priv_data) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006867 hdd_err("at least 1 param is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006868 return -EINVAL;
6869 }
6870
6871 hdd_ctx = (hdd_context_t *)adapter->pHddCtx;
6872
6873 for (i = 0; i < cmd_num_total; i++) {
6874
6875 cmd_i = (uint8_t *)hdd_drv_cmds[i].cmd;
6876 handler = hdd_drv_cmds[i].handler;
6877 len = strlen(cmd_i);
6878
6879 if (!handler) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006880 hdd_err("no. %d handler is NULL", i);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006881 return -EINVAL;
6882 }
6883
6884 if (strncasecmp(cmd, cmd_i, len) == 0)
6885 return handler(adapter, hdd_ctx,
6886 cmd, len, priv_data);
6887 }
6888
6889 return drv_cmd_invalid(adapter, hdd_ctx, cmd, len, priv_data);
6890}
6891
6892/**
6893 * hdd_driver_command() - top level wlan hdd driver command handler
6894 * @adapter: Pointer to the hdd adapter
6895 * @priv_data: Pointer to the raw command data
6896 *
6897 * This function is the top level wlan hdd driver command handler. It
6898 * handles the command with the help of hdd_drv_cmd_process()
6899 *
6900 * Return: 0 for success non-zero for failure
6901 */
6902static int hdd_driver_command(hdd_adapter_t *adapter,
6903 hdd_priv_data_t *priv_data)
6904{
6905 uint8_t *command = NULL;
6906 int ret = 0;
Ashish Kumar Dhanotiyaff4e1c42017-03-14 15:54:05 +05306907 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006908
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05306909 ENTER();
6910
Anurag Chouhan6d760662016-02-20 16:05:43 +05306911 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006912 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006913 return -EINVAL;
6914 }
6915
Ashish Kumar Dhanotiyaff4e1c42017-03-14 15:54:05 +05306916 ret = wlan_hdd_validate_context(hdd_ctx);
6917 if (ret)
6918 return ret;
6919
6920 if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) {
6921 hdd_err("Driver module is closed; command can not be processed");
6922 return -EINVAL;
6923 }
6924
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006925 /*
6926 * Note that valid pointers are provided by caller
6927 */
6928
6929 /* copy to local struct to avoid numerous changes to legacy code */
6930 if (priv_data->total_len <= 0 ||
6931 priv_data->total_len > WLAN_PRIV_DATA_MAX_LEN) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006932 hdd_warn("Invalid priv_data.total_len: %d!!!",
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006933 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006934 ret = -EINVAL;
6935 goto exit;
6936 }
6937
6938 /* Allocate +1 for '\0' */
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07006939 command = qdf_mem_malloc(priv_data->total_len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006940 if (!command) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006941 hdd_err("failed to allocate memory");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006942 ret = -ENOMEM;
6943 goto exit;
6944 }
6945
6946 if (copy_from_user(command, priv_data->buf, priv_data->total_len)) {
6947 ret = -EFAULT;
6948 goto exit;
6949 }
6950
6951 /* Make sure the command is NUL-terminated */
6952 command[priv_data->total_len] = '\0';
6953
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08006954 hdd_debug("%s: %s", adapter->dev->name, command);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006955 ret = hdd_drv_cmd_process(adapter, command, priv_data);
6956
6957exit:
6958 if (command)
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07006959 qdf_mem_free(command);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05306960 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006961 return ret;
6962}
6963
6964#ifdef CONFIG_COMPAT
6965static int hdd_driver_compat_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
6966{
6967 struct {
6968 compat_uptr_t buf;
6969 int used_len;
6970 int total_len;
6971 } compat_priv_data;
6972 hdd_priv_data_t priv_data;
6973 int ret = 0;
6974
6975 /*
6976 * Note that adapter and ifr have already been verified by caller,
6977 * and HDD context has also been validated
6978 */
6979 if (copy_from_user(&compat_priv_data, ifr->ifr_data,
6980 sizeof(compat_priv_data))) {
6981 ret = -EFAULT;
6982 goto exit;
6983 }
6984 priv_data.buf = compat_ptr(compat_priv_data.buf);
6985 priv_data.used_len = compat_priv_data.used_len;
6986 priv_data.total_len = compat_priv_data.total_len;
6987 ret = hdd_driver_command(adapter, &priv_data);
6988exit:
6989 return ret;
6990}
6991#else /* CONFIG_COMPAT */
6992static int hdd_driver_compat_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
6993{
6994 /* will never be invoked */
6995 return 0;
6996}
6997#endif /* CONFIG_COMPAT */
6998
6999static int hdd_driver_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
7000{
7001 hdd_priv_data_t priv_data;
7002 int ret = 0;
7003
7004 /*
7005 * Note that adapter and ifr have already been verified by caller,
7006 * and HDD context has also been validated
7007 */
7008 if (copy_from_user(&priv_data, ifr->ifr_data, sizeof(priv_data)))
7009 ret = -EFAULT;
7010 else
7011 ret = hdd_driver_command(adapter, &priv_data);
7012
7013 return ret;
7014}
7015
7016/**
7017 * __hdd_ioctl() - ioctl handler for wlan network interfaces
7018 * @dev: device upon which the ioctl was received
7019 * @ifr: ioctl request information
7020 * @cmd: ioctl command
7021 *
7022 * This function does initial processing of wlan device ioctls.
7023 * Currently two flavors of ioctls are supported. The primary ioctl
7024 * that is supported is the (SIOCDEVPRIVATE + 1) ioctl which is used
7025 * for Android "DRIVER" commands. The other ioctl that is
7026 * conditionally supported is the SIOCIOCTLTX99 ioctl which is used
7027 * for FTM on some platforms. This function simply verifies that the
7028 * driver is in a sane state, and that the ioctl is one of the
7029 * supported flavors, in which case flavor-specific handlers are
7030 * dispatched.
7031 *
7032 * Return: 0 on success, non-zero on error
7033 */
7034static int __hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7035{
7036 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
7037 hdd_context_t *hdd_ctx;
7038 int ret;
7039
Jeff Johnson3c3994a2016-02-11 08:12:30 -08007040 ENTER_DEV(dev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307041
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007042 if (dev != adapter->dev) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08007043 hdd_err("HDD adapter/dev inconsistency");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007044 ret = -ENODEV;
7045 goto exit;
7046 }
7047
7048 if ((!ifr) || (!ifr->ifr_data)) {
Srinivas Girigowdadc99f842017-03-06 17:15:59 -08007049 hdd_err("invalid data cmd: %d", cmd);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007050 ret = -EINVAL;
7051 goto exit;
7052 }
7053#if defined(QCA_WIFI_FTM) && defined(LINUX_QCMBR)
Anurag Chouhan6d760662016-02-20 16:05:43 +05307054 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007055 if (SIOCIOCTLTX99 == cmd) {
7056 ret = wlan_hdd_qcmbr_unified_ioctl(adapter, ifr);
7057 goto exit;
7058 }
7059 }
7060#endif
7061
7062 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
7063 ret = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307064 if (ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007065 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007066
7067 switch (cmd) {
7068 case (SIOCDEVPRIVATE + 1):
7069 if (is_compat_task())
7070 ret = hdd_driver_compat_ioctl(adapter, ifr);
7071 else
7072 ret = hdd_driver_ioctl(adapter, ifr);
7073 break;
7074 default:
Srinivas Girigowda86ecc012017-03-10 12:26:57 -08007075 hdd_warn("unknown ioctl %d", cmd);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007076 ret = -EINVAL;
7077 break;
7078 }
7079exit:
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307080 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007081 return ret;
7082}
7083
7084/**
7085 * hdd_ioctl() - ioctl handler (wrapper) for wlan network interfaces
7086 * @dev: device upon which the ioctl was received
7087 * @ifr: ioctl request information
7088 * @cmd: ioctl command
7089 *
7090 * This function acts as an SSR-protecting wrapper to __hdd_ioctl()
7091 * which is where the ioctls are really handled.
7092 *
7093 * Return: 0 on success, non-zero on error
7094 */
7095int hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7096{
7097 int ret;
7098
7099 cds_ssr_protect(__func__);
7100 ret = __hdd_ioctl(dev, ifr, cmd);
7101 cds_ssr_unprotect(__func__);
7102 return ret;
7103}