blob: fc3f3d1d6ff005c242d852f8bc318ddb12f64a36 [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Tushnim Bhattacharyyaca50b322015-12-28 17:14:36 -08002 * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/*
23 * This file was originally distributed by Qualcomm Atheros, Inc.
24 * under proprietary terms before Copyright ownership was assigned
25 * to the Linux Foundation.
26 */
27
28/* 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"
35#include "wlan_hdd_driver_ops.h"
36#include "cds_concurrency.h"
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +053037#include "wlan_hdd_hostapd.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080038
39#include "wlan_hdd_p2p.h"
40#include <linux/ctype.h>
41#include "wma.h"
42#include "wlan_hdd_napi.h"
43
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -080044#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080045#include <sme_api.h>
46#include <sir_api.h>
47#endif
48#include "hif.h"
49
50#if defined(LINUX_QCMBR)
51#define SIOCIOCTLTX99 (SIOCDEVPRIVATE+13)
52#endif
53
54/*
55 * Size of Driver command strings from upper layer
56 */
57#define SIZE_OF_SETROAMMODE 11 /* size of SETROAMMODE */
58#define SIZE_OF_GETROAMMODE 11 /* size of GETROAMMODE */
59
Rajeev Kumar8e3e2832015-11-06 16:02:54 -080060/*
61 * Ibss prop IE from command will be of size:
62 * size = sizeof(oui) + sizeof(oui_data) + 1(Element ID) + 1(EID Length)
63 * OUI_DATA should be at least 3 bytes long
64 */
65#define WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH (3)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080066
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -080067#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080068#define TID_MIN_VALUE 0
69#define TID_MAX_VALUE 15
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -080070#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080071
72/*
73 * Maximum buffer size used for returning the data back to user space
74 */
75#define WLAN_MAX_BUF_SIZE 1024
76#define WLAN_PRIV_DATA_MAX_LEN 8192
77
78/*
79 * Driver miracast parameters 0-Disabled
80 * 1-Source, 2-Sink
81 */
82#define WLAN_HDD_DRIVER_MIRACAST_CFG_MIN_VAL 0
83#define WLAN_HDD_DRIVER_MIRACAST_CFG_MAX_VAL 2
84
85/*
86 * When ever we need to print IBSSPEERINFOALL for more than 16 STA
87 * we will split the printing.
88 */
89#define NUM_OF_STA_DATA_TO_PRINT 16
90
91/*
92 * Android DRIVER command structures
93 */
94struct android_wifi_reassoc_params {
95 unsigned char bssid[18];
96 int channel;
97};
98
99#define ANDROID_WIFI_ACTION_FRAME_SIZE 1040
100struct android_wifi_af_params {
101 unsigned char bssid[18];
102 int channel;
103 int dwell_time;
104 int len;
105 unsigned char data[ANDROID_WIFI_ACTION_FRAME_SIZE];
106};
107
108/*
109 * Define HDD driver command handling entry, each contains a command
110 * string and the handler.
111 */
112typedef int (*hdd_drv_cmd_handler_t)(hdd_adapter_t *adapter,
113 hdd_context_t *hdd_ctx,
114 uint8_t *cmd,
115 uint8_t cmd_name_len,
116 hdd_priv_data_t *priv_data);
117
118typedef struct {
119 const char *cmd;
120 hdd_drv_cmd_handler_t handler;
121} hdd_drv_cmd_t;
122
123#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
124#define WLAN_WAIT_TIME_READY_TO_EXTWOW 2000
125#define WLAN_HDD_MAX_TCP_PORT 65535
126#endif
127
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800128static uint16_t cesium_pid;
129extern struct sock *cesium_nl_srv_sock;
130
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -0800131#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800132static void hdd_get_tsm_stats_cb(tAniTrafStrmMetrics tsm_metrics,
133 const uint32_t staId, void *context)
134{
135 struct statsContext *stats_context = NULL;
136 hdd_adapter_t *adapter = NULL;
137
138 if (NULL == context) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530139 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800140 "%s: Bad param, context [%p]", __func__, context);
141 return;
142 }
143
144 /*
145 * there is a race condition that exists between this callback
146 * function and the caller since the caller could time out either
147 * before or while this code is executing. we use a spinlock to
148 * serialize these actions
149 */
150 spin_lock(&hdd_context_lock);
151
152 stats_context = context;
153 adapter = stats_context->pAdapter;
154 if ((NULL == adapter) ||
155 (STATS_CONTEXT_MAGIC != stats_context->magic)) {
156 /*
157 * the caller presumably timed out so there is
158 * nothing we can do
159 */
160 spin_unlock(&hdd_context_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530161 hddLog(QDF_TRACE_LEVEL_WARN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800162 "%s: Invalid context, adapter [%p] magic [%08x]",
163 __func__, adapter, stats_context->magic);
164 return;
165 }
166
167 /* context is valid so caller is still waiting */
168
169 /* paranoia: invalidate the magic */
170 stats_context->magic = 0;
171
172 /* copy over the tsm stats */
173 adapter->tsmStats.UplinkPktQueueDly = tsm_metrics.UplinkPktQueueDly;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530174 qdf_mem_copy(adapter->tsmStats.UplinkPktQueueDlyHist,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800175 tsm_metrics.UplinkPktQueueDlyHist,
176 sizeof(adapter->tsmStats.UplinkPktQueueDlyHist) /
177 sizeof(adapter->tsmStats.UplinkPktQueueDlyHist[0]));
178 adapter->tsmStats.UplinkPktTxDly = tsm_metrics.UplinkPktTxDly;
179 adapter->tsmStats.UplinkPktLoss = tsm_metrics.UplinkPktLoss;
180 adapter->tsmStats.UplinkPktCount = tsm_metrics.UplinkPktCount;
181 adapter->tsmStats.RoamingCount = tsm_metrics.RoamingCount;
182 adapter->tsmStats.RoamingDly = tsm_metrics.RoamingDly;
183
184 /* notify the caller */
185 complete(&stats_context->completion);
186
187 /* serialization is complete */
188 spin_unlock(&hdd_context_lock);
189}
190
191static
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530192QDF_STATUS hdd_get_tsm_stats(hdd_adapter_t *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800193 const uint8_t tid,
194 tAniTrafStrmMetrics *tsm_metrics)
195{
196 hdd_station_ctx_t *hdd_sta_ctx = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530197 QDF_STATUS hstatus;
198 QDF_STATUS vstatus = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800199 unsigned long rc;
200 struct statsContext context;
201 hdd_context_t *hdd_ctx = NULL;
202
203 if (NULL == adapter) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530204 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800205 "%s: adapter is NULL", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530206 return QDF_STATUS_E_FAULT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800207 }
208
209 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
210 hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
211
212 /* we are connected prepare our callback context */
213 init_completion(&context.completion);
214 context.pAdapter = adapter;
215 context.magic = STATS_CONTEXT_MAGIC;
216
217 /* query tsm stats */
218 hstatus = sme_get_tsm_stats(hdd_ctx->hHal, hdd_get_tsm_stats_cb,
219 hdd_sta_ctx->conn_info.staId[0],
220 hdd_sta_ctx->conn_info.bssId,
221 &context, hdd_ctx->pcds_context, tid);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530222 if (QDF_STATUS_SUCCESS != hstatus) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530223 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800224 "%s: Unable to retrieve statistics", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530225 vstatus = QDF_STATUS_E_FAULT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800226 } else {
227 /* request was sent -- wait for the response */
228 rc = wait_for_completion_timeout(&context.completion,
229 msecs_to_jiffies(WLAN_WAIT_TIME_STATS));
230 if (!rc) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530231 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800232 "%s: SME timed out while retrieving statistics",
233 __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530234 vstatus = QDF_STATUS_E_TIMEOUT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800235 }
236 }
237
238 /*
239 * either we never sent a request, we sent a request and received a
240 * response or we sent a request and timed out. if we never sent a
241 * request or if we sent a request and got a response, we want to
242 * clear the magic out of paranoia. if we timed out there is a
243 * race condition such that the callback function could be
244 * executing at the same time we are. of primary concern is if the
245 * callback function had already verified the "magic" but had not
246 * yet set the completion variable when a timeout occurred. we
247 * serialize these activities by invalidating the magic while
248 * holding a shared spinlock which will cause us to block if the
249 * callback is currently executing
250 */
251 spin_lock(&hdd_context_lock);
252 context.magic = 0;
253 spin_unlock(&hdd_context_lock);
254
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530255 if (QDF_STATUS_SUCCESS == vstatus) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800256 tsm_metrics->UplinkPktQueueDly =
257 adapter->tsmStats.UplinkPktQueueDly;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530258 qdf_mem_copy(tsm_metrics->UplinkPktQueueDlyHist,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800259 adapter->tsmStats.UplinkPktQueueDlyHist,
260 sizeof(adapter->tsmStats.UplinkPktQueueDlyHist) /
261 sizeof(adapter->tsmStats.
262 UplinkPktQueueDlyHist[0]));
263 tsm_metrics->UplinkPktTxDly = adapter->tsmStats.UplinkPktTxDly;
264 tsm_metrics->UplinkPktLoss = adapter->tsmStats.UplinkPktLoss;
265 tsm_metrics->UplinkPktCount = adapter->tsmStats.UplinkPktCount;
266 tsm_metrics->RoamingCount = adapter->tsmStats.RoamingCount;
267 tsm_metrics->RoamingDly = adapter->tsmStats.RoamingDly;
268 }
269 return vstatus;
270}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -0800271#endif /*FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800272
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800273/* Function header is left blank intentionally */
274static int hdd_parse_setrmcenable_command(uint8_t *pValue,
275 uint8_t *pRmcEnable)
276{
277 uint8_t *inPtr = pValue;
278 int tempInt;
279 int v = 0;
280 char buf[32];
281 *pRmcEnable = 0;
282
283 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
284
285 if (NULL == inPtr) {
286 return 0;
287 }
288
289 else if (SPACE_ASCII_VALUE != *inPtr) {
290 return 0;
291 }
292
293 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
294 inPtr++;
295
296 if ('\0' == *inPtr) {
297 return 0;
298 }
299
300 sscanf(inPtr, "%32s ", buf);
301 v = kstrtos32(buf, 10, &tempInt);
302 if (v < 0) {
303 return -EINVAL;
304 }
305
306 *pRmcEnable = tempInt;
307
308 hddLog(LOG1, FL("ucRmcEnable: %d"), *pRmcEnable);
309
310 return 0;
311}
312
313/* Function header is left blank intentionally */
314static int hdd_parse_setrmcactionperiod_command(uint8_t *pValue,
315 uint32_t *pActionPeriod)
316{
317 uint8_t *inPtr = pValue;
318 int tempInt;
319 int v = 0;
320 char buf[32];
321 *pActionPeriod = 0;
322
323 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
324
325 if (NULL == inPtr) {
326 return -EINVAL;
327 }
328
329 else if (SPACE_ASCII_VALUE != *inPtr) {
330 return -EINVAL;
331 }
332
333 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
334 inPtr++;
335
336 if ('\0' == *inPtr) {
337 return 0;
338 }
339
340 sscanf(inPtr, "%32s ", buf);
341 v = kstrtos32(buf, 10, &tempInt);
342 if (v < 0) {
343 return -EINVAL;
344 }
345
346 if ((tempInt < WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STAMIN) ||
347 (tempInt > WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STAMAX)) {
348 return -EINVAL;
349 }
350
351 *pActionPeriod = tempInt;
352
353 hddLog(LOG1, FL("uActionPeriod: %d"), *pActionPeriod);
354
355 return 0;
356}
357
358/* Function header is left blank intentionally */
359static int hdd_parse_setrmcrate_command(uint8_t *pValue,
360 uint32_t *pRate,
361 tTxrateinfoflags *pTxFlags)
362{
363 uint8_t *inPtr = pValue;
364 int tempInt;
365 int v = 0;
366 char buf[32];
367 *pRate = 0;
368 *pTxFlags = 0;
369
370 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
371
372 if (NULL == inPtr) {
373 return -EINVAL;
374 }
375
376 else if (SPACE_ASCII_VALUE != *inPtr) {
377 return -EINVAL;
378 }
379
380 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
381 inPtr++;
382
383 if ('\0' == *inPtr) {
384 return 0;
385 }
386
387 sscanf(inPtr, "%32s ", buf);
388 v = kstrtos32(buf, 10, &tempInt);
389 if (v < 0) {
390 return -EINVAL;
391 }
392
393 switch (tempInt) {
394 default:
395 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN,
396 "Unsupported rate: %d", tempInt);
397 return -EINVAL;
398 case 0:
399 case 6:
400 case 9:
401 case 12:
402 case 18:
403 case 24:
404 case 36:
405 case 48:
406 case 54:
407 *pTxFlags = eHAL_TX_RATE_LEGACY;
408 *pRate = tempInt * 10;
409 break;
410 case 65:
411 *pTxFlags = eHAL_TX_RATE_HT20;
412 *pRate = tempInt * 10;
413 break;
414 case 72:
415 *pTxFlags = eHAL_TX_RATE_HT20 | eHAL_TX_RATE_SGI;
416 *pRate = 722;
417 break;
418 }
419
420 hddLog(LOG1, FL("Rate: %d"), *pRate);
421
422 return 0;
423}
424
425/**
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700426 * hdd_get_ibss_peer_info_cb() - IBSS peer Info request callback
427 * @UserData: Adapter private data
428 * @pPeerInfoRsp: Peer info response
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800429 *
430 * This is an asynchronous callback function from SME when the peer info
431 * is received
432 *
433 * Return: 0 for success non-zero for failure
434 */
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700435void
436hdd_get_ibss_peer_info_cb(void *pUserData,
437 tSirPeerInfoRspParams *pPeerInfo)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800438{
439 hdd_adapter_t *adapter = (hdd_adapter_t *) pUserData;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800440 hdd_station_ctx_t *pStaCtx;
441 uint8_t i;
442
443 /* Sanity check */
444 if ((NULL == adapter) ||
445 (WLAN_HDD_ADAPTER_MAGIC != adapter->magic)) {
446 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_FATAL,
447 "invalid adapter or adapter has invalid magic");
448 return;
449 }
450
451 pStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
452 if (NULL != pPeerInfo && QDF_STATUS_SUCCESS == pPeerInfo->status) {
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700453 /* validate number of peers */
454 if (pPeerInfo->numPeers < SIR_MAX_NUM_STA_IN_IBSS) {
455 pStaCtx->ibss_peer_info.status = pPeerInfo->status;
456 pStaCtx->ibss_peer_info.numPeers = pPeerInfo->numPeers;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800457
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700458 for (i = 0; i < pPeerInfo->numPeers; i++) {
459 pStaCtx->ibss_peer_info.peerInfoParams[i] =
460 pPeerInfo->peerInfoParams[i];
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800461 }
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700462 hdd_info("Peer Info copied in HDD");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800463 } else {
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700464 hdd_info("Number of peers %d returned is more than limit %d",
465 pPeerInfo->numPeers, SIR_MAX_NUM_STA_IN_IBSS);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800466 }
467 } else {
468 hddLog(LOG1, FL("peerInfo returned is NULL"));
469 }
470
471 complete(&adapter->ibss_peer_info_comp);
472}
473
474/**
475 * hdd_cfg80211_get_ibss_peer_info_all() - get ibss peers' info
476 * @adapter: Adapter context
477 *
478 * Request function to get IBSS peer info from lower layers
479 *
480 * Return: 0 for success non-zero for failure
481 */
482static
483QDF_STATUS hdd_cfg80211_get_ibss_peer_info_all(hdd_adapter_t *adapter)
484{
485 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
486 QDF_STATUS retStatus = QDF_STATUS_E_FAILURE;
487 unsigned long rc;
488
489 INIT_COMPLETION(adapter->ibss_peer_info_comp);
490
491 retStatus = sme_request_ibss_peer_info(hHal, adapter,
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700492 hdd_get_ibss_peer_info_cb,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800493 true, 0xFF);
494
495 if (QDF_STATUS_SUCCESS == retStatus) {
496 rc = wait_for_completion_timeout
497 (&adapter->ibss_peer_info_comp,
498 msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT));
499
500 /* status will be 0 if timed out */
501 if (!rc) {
502 hddLog(QDF_TRACE_LEVEL_WARN,
503 "%s: Warning: IBSS_PEER_INFO_TIMEOUT",
504 __func__);
505 retStatus = QDF_STATUS_E_FAILURE;
506 return retStatus;
507 }
508 } else {
509 hddLog(QDF_TRACE_LEVEL_WARN,
510 "%s: Warning: sme_request_ibss_peer_info Request failed",
511 __func__);
512 }
513
514 return retStatus;
515}
516
517/**
518 * hdd_cfg80211_get_ibss_peer_info() - get ibss peer info
519 * @adapter: Adapter context
520 * @staIdx: Sta index for which the peer info is requested
521 *
522 * Request function to get IBSS peer info from lower layers
523 *
524 * Return: 0 for success non-zero for failure
525 */
526static QDF_STATUS
527hdd_cfg80211_get_ibss_peer_info(hdd_adapter_t *adapter, uint8_t staIdx)
528{
529 unsigned long rc;
530 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
531 QDF_STATUS retStatus = QDF_STATUS_E_FAILURE;
532
533 INIT_COMPLETION(adapter->ibss_peer_info_comp);
534
535 retStatus = sme_request_ibss_peer_info(hHal, adapter,
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700536 hdd_get_ibss_peer_info_cb,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800537 false, staIdx);
538
539 if (QDF_STATUS_SUCCESS == retStatus) {
540 rc = wait_for_completion_timeout(
541 &adapter->ibss_peer_info_comp,
542 msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT));
543
544 /* status = 0 on timeout */
545 if (!rc) {
546 hddLog(QDF_TRACE_LEVEL_WARN,
547 "%s: Warning: IBSS_PEER_INFO_TIMEOUT",
548 __func__);
549 retStatus = QDF_STATUS_E_FAILURE;
550 return retStatus;
551 }
552 } else {
553 hddLog(QDF_TRACE_LEVEL_WARN,
554 "%s: Warning: sme_request_ibss_peer_info Request failed",
555 __func__);
556 }
557
558 return retStatus;
559}
560
561/* Function header is left blank intentionally */
562QDF_STATUS
563hdd_parse_get_ibss_peer_info(uint8_t *pValue, struct qdf_mac_addr *pPeerMacAddr)
564{
565 uint8_t *inPtr = pValue;
566 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
567
568 if (NULL == inPtr) {
569 return QDF_STATUS_E_FAILURE;;
570 }
571
572 else if (SPACE_ASCII_VALUE != *inPtr) {
573 return QDF_STATUS_E_FAILURE;;
574 }
575
576 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
577 inPtr++;
578
579 if ('\0' == *inPtr) {
580 return QDF_STATUS_E_FAILURE;;
581 }
582
583 if (inPtr[2] != ':' || inPtr[5] != ':' || inPtr[8] != ':' ||
584 inPtr[11] != ':' || inPtr[14] != ':') {
585 return QDF_STATUS_E_FAILURE;;
586 }
587 sscanf(inPtr, "%2x:%2x:%2x:%2x:%2x:%2x",
588 (unsigned int *)&pPeerMacAddr->bytes[0],
589 (unsigned int *)&pPeerMacAddr->bytes[1],
590 (unsigned int *)&pPeerMacAddr->bytes[2],
591 (unsigned int *)&pPeerMacAddr->bytes[3],
592 (unsigned int *)&pPeerMacAddr->bytes[4],
593 (unsigned int *)&pPeerMacAddr->bytes[5]);
594
595 return QDF_STATUS_SUCCESS;
596}
597
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800598static void hdd_get_band_helper(hdd_context_t *hdd_ctx, int *pBand)
599{
600 eCsrBand band = -1;
601 sme_get_freq_band((tHalHandle) (hdd_ctx->hHal), &band);
602 switch (band) {
603 case eCSR_BAND_ALL:
604 *pBand = WLAN_HDD_UI_BAND_AUTO;
605 break;
606
607 case eCSR_BAND_24:
608 *pBand = WLAN_HDD_UI_BAND_2_4_GHZ;
609 break;
610
611 case eCSR_BAND_5G:
612 *pBand = WLAN_HDD_UI_BAND_5_GHZ;
613 break;
614
615 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530616 hddLog(QDF_TRACE_LEVEL_WARN, "%s: Invalid Band %d", __func__,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800617 band);
618 *pBand = -1;
619 break;
620 }
621}
622
623/**
624 * _hdd_parse_bssid_and_chan() - helper function to parse bssid and channel
625 * @data: input data
626 * @target_ap_bssid: pointer to bssid (output parameter)
627 * @channel: pointer to channel (output parameter)
628 *
629 * Return: 0 if parsing is successful; -EINVAL otherwise
630 */
631static int _hdd_parse_bssid_and_chan(const uint8_t **data,
632 uint8_t *bssid,
633 uint8_t *channel)
634{
635 const uint8_t *in_ptr;
636 int v = 0;
637 int temp_int;
638 uint8_t temp_buf[32];
639
640 /* 12 hexa decimal digits, 5 ':' and '\0' */
641 uint8_t mac_addr[18];
642
643 if (!data || !*data)
644 return -EINVAL;
645
646 in_ptr = *data;
647
648 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
649 /* no argument after the command */
650 if (NULL == in_ptr)
651 goto error;
652 /* no space after the command */
653 else if (SPACE_ASCII_VALUE != *in_ptr)
654 goto error;
655
656 /* remove empty spaces */
657 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
658 in_ptr++;
659
660 /* no argument followed by spaces */
661 if ('\0' == *in_ptr)
662 goto error;
663
664 v = sscanf(in_ptr, "%17s", mac_addr);
665 if (!((1 == v) && hdd_is_valid_mac_address(mac_addr))) {
666 hddLog(LOGE,
667 FL(
668 "Invalid MAC address or All hex inputs are not read (%d)"
669 ),
670 v);
671 goto error;
672 }
673
674 bssid[0] = hex_to_bin(mac_addr[0]) << 4 |
675 hex_to_bin(mac_addr[1]);
676 bssid[1] = hex_to_bin(mac_addr[3]) << 4 |
677 hex_to_bin(mac_addr[4]);
678 bssid[2] = hex_to_bin(mac_addr[6]) << 4 |
679 hex_to_bin(mac_addr[7]);
680 bssid[3] = hex_to_bin(mac_addr[9]) << 4 |
681 hex_to_bin(mac_addr[10]);
682 bssid[4] = hex_to_bin(mac_addr[12]) << 4 |
683 hex_to_bin(mac_addr[13]);
684 bssid[5] = hex_to_bin(mac_addr[15]) << 4 |
685 hex_to_bin(mac_addr[16]);
686
687 /* point to the next argument */
688 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
689 /* no argument after the command */
690 if (NULL == in_ptr)
691 goto error;
692
693 /* remove empty spaces */
694 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
695 in_ptr++;
696
697 /* no argument followed by spaces */
698 if ('\0' == *in_ptr)
699 goto error;
700
701 /* get the next argument ie the channel number */
702 v = sscanf(in_ptr, "%31s ", temp_buf);
703 if (1 != v)
704 goto error;
705
706 v = kstrtos32(temp_buf, 10, &temp_int);
707 if ((v < 0) || (temp_int < 0) ||
708 (temp_int > WNI_CFG_CURRENT_CHANNEL_STAMAX))
709 return -EINVAL;
710
711 *channel = temp_int;
712 *data = in_ptr;
713 return 0;
714error:
715 *data = in_ptr;
716 return -EINVAL;
717}
718
719/**
720 * hdd_parse_send_action_frame_data() - HDD Parse send action frame data
721 * @pValue: Pointer to input data
722 * @pTargetApBssid: Pointer to target Ap bssid
723 * @pChannel: Pointer to the Target AP channel
724 * @pDwellTime: Pointer to the time to stay off-channel
725 * after transmitting action frame
726 * @pBuf: Pointer to data
727 * @pBufLen: Pointer to data length
728 *
729 * This function parses the send action frame data passed in the format
730 * SENDACTIONFRAME<space><bssid><space><channel><space><dwelltime><space><data>
731 *
732 * Return: 0 for success non-zero for failure
733 */
734static int
735hdd_parse_send_action_frame_v1_data(const uint8_t *pValue,
736 uint8_t *pTargetApBssid,
737 uint8_t *pChannel, uint8_t *pDwellTime,
738 uint8_t **pBuf, uint8_t *pBufLen)
739{
740 const uint8_t *inPtr = pValue;
741 const uint8_t *dataEnd;
742 int tempInt;
743 int j = 0;
744 int i = 0;
745 int v = 0;
746 uint8_t tempBuf[32];
747 uint8_t tempByte = 0;
748
749 if (_hdd_parse_bssid_and_chan(&inPtr, pTargetApBssid, pChannel))
750 return -EINVAL;
751
752 /* point to the next argument */
753 inPtr = strnchr(inPtr, strlen(inPtr), SPACE_ASCII_VALUE);
754 /* no argument after the command */
755 if (NULL == inPtr)
756 return -EINVAL;
757 /* removing empty spaces */
758 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
759 inPtr++;
760
761 /* no argument followed by spaces */
762 if ('\0' == *inPtr) {
763 return -EINVAL;
764 }
765
766 /* getting the next argument ie the dwell time */
767 v = sscanf(inPtr, "%31s ", tempBuf);
768 if (1 != v)
769 return -EINVAL;
770
771 v = kstrtos32(tempBuf, 10, &tempInt);
772 if (v < 0 || tempInt < 0)
773 return -EINVAL;
774
775 *pDwellTime = tempInt;
776
777 /* point to the next argument */
778 inPtr = strnchr(inPtr, strlen(inPtr), SPACE_ASCII_VALUE);
779 /* no argument after the command */
780 if (NULL == inPtr)
781 return -EINVAL;
782 /* removing empty spaces */
783 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
784 inPtr++;
785
786 /* no argument followed by spaces */
787 if ('\0' == *inPtr) {
788 return -EINVAL;
789 }
790
791 /* find the length of data */
792 dataEnd = inPtr;
793 while (('\0' != *dataEnd)) {
794 dataEnd++;
795 }
796 *pBufLen = dataEnd - inPtr;
797 if (*pBufLen <= 0)
798 return -EINVAL;
799
800 /*
801 * Allocate the number of bytes based on the number of input characters
802 * whether it is even or odd.
803 * if the number of input characters are even, then we need N/2 byte.
804 * if the number of input characters are odd, then we need do (N+1)/2
805 * to compensate rounding off.
806 * For example, if N = 18, then (18 + 1)/2 = 9 bytes are enough.
807 * If N = 19, then we need 10 bytes, hence (19 + 1)/2 = 10 bytes
808 */
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530809 *pBuf = qdf_mem_malloc((*pBufLen + 1) / 2);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800810 if (NULL == *pBuf) {
Anurag Chouhanf04e84f2016-03-03 10:12:12 +0530811 hddLog(LOGE, FL("qdf_mem_malloc failed"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800812 return -ENOMEM;
813 }
814
815 /* the buffer received from the upper layer is character buffer,
816 * we need to prepare the buffer taking 2 characters in to a U8 hex
817 * decimal number for example 7f0000f0...form a buffer to contain 7f
818 * in 0th location, 00 in 1st and f0 in 3rd location
819 */
820 for (i = 0, j = 0; j < *pBufLen; j += 2) {
821 if (j + 1 == *pBufLen) {
822 tempByte = hex_to_bin(inPtr[j]);
823 } else {
824 tempByte =
825 (hex_to_bin(inPtr[j]) << 4) |
826 (hex_to_bin(inPtr[j + 1]));
827 }
828 (*pBuf)[i++] = tempByte;
829 }
830 *pBufLen = i;
831 return 0;
832}
833
834/**
835 * hdd_parse_reassoc_command_data() - HDD Parse reassoc command data
836 * @pValue: Pointer to input data (its a NULL terminated string)
837 * @pTargetApBssid: Pointer to target Ap bssid
838 * @pChannel: Pointer to the Target AP channel
839 *
840 * This function parses the reasoc command data passed in the format
841 * REASSOC<space><bssid><space><channel>
842 *
843 * Return: 0 for success non-zero for failure
844 */
845static int hdd_parse_reassoc_command_v1_data(const uint8_t *pValue,
846 uint8_t *pTargetApBssid,
847 uint8_t *pChannel)
848{
849 const uint8_t *inPtr = pValue;
850
851 if (_hdd_parse_bssid_and_chan(&inPtr, pTargetApBssid, pChannel))
852 return -EINVAL;
853
854 return 0;
855}
856
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800857/**
858 * hdd_reassoc() - perform a userspace-directed reassoc
859 * @adapter: Adapter upon which the command was received
860 * @bssid: BSSID with which to reassociate
861 * @channel: channel upon which to reassociate
862 *
863 * This function performs a userspace-directed reassoc operation
864 *
865 * Return: 0 for success non-zero for failure
866 */
867static int
868hdd_reassoc(hdd_adapter_t *adapter, const uint8_t *bssid,
869 const uint8_t channel)
870{
871 hdd_station_ctx_t *pHddStaCtx;
872 int ret = 0;
873
Krunal Sonibe766b02016-03-10 13:00:44 -0800874 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800875 hdd_warn("Unsupported in mode %s(%d)",
876 hdd_device_mode_to_string(adapter->device_mode),
877 adapter->device_mode);
878 return -EINVAL;
879 }
880
881 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
882
883 /* if not associated, no need to proceed with reassoc */
884 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530885 hddLog(QDF_TRACE_LEVEL_INFO, "%s: Not associated", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800886 ret = -EINVAL;
887 goto exit;
888 }
889
890 /*
891 * if the target bssid is same as currently associated AP,
892 * then no need to proceed with reassoc
893 */
894 if (!memcmp(bssid, pHddStaCtx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530895 QDF_MAC_ADDR_SIZE)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800896 hddLog(LOG1,
897 FL("Reassoc BSSID is same as currently associated AP bssid"));
898 ret = -EINVAL;
899 goto exit;
900 }
901
902 /* Check channel number is a valid channel number */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530903 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800904 wlan_hdd_validate_operation_channel(adapter, channel)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530905 hddLog(QDF_TRACE_LEVEL_ERROR, "%s: Invalid Channel %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800906 __func__, channel);
907 ret = -EINVAL;
908 goto exit;
909 }
910
911 /* Proceed with reassoc */
912 {
913 tCsrHandoffRequest handoffInfo;
914 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
915
916 handoffInfo.channel = channel;
917 handoffInfo.src = REASSOC;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530918 qdf_mem_copy(handoffInfo.bssid.bytes, bssid, QDF_MAC_ADDR_SIZE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800919 sme_handoff_request(hdd_ctx->hHal, adapter->sessionId,
920 &handoffInfo);
921 }
922exit:
923 return ret;
924}
925
926/**
927 * hdd_parse_reassoc_v1() - parse version 1 of the REASSOC command
928 * @adapter: Adapter upon which the command was received
929 * @command: ASCII text command that was received
930 *
931 * This function parses the v1 REASSOC command with the format
932 *
933 * REASSOC xx:xx:xx:xx:xx:xx CH
934 *
935 * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the
936 * BSSID and CH is the ASCII representation of the channel. For
937 * example
938 *
939 * REASSOC 00:0a:0b:11:22:33 48
940 *
941 * Return: 0 for success non-zero for failure
942 */
943static int hdd_parse_reassoc_v1(hdd_adapter_t *adapter, const char *command)
944{
945 uint8_t channel = 0;
946 tSirMacAddr bssid;
947 int ret;
948
949 ret = hdd_parse_reassoc_command_v1_data(command, bssid, &channel);
950 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530951 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800952 "%s: Failed to parse reassoc command data", __func__);
953 } else {
954 ret = hdd_reassoc(adapter, bssid, channel);
955 }
956 return ret;
957}
958
959/**
960 * hdd_parse_reassoc_v2() - parse version 2 of the REASSOC command
961 * @adapter: Adapter upon which the command was received
962 * @command: Command that was received, ASCII command
963 * followed by binary data
964 *
965 * This function parses the v2 REASSOC command with the format
966 *
967 * REASSOC <android_wifi_reassoc_params>
968 *
969 * Return: 0 for success non-zero for failure
970 */
971static int hdd_parse_reassoc_v2(hdd_adapter_t *adapter, const char *command)
972{
973 struct android_wifi_reassoc_params params;
974 tSirMacAddr bssid;
975 int ret;
976
977 /* The params are located after "REASSOC " */
978 memcpy(&params, command + 8, sizeof(params));
979
980 if (!mac_pton(params.bssid, (u8 *) &bssid)) {
981 hddLog(LOGE, "%s: MAC address parsing failed", __func__);
982 ret = -EINVAL;
983 } else {
984 ret = hdd_reassoc(adapter, bssid, params.channel);
985 }
986 return ret;
987}
988
989/**
990 * hdd_parse_reassoc() - parse the REASSOC command
991 * @adapter: Adapter upon which the command was received
992 * @command: Command that was received
993 *
994 * There are two different versions of the REASSOC command. Version 1
995 * of the command contains a parameter list that is ASCII characters
996 * whereas version 2 contains a combination of ASCII and binary
997 * payload. Determine if a version 1 or a version 2 command is being
998 * parsed by examining the parameters, and then dispatch the parser
999 * that is appropriate for the command.
1000 *
1001 * Return: 0 for success non-zero for failure
1002 */
1003static int hdd_parse_reassoc(hdd_adapter_t *adapter, const char *command)
1004{
1005 int ret;
1006
1007 /* both versions start with "REASSOC "
1008 * v1 has a bssid and channel # as an ASCII string
1009 * REASSOC xx:xx:xx:xx:xx:xx CH
1010 * v2 has a C struct
1011 * REASSOC <binary c struct>
1012 *
1013 * The first field in the v2 struct is also the bssid in ASCII.
1014 * But in the case of a v2 message the BSSID is NUL-terminated.
1015 * Hence we can peek at that offset to see if this is V1 or V2
1016 * REASSOC xx:xx:xx:xx:xx:xx*
1017 * 1111111111222222
1018 * 01234567890123456789012345
1019 */
1020 if (command[25]) {
1021 ret = hdd_parse_reassoc_v1(adapter, command);
1022 } else {
1023 ret = hdd_parse_reassoc_v2(adapter, command);
1024 }
1025
1026 return ret;
1027}
1028
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001029/**
1030 * hdd_sendactionframe() - send a userspace-supplied action frame
1031 * @adapter: Adapter upon which the command was received
1032 * @bssid: BSSID target of the action frame
1033 * @channel: Channel upon which to send the frame
1034 * @dwell_time: Amount of time to dwell when the frame is sent
1035 * @payload_len:Length of the payload
1036 * @payload: Payload of the frame
1037 *
1038 * This function sends a userspace-supplied action frame
1039 *
1040 * Return: 0 for success non-zero for failure
1041 */
1042static int
1043hdd_sendactionframe(hdd_adapter_t *adapter, const uint8_t *bssid,
1044 const uint8_t channel, const uint8_t dwell_time,
1045 const uint8_t payload_len, const uint8_t *payload)
1046{
1047 struct ieee80211_channel chan;
1048 uint8_t frame_len;
1049 uint8_t *frame;
1050 struct ieee80211_hdr_3addr *hdr;
1051 u64 cookie;
1052 hdd_station_ctx_t *pHddStaCtx;
1053 hdd_context_t *hdd_ctx;
1054 int ret = 0;
1055 tpSirMacVendorSpecificFrameHdr pVendorSpecific =
1056 (tpSirMacVendorSpecificFrameHdr) payload;
1057#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
1058 struct cfg80211_mgmt_tx_params params;
1059#endif
1060
Krunal Sonibe766b02016-03-10 13:00:44 -08001061 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001062 hdd_warn("Unsupported in mode %s(%d)",
1063 hdd_device_mode_to_string(adapter->device_mode),
1064 adapter->device_mode);
1065 return -EINVAL;
1066 }
1067
1068 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
1069 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1070
1071 /* if not associated, no need to send action frame */
1072 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301073 hddLog(QDF_TRACE_LEVEL_INFO, "%s: Not associated", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001074 ret = -EINVAL;
1075 goto exit;
1076 }
1077
1078 /*
1079 * if the target bssid is different from currently associated AP,
1080 * then no need to send action frame
1081 */
1082 if (memcmp(bssid, pHddStaCtx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05301083 QDF_MAC_ADDR_SIZE)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001084 hddLog(LOG1, FL("STA is not associated to this AP"));
1085 ret = -EINVAL;
1086 goto exit;
1087 }
1088
1089 chan.center_freq = sme_chn_to_freq(channel);
1090 /* Check if it is specific action frame */
1091 if (pVendorSpecific->category ==
1092 SIR_MAC_ACTION_VENDOR_SPECIFIC_CATEGORY) {
1093 static const uint8_t Oui[] = { 0x00, 0x00, 0xf0 };
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301094 if (!qdf_mem_cmp(pVendorSpecific->Oui, (void *)Oui, 3)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001095 /*
1096 * if the channel number is different from operating
1097 * channel then no need to send action frame
1098 */
1099 if (channel != 0) {
1100 if (channel !=
1101 pHddStaCtx->conn_info.operationChannel) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301102 hddLog(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001103 "%s: channel(%d) is different from operating channel(%d)",
1104 __func__, channel,
1105 pHddStaCtx->conn_info.
1106 operationChannel);
1107 ret = -EINVAL;
1108 goto exit;
1109 }
1110 /*
1111 * If channel number is specified and same
1112 * as home channel, ensure that action frame
1113 * is sent immediately by cancelling
1114 * roaming scans. Otherwise large dwell times
1115 * may cause long delays in sending action
1116 * frames.
1117 */
1118 sme_abort_roam_scan(hdd_ctx->hHal,
1119 adapter->sessionId);
1120 } else {
1121 /*
1122 * 0 is accepted as current home channel,
1123 * delayed transmission of action frame is ok.
1124 */
1125 chan.center_freq =
1126 sme_chn_to_freq(pHddStaCtx->conn_info.
1127 operationChannel);
1128 }
1129 }
1130 }
1131 if (chan.center_freq == 0) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301132 hddLog(QDF_TRACE_LEVEL_ERROR, "%s:invalid channel number %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001133 __func__, channel);
1134 ret = -EINVAL;
1135 goto exit;
1136 }
1137
1138 frame_len = payload_len + 24;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301139 frame = qdf_mem_malloc(frame_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001140 if (!frame) {
1141 hddLog(LOGE, FL("memory allocation failed"));
1142 ret = -ENOMEM;
1143 goto exit;
1144 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301145 qdf_mem_zero(frame, frame_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001146
1147 hdr = (struct ieee80211_hdr_3addr *)frame;
1148 hdr->frame_control =
1149 cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301150 qdf_mem_copy(hdr->addr1, bssid, QDF_MAC_ADDR_SIZE);
1151 qdf_mem_copy(hdr->addr2, adapter->macAddressCurrent.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05301152 QDF_MAC_ADDR_SIZE);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301153 qdf_mem_copy(hdr->addr3, bssid, QDF_MAC_ADDR_SIZE);
1154 qdf_mem_copy(hdr + 1, payload, payload_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001155
1156#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
1157 params.chan = &chan;
1158 params.offchan = 0;
1159 params.wait = dwell_time;
1160 params.buf = frame;
1161 params.len = frame_len;
1162 params.no_cck = 1;
1163 params.dont_wait_for_ack = 1;
1164 ret = wlan_hdd_mgmt_tx(NULL, &adapter->wdev, &params, &cookie);
1165#else
1166 ret = wlan_hdd_mgmt_tx(NULL,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001167 &(adapter->wdev),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001168 &chan, 0,
Amar Singhal01098f72015-10-08 11:55:32 -07001169
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001170 dwell_time, frame, frame_len, 1, 1, &cookie);
1171#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
1172
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301173 qdf_mem_free(frame);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001174exit:
1175 return ret;
1176}
1177
1178/**
1179 * hdd_parse_sendactionframe_v1() - parse version 1 of the
1180 * SENDACTIONFRAME command
1181 * @adapter: Adapter upon which the command was received
1182 * @command: ASCII text command that was received
1183 *
1184 * This function parses the v1 SENDACTIONFRAME command with the format
1185 *
1186 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DW xxxxxx
1187 *
1188 * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the
1189 * BSSID, CH is the ASCII representation of the channel, DW is the
1190 * ASCII representation of the dwell time, and xxxxxx is the Hex-ASCII
1191 * payload. For example
1192 *
1193 * SENDACTIONFRAME 00:0a:0b:11:22:33 48 40 aabbccddee
1194 *
1195 * Return: 0 for success non-zero for failure
1196 */
1197static int
1198hdd_parse_sendactionframe_v1(hdd_adapter_t *adapter, const char *command)
1199{
1200 uint8_t channel = 0;
1201 uint8_t dwell_time = 0;
1202 uint8_t payload_len = 0;
1203 uint8_t *payload = NULL;
1204 tSirMacAddr bssid;
1205 int ret;
1206
1207 ret = hdd_parse_send_action_frame_v1_data(command, bssid, &channel,
1208 &dwell_time, &payload,
1209 &payload_len);
1210 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301211 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001212 "%s: Failed to parse send action frame data", __func__);
1213 } else {
1214 ret = hdd_sendactionframe(adapter, bssid, channel,
1215 dwell_time, payload_len, payload);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301216 qdf_mem_free(payload);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001217 }
1218
1219 return ret;
1220}
1221
1222/**
1223 * hdd_parse_sendactionframe_v2() - parse version 2 of the
1224 * SENDACTIONFRAME command
1225 * @adapter: Adapter upon which the command was received
1226 * @command: Command that was received, ASCII command
1227 * followed by binary data
1228 *
1229 * This function parses the v2 SENDACTIONFRAME command with the format
1230 *
1231 * SENDACTIONFRAME <android_wifi_af_params>
1232 *
1233 * Return: 0 for success non-zero for failure
1234 */
1235static int
1236hdd_parse_sendactionframe_v2(hdd_adapter_t *adapter, const char *command)
1237{
1238 struct android_wifi_af_params *params;
1239 tSirMacAddr bssid;
1240 int ret;
1241
1242 /* params are large so keep off the stack */
1243 params = kmalloc(sizeof(*params), GFP_KERNEL);
1244 if (!params)
1245 return -ENOMEM;
1246
1247 /* The params are located after "SENDACTIONFRAME " */
1248 memcpy(params, command + 16, sizeof(*params));
1249
1250 if (!mac_pton(params->bssid, (u8 *) &bssid)) {
1251 hddLog(LOGE, "%s: MAC address parsing failed", __func__);
1252 ret = -EINVAL;
1253 } else {
1254 ret = hdd_sendactionframe(adapter, bssid, params->channel,
1255 params->dwell_time, params->len,
1256 params->data);
1257 }
1258 kfree(params);
1259 return ret;
1260}
1261
1262/**
1263 * hdd_parse_sendactionframe() - parse the SENDACTIONFRAME command
1264 * @adapter: Adapter upon which the command was received
1265 * @command: Command that was received
1266 *
1267 * There are two different versions of the SENDACTIONFRAME command.
1268 * Version 1 of the command contains a parameter list that is ASCII
1269 * characters whereas version 2 contains a combination of ASCII and
1270 * binary payload. Determine if a version 1 or a version 2 command is
1271 * being parsed by examining the parameters, and then dispatch the
1272 * parser that is appropriate for the version of the command.
1273 *
1274 * Return: 0 for success non-zero for failure
1275 */
1276static int
1277hdd_parse_sendactionframe(hdd_adapter_t *adapter, const char *command)
1278{
1279 int ret;
1280
1281 /*
1282 * both versions start with "SENDACTIONFRAME "
1283 * v1 has a bssid and other parameters as an ASCII string
1284 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DWELL LEN FRAME
1285 * v2 has a C struct
1286 * SENDACTIONFRAME <binary c struct>
1287 *
1288 * The first field in the v2 struct is also the bssid in ASCII.
1289 * But in the case of a v2 message the BSSID is NUL-terminated.
1290 * Hence we can peek at that offset to see if this is V1 or V2
1291 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx*
1292 * 111111111122222222223333
1293 * 0123456789012345678901234567890123
1294 */
1295 if (command[33]) {
1296 ret = hdd_parse_sendactionframe_v1(adapter, command);
1297 } else {
1298 ret = hdd_parse_sendactionframe_v2(adapter, command);
1299 }
1300
1301 return ret;
1302}
1303
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001304/**
1305 * hdd_parse_channellist() - HDD Parse channel list
1306 * @pValue: Pointer to input channel list
1307 * @ChannelList: Pointer to local output array to record
1308 * channel list
1309 * @pNumChannels: Pointer to number of roam scan channels
1310 *
1311 * This function parses the channel list passed in the format
1312 * SETROAMSCANCHANNELS<space><Number of channels><space>Channel 1<space>Channel 2<space>Channel N
1313 * if the Number of channels (N) does not match with the actual number
1314 * of channels passed then take the minimum of N and count of
1315 * (Ch1, Ch2, ...Ch M). For example, if SETROAMSCANCHANNELS 3 36 40 44 48,
1316 * only 36, 40 and 44 shall be taken. If SETROAMSCANCHANNELS 5 36 40 44 48,
1317 * ignore 5 and take 36, 40, 44 and 48. This function does not take care of
1318 * removing duplicate channels from the list
1319 *
1320 * Return: 0 for success non-zero for failure
1321 */
1322static int
1323hdd_parse_channellist(const uint8_t *pValue, uint8_t *pChannelList,
1324 uint8_t *pNumChannels)
1325{
1326 const uint8_t *inPtr = pValue;
1327 int tempInt;
1328 int j = 0;
1329 int v = 0;
1330 char buf[32];
1331
1332 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
1333 /* no argument after the command */
1334 if (NULL == inPtr) {
1335 return -EINVAL;
1336 }
1337
1338 /* no space after the command */
1339 else if (SPACE_ASCII_VALUE != *inPtr) {
1340 return -EINVAL;
1341 }
1342
1343 /* remove empty spaces */
1344 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
1345 inPtr++;
1346
1347 /* no argument followed by spaces */
1348 if ('\0' == *inPtr) {
1349 return -EINVAL;
1350 }
1351
1352 /* get the first argument ie the number of channels */
1353 v = sscanf(inPtr, "%31s ", buf);
1354 if (1 != v)
1355 return -EINVAL;
1356
1357 v = kstrtos32(buf, 10, &tempInt);
1358 if ((v < 0) ||
1359 (tempInt <= 0) || (tempInt > WNI_CFG_VALID_CHANNEL_LIST_LEN)) {
1360 return -EINVAL;
1361 }
1362
1363 *pNumChannels = tempInt;
1364
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301365 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001366 "Number of channels are: %d", *pNumChannels);
1367
1368 for (j = 0; j < (*pNumChannels); j++) {
1369 /*
1370 * inPtr pointing to the beginning of first space after number
1371 * of channels
1372 */
1373 inPtr = strpbrk(inPtr, " ");
1374 /* no channel list after the number of channels argument */
1375 if (NULL == inPtr) {
1376 if (0 != j) {
1377 *pNumChannels = j;
1378 return 0;
1379 } else {
1380 return -EINVAL;
1381 }
1382 }
1383
1384 /* remove empty space */
1385 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
1386 inPtr++;
1387
1388 /*
1389 * no channel list after the number of channels
1390 * argument and spaces
1391 */
1392 if ('\0' == *inPtr) {
1393 if (0 != j) {
1394 *pNumChannels = j;
1395 return 0;
1396 } else {
1397 return -EINVAL;
1398 }
1399 }
1400
1401 v = sscanf(inPtr, "%31s ", buf);
1402 if (1 != v)
1403 return -EINVAL;
1404
1405 v = kstrtos32(buf, 10, &tempInt);
1406 if ((v < 0) ||
1407 (tempInt <= 0) ||
1408 (tempInt > WNI_CFG_CURRENT_CHANNEL_STAMAX)) {
1409 return -EINVAL;
1410 }
1411 pChannelList[j] = tempInt;
1412
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301413 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001414 "Channel %d added to preferred channel list",
1415 pChannelList[j]);
1416 }
1417
1418 return 0;
1419}
1420
1421/**
1422 * hdd_parse_set_roam_scan_channels_v1() - parse version 1 of the
1423 * SETROAMSCANCHANNELS command
1424 * @adapter: Adapter upon which the command was received
1425 * @command: ASCII text command that was received
1426 *
1427 * This function parses the v1 SETROAMSCANCHANNELS command with the format
1428 *
1429 * SETROAMSCANCHANNELS N C1 C2 ... Cn
1430 *
1431 * Where "N" is the ASCII representation of the number of channels and
1432 * C1 thru Cn is the ASCII representation of the channels. For example
1433 *
1434 * SETROAMSCANCHANNELS 4 36 40 44 48
1435 *
1436 * Return: 0 for success non-zero for failure
1437 */
1438static int
1439hdd_parse_set_roam_scan_channels_v1(hdd_adapter_t *adapter,
1440 const char *command)
1441{
1442 uint8_t channel_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
1443 uint8_t num_chan = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301444 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001445 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1446 int ret;
1447
1448 ret = hdd_parse_channellist(command, channel_list, &num_chan);
1449 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301450 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001451 "%s: Failed to parse channel list information",
1452 __func__);
1453 goto exit;
1454 }
1455
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301456 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001457 TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL,
1458 adapter->sessionId, num_chan));
1459
1460 if (num_chan > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301461 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001462 "%s: number of channels (%d) supported exceeded max (%d)",
1463 __func__, num_chan, WNI_CFG_VALID_CHANNEL_LIST_LEN);
1464 ret = -EINVAL;
1465 goto exit;
1466 }
1467
1468 status =
1469 sme_change_roam_scan_channel_list(hdd_ctx->hHal,
1470 adapter->sessionId,
1471 channel_list, num_chan);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301472 if (QDF_STATUS_SUCCESS != status) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301473 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001474 "%s: Failed to update channel list information",
1475 __func__);
1476 ret = -EINVAL;
1477 goto exit;
1478 }
1479exit:
1480 return ret;
1481}
1482
1483/**
1484 * hdd_parse_set_roam_scan_channels_v2() - parse version 2 of the
1485 * SETROAMSCANCHANNELS command
1486 * @adapter: Adapter upon which the command was received
1487 * @command: Command that was received, ASCII command
1488 * followed by binary data
1489 *
1490 * This function parses the v2 SETROAMSCANCHANNELS command with the format
1491 *
1492 * SETROAMSCANCHANNELS [N][C1][C2][Cn]
1493 *
1494 * The command begins with SETROAMSCANCHANNELS followed by a space, but
1495 * what follows the space is an array of u08 parameters. For example
1496 *
1497 * SETROAMSCANCHANNELS [0x04 0x24 0x28 0x2c 0x30]
1498 *
1499 * Return: 0 for success non-zero for failure
1500 */
1501static int
1502hdd_parse_set_roam_scan_channels_v2(hdd_adapter_t *adapter,
1503 const char *command)
1504{
1505 const uint8_t *value;
1506 uint8_t channel_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
1507 uint8_t channel;
1508 uint8_t num_chan;
1509 int i;
1510 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301511 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001512 int ret = 0;
1513
1514 /* array of values begins after "SETROAMSCANCHANNELS " */
1515 value = command + 20;
1516
1517 num_chan = *value++;
1518 if (num_chan > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301519 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001520 "%s: number of channels (%d) supported exceeded max (%d)",
1521 __func__, num_chan, WNI_CFG_VALID_CHANNEL_LIST_LEN);
1522 ret = -EINVAL;
1523 goto exit;
1524 }
1525
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301526 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001527 TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL,
1528 adapter->sessionId, num_chan));
1529
1530 for (i = 0; i < num_chan; i++) {
1531 channel = *value++;
1532 if (channel > WNI_CFG_CURRENT_CHANNEL_STAMAX) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301533 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001534 "%s: index %d invalid channel %d", __func__,
1535 i, channel);
1536 ret = -EINVAL;
1537 goto exit;
1538 }
1539 channel_list[i] = channel;
1540 }
1541 status =
1542 sme_change_roam_scan_channel_list(hdd_ctx->hHal,
1543 adapter->sessionId,
1544 channel_list, num_chan);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301545 if (QDF_STATUS_SUCCESS != status) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301546 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001547 "%s: Failed to update channel list information",
1548 __func__);
1549 ret = -EINVAL;
1550 goto exit;
1551 }
1552exit:
1553 return ret;
1554}
1555
1556/**
1557 * hdd_parse_set_roam_scan_channels() - parse the
1558 * SETROAMSCANCHANNELS command
1559 * @adapter: Adapter upon which the command was received
1560 * @command: Command that was received
1561 *
1562 * There are two different versions of the SETROAMSCANCHANNELS command.
1563 * Version 1 of the command contains a parameter list that is ASCII
1564 * characters whereas version 2 contains a binary payload. Determine
1565 * if a version 1 or a version 2 command is being parsed by examining
1566 * the parameters, and then dispatch the parser that is appropriate for
1567 * the command.
1568 *
1569 * Return: 0 for success non-zero for failure
1570 */
1571static int
1572hdd_parse_set_roam_scan_channels(hdd_adapter_t *adapter, const char *command)
1573{
1574 const char *cursor;
1575 char ch;
1576 bool v1;
1577 int ret;
1578
1579 /* start after "SETROAMSCANCHANNELS " */
1580 cursor = command + 20;
1581
1582 /* assume we have a version 1 command until proven otherwise */
1583 v1 = true;
1584
1585 /* v1 params will only contain ASCII digits and space */
1586 while ((ch = *cursor++) && v1) {
1587 if (!(isdigit(ch) || isspace(ch))) {
1588 v1 = false;
1589 }
1590 }
1591 if (v1) {
1592 ret = hdd_parse_set_roam_scan_channels_v1(adapter, command);
1593 } else {
1594 ret = hdd_parse_set_roam_scan_channels_v2(adapter, command);
1595 }
1596
1597 return ret;
1598}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001599
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08001600#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001601/**
1602 * hdd_parse_plm_cmd() - HDD Parse Plm command
1603 * @pValue: Pointer to input data
1604 * @pPlmRequest:Pointer to output struct tpSirPlmReq
1605 *
1606 * This function parses the plm command passed in the format
1607 * CCXPLMREQ<space><enable><space><dialog_token><space>
1608 * <meas_token><space><num_of_bursts><space><burst_int><space>
1609 * <measu duration><space><burst_len><space><desired_tx_pwr>
1610 * <space><multcast_addr><space><number_of_channels>
1611 * <space><channel_numbers>
1612 *
1613 * Return: 0 for success non-zero for failure
1614 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301615QDF_STATUS hdd_parse_plm_cmd(uint8_t *pValue, tSirPlmReq *pPlmRequest)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001616{
1617 uint8_t *cmdPtr = NULL;
1618 int count, content = 0, ret = 0;
1619 char buf[32];
1620
1621 /* move to argument list */
1622 cmdPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
1623 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301624 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001625
1626 /* no space after the command */
1627 if (SPACE_ASCII_VALUE != *cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301628 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001629
1630 /* remove empty spaces */
1631 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1632 cmdPtr++;
1633
1634 /* START/STOP PLM req */
1635 ret = sscanf(cmdPtr, "%31s ", buf);
1636 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301637 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001638
1639 ret = kstrtos32(buf, 10, &content);
1640 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301641 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001642
1643 pPlmRequest->enable = content;
1644 cmdPtr = strpbrk(cmdPtr, " ");
1645
1646 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301647 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001648
1649 /* remove empty spaces */
1650 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1651 cmdPtr++;
1652
1653 /* Dialog token of radio meas req containing meas reqIE */
1654 ret = sscanf(cmdPtr, "%31s ", buf);
1655 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301656 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001657
1658 ret = kstrtos32(buf, 10, &content);
1659 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301660 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001661
1662 pPlmRequest->diag_token = content;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301663 hddLog(QDF_TRACE_LEVEL_DEBUG, "diag token %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001664 pPlmRequest->diag_token);
1665 cmdPtr = strpbrk(cmdPtr, " ");
1666
1667 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301668 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001669
1670 /* remove empty spaces */
1671 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1672 cmdPtr++;
1673
1674 /* measurement token of meas req IE */
1675 ret = sscanf(cmdPtr, "%31s ", buf);
1676 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301677 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001678
1679 ret = kstrtos32(buf, 10, &content);
1680 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301681 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001682
1683 pPlmRequest->meas_token = content;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301684 hddLog(QDF_TRACE_LEVEL_DEBUG, "meas token %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001685 pPlmRequest->meas_token);
1686
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301687 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001688 "PLM req %s", pPlmRequest->enable ? "START" : "STOP");
1689 if (pPlmRequest->enable) {
1690
1691 cmdPtr = strpbrk(cmdPtr, " ");
1692
1693 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301694 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001695
1696 /* remove empty spaces */
1697 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1698 cmdPtr++;
1699
1700 /* total number of bursts after which STA stops sending */
1701 ret = sscanf(cmdPtr, "%31s ", buf);
1702 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301703 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001704
1705 ret = kstrtos32(buf, 10, &content);
1706 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301707 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001708
1709 if (content < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301710 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001711
1712 pPlmRequest->numBursts = content;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301713 hddLog(QDF_TRACE_LEVEL_DEBUG, "num burst %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001714 pPlmRequest->numBursts);
1715 cmdPtr = strpbrk(cmdPtr, " ");
1716
1717 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301718 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001719
1720 /* remove empty spaces */
1721 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1722 cmdPtr++;
1723
1724 /* burst interval in seconds */
1725 ret = sscanf(cmdPtr, "%31s ", buf);
1726 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301727 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001728
1729 ret = kstrtos32(buf, 10, &content);
1730 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301731 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001732
1733 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301734 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001735
1736 pPlmRequest->burstInt = content;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301737 hddLog(QDF_TRACE_LEVEL_DEBUG, "burst Int %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001738 pPlmRequest->burstInt);
1739 cmdPtr = strpbrk(cmdPtr, " ");
1740
1741 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301742 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001743
1744 /* remove empty spaces */
1745 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1746 cmdPtr++;
1747
1748 /* Meas dur in TU's,STA goes off-ch and transmit PLM bursts */
1749 ret = sscanf(cmdPtr, "%31s ", buf);
1750 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301751 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001752
1753 ret = kstrtos32(buf, 10, &content);
1754 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301755 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001756
1757 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301758 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001759
1760 pPlmRequest->measDuration = content;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301761 hddLog(QDF_TRACE_LEVEL_DEBUG, "measDur %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001762 pPlmRequest->measDuration);
1763 cmdPtr = strpbrk(cmdPtr, " ");
1764
1765 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301766 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001767
1768 /* remove empty spaces */
1769 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1770 cmdPtr++;
1771
1772 /* burst length of PLM bursts */
1773 ret = sscanf(cmdPtr, "%31s ", buf);
1774 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301775 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001776
1777 ret = kstrtos32(buf, 10, &content);
1778 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301779 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001780
1781 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301782 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001783
1784 pPlmRequest->burstLen = content;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301785 hddLog(QDF_TRACE_LEVEL_DEBUG, "burstLen %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001786 pPlmRequest->burstLen);
1787 cmdPtr = strpbrk(cmdPtr, " ");
1788
1789 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301790 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001791
1792 /* remove empty spaces */
1793 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1794 cmdPtr++;
1795
1796 /* desired tx power for transmission of PLM bursts */
1797 ret = sscanf(cmdPtr, "%31s ", buf);
1798 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301799 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001800
1801 ret = kstrtos32(buf, 10, &content);
1802 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301803 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001804
1805 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301806 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001807
1808 pPlmRequest->desiredTxPwr = content;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301809 hddLog(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001810 "desiredTxPwr %d", pPlmRequest->desiredTxPwr);
1811
Anurag Chouhan6d760662016-02-20 16:05:43 +05301812 for (count = 0; count < QDF_MAC_ADDR_SIZE; count++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001813 cmdPtr = strpbrk(cmdPtr, " ");
1814
1815 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301816 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001817
1818 /* remove empty spaces */
1819 while ((SPACE_ASCII_VALUE == *cmdPtr)
1820 && ('\0' != *cmdPtr))
1821 cmdPtr++;
1822
1823 ret = sscanf(cmdPtr, "%31s ", buf);
1824 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301825 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001826
1827 ret = kstrtos32(buf, 16, &content);
1828 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301829 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001830
Srinivas Girigowda5146dee2015-11-18 21:46:48 -08001831 pPlmRequest->mac_addr.bytes[count] = content;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001832 }
1833
Srinivas Girigowda5146dee2015-11-18 21:46:48 -08001834 hdd_debug("MC addr " MAC_ADDRESS_STR,
1835 MAC_ADDR_ARRAY(pPlmRequest->mac_addr.bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001836
1837 cmdPtr = strpbrk(cmdPtr, " ");
1838
1839 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301840 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001841
1842 /* remove empty spaces */
1843 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1844 cmdPtr++;
1845
1846 /* number of channels */
1847 ret = sscanf(cmdPtr, "%31s ", buf);
1848 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301849 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001850
1851 ret = kstrtos32(buf, 10, &content);
1852 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301853 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001854
1855 if (content < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301856 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001857
1858 pPlmRequest->plmNumCh = content;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301859 hddLog(QDF_TRACE_LEVEL_DEBUG, "numch %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001860 pPlmRequest->plmNumCh);
1861
1862 /* Channel numbers */
1863 for (count = 0; count < pPlmRequest->plmNumCh; count++) {
1864 cmdPtr = strpbrk(cmdPtr, " ");
1865
1866 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301867 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001868
1869 /* remove empty spaces */
1870 while ((SPACE_ASCII_VALUE == *cmdPtr)
1871 && ('\0' != *cmdPtr))
1872 cmdPtr++;
1873
1874 ret = sscanf(cmdPtr, "%31s ", buf);
1875 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301876 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001877
1878 ret = kstrtos32(buf, 10, &content);
1879 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301880 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001881
1882 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301883 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001884
1885 pPlmRequest->plmChList[count] = content;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301886 hddLog(QDF_TRACE_LEVEL_DEBUG, " ch- %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001887 pPlmRequest->plmChList[count]);
1888 }
1889 }
1890 /* If PLM START */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301891 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001892}
1893#endif
1894
1895#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
1896static void wlan_hdd_ready_to_extwow(void *callbackContext, bool is_success)
1897{
1898 hdd_context_t *hdd_ctx = (hdd_context_t *) callbackContext;
1899 int rc;
1900
1901 rc = wlan_hdd_validate_context(hdd_ctx);
1902 if (0 != rc) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301903 hddLog(QDF_TRACE_LEVEL_ERROR, FL("HDD context is not valid"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001904 return;
1905 }
1906 hdd_ctx->ext_wow_should_suspend = is_success;
1907 complete(&hdd_ctx->ready_to_extwow);
1908}
1909
1910static int hdd_enable_ext_wow(hdd_adapter_t *adapter,
1911 tpSirExtWoWParams arg_params)
1912{
1913 tSirExtWoWParams params;
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301914 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001915 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1916 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
1917 int rc;
1918
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301919 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001920
1921 INIT_COMPLETION(hdd_ctx->ready_to_extwow);
1922
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301923 qdf_ret_status = sme_configure_ext_wow(hHal, &params,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001924 &wlan_hdd_ready_to_extwow,
1925 hdd_ctx);
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301926 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301927 hddLog(QDF_TRACE_LEVEL_ERROR,
Krishna Kumaar Natarajand9131902015-10-19 11:52:47 -07001928 FL("sme_configure_ext_wow returned failure %d"),
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301929 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001930 return -EPERM;
1931 }
1932
1933 rc = wait_for_completion_timeout(&hdd_ctx->ready_to_extwow,
1934 msecs_to_jiffies(WLAN_WAIT_TIME_READY_TO_EXTWOW));
1935 if (!rc) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301936 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001937 "%s: Failed to get ready to extwow", __func__);
1938 return -EPERM;
1939 }
1940
1941 if (hdd_ctx->ext_wow_should_suspend) {
1942 if (hdd_ctx->config->extWowGotoSuspend) {
1943 pm_message_t state;
1944
1945 state.event = PM_EVENT_SUSPEND;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301946 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001947 "%s: Received ready to ExtWoW. Going to suspend",
1948 __func__);
1949
1950 rc = wlan_hdd_cfg80211_suspend_wlan(hdd_ctx->wiphy, NULL);
1951 if (rc < 0) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301952 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001953 "%s: wlan_hdd_cfg80211_suspend_wlan failed, error = %d",
1954 __func__, rc);
1955 return rc;
1956 }
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301957 qdf_ret_status = wlan_hdd_bus_suspend(state);
1958 if (qdf_ret_status != QDF_STATUS_SUCCESS) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301959 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001960 "%s: wlan_hdd_suspend failed, status = %d",
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301961 __func__, qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001962 wlan_hdd_cfg80211_resume_wlan(hdd_ctx->wiphy);
1963 return -EPERM;
1964 }
1965 }
1966 } else {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301967 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001968 "%s: Received ready to ExtWoW failure", __func__);
1969 return -EPERM;
1970 }
1971
1972 return 0;
1973}
1974
1975static int hdd_enable_ext_wow_parser(hdd_adapter_t *adapter, int vdev_id,
1976 int value)
1977{
1978 tSirExtWoWParams params;
1979 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1980 int rc;
1981
1982 rc = wlan_hdd_validate_context(hdd_ctx);
1983 if (0 != rc) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301984 hddLog(QDF_TRACE_LEVEL_ERROR, FL("HDD context is not valid"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001985 return -EINVAL;
1986 }
1987
1988 if (value < EXT_WOW_TYPE_APP_TYPE1 ||
1989 value > EXT_WOW_TYPE_APP_TYPE1_2) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301990 hddLog(QDF_TRACE_LEVEL_ERROR, FL("Invalid type"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001991 return -EINVAL;
1992 }
1993
1994 if (value == EXT_WOW_TYPE_APP_TYPE1 &&
1995 hdd_ctx->is_extwow_app_type1_param_set)
1996 params.type = value;
1997 else if (value == EXT_WOW_TYPE_APP_TYPE2 &&
1998 hdd_ctx->is_extwow_app_type2_param_set)
1999 params.type = value;
2000 else if (value == EXT_WOW_TYPE_APP_TYPE1_2 &&
2001 hdd_ctx->is_extwow_app_type1_param_set &&
2002 hdd_ctx->is_extwow_app_type2_param_set)
2003 params.type = value;
2004 else {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302005 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002006 FL("Set app params before enable it value %d"), value);
2007 return -EINVAL;
2008 }
2009
2010 params.vdev_id = vdev_id;
2011 params.wakeup_pin_num = hdd_ctx->config->extWowApp1WakeupPinNumber |
2012 (hdd_ctx->config->extWowApp2WakeupPinNumber
2013 << 8);
2014
2015 return hdd_enable_ext_wow(adapter, &params);
2016}
2017
2018static int hdd_set_app_type1_params(tHalHandle hHal,
2019 tpSirAppType1Params arg_params)
2020{
2021 tSirAppType1Params params;
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05302022 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002023
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302024 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002025
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05302026 qdf_ret_status = sme_configure_app_type1_params(hHal, &params);
2027 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302028 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002029 FL("sme_configure_app_type1_params returned failure %d"),
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05302030 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002031 return -EPERM;
2032 }
2033
2034 return 0;
2035}
2036
2037static int hdd_set_app_type1_parser(hdd_adapter_t *adapter,
2038 char *arg, int len)
2039{
2040 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2041 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
2042 char id[20], password[20];
2043 tSirAppType1Params params;
Srinivas Girigowda04209912015-11-24 12:11:13 -08002044 int rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002045
2046 rc = wlan_hdd_validate_context(hdd_ctx);
2047 if (0 != rc) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302048 hddLog(QDF_TRACE_LEVEL_ERROR, FL("HDD context is not valid"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002049 return -EINVAL;
2050 }
2051
2052 if (2 != sscanf(arg, "%8s %16s", id, password)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302053 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002054 FL("Invalid Number of arguments"));
2055 return -EINVAL;
2056 }
2057
2058 memset(&params, 0, sizeof(tSirAppType1Params));
2059 params.vdev_id = adapter->sessionId;
Anurag Chouhanc5548422016-02-24 18:33:27 +05302060 qdf_copy_macaddr(&params.wakee_mac_addr, &adapter->macAddressCurrent);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002061
2062 params.id_length = strlen(id);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302063 qdf_mem_copy(params.identification_id, id, params.id_length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002064 params.pass_length = strlen(password);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302065 qdf_mem_copy(params.password, password, params.pass_length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002066
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302067 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002068 "%s: %d %pM %.8s %u %.16s %u",
Srinivas Girigowda04209912015-11-24 12:11:13 -08002069 __func__, params.vdev_id, params.wakee_mac_addr.bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002070 params.identification_id, params.id_length,
2071 params.password, params.pass_length);
2072
2073 return hdd_set_app_type1_params(hHal, &params);
2074}
2075
2076static int hdd_set_app_type2_params(tHalHandle hHal,
2077 tpSirAppType2Params arg_params)
2078{
2079 tSirAppType2Params params;
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05302080 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002081
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302082 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002083
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05302084 qdf_ret_status = sme_configure_app_type2_params(hHal, &params);
2085 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302086 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002087 FL("sme_configure_app_type2_params returned failure %d"),
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05302088 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002089 return -EPERM;
2090 }
2091
2092 return 0;
2093}
2094
2095static int hdd_set_app_type2_parser(hdd_adapter_t *adapter,
2096 char *arg, int len)
2097{
2098 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2099 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
2100 char mac_addr[20], rc4_key[20];
Anurag Chouhan6d760662016-02-20 16:05:43 +05302101 unsigned int gateway_mac[QDF_MAC_ADDR_SIZE];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002102 tSirAppType2Params params;
2103 int ret;
2104
2105 ret = wlan_hdd_validate_context(hdd_ctx);
2106 if (0 != ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302107 hddLog(QDF_TRACE_LEVEL_ERROR, FL("HDD context is not valid"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002108 return -EINVAL;
2109 }
2110
2111 memset(&params, 0, sizeof(tSirAppType2Params));
2112
Bhargav Shahf4fd97d2015-07-08 10:21:37 +05302113 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 -08002114 mac_addr, rc4_key, (unsigned int *)&params.ip_id,
2115 (unsigned int *)&params.ip_device_ip,
2116 (unsigned int *)&params.ip_server_ip,
2117 (unsigned int *)&params.tcp_seq,
2118 (unsigned int *)&params.tcp_ack_seq,
Bhargav Shahf4fd97d2015-07-08 10:21:37 +05302119 (uint16_t *)&params.tcp_src_port,
2120 (uint16_t *)&params.tcp_dst_port,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002121 (unsigned int *)&params.keepalive_init,
2122 (unsigned int *)&params.keepalive_min,
2123 (unsigned int *)&params.keepalive_max,
2124 (unsigned int *)&params.keepalive_inc,
2125 (unsigned int *)&params.tcp_tx_timeout_val,
2126 (unsigned int *)&params.tcp_rx_timeout_val);
2127
2128 if (ret != 15 && ret != 7) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302129 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002130 "Invalid Number of arguments");
2131 return -EINVAL;
2132 }
2133
2134 if (6 !=
2135 sscanf(mac_addr, "%02x:%02x:%02x:%02x:%02x:%02x", &gateway_mac[0],
2136 &gateway_mac[1], &gateway_mac[2], &gateway_mac[3],
2137 &gateway_mac[4], &gateway_mac[5])) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302138 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002139 "Invalid MacAddress Input %s", mac_addr);
2140 return -EINVAL;
2141 }
2142
2143 if (params.tcp_src_port > WLAN_HDD_MAX_TCP_PORT ||
2144 params.tcp_dst_port > WLAN_HDD_MAX_TCP_PORT) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302145 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002146 "Invalid TCP Port Number");
2147 return -EINVAL;
2148 }
2149
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302150 qdf_mem_copy(&params.gateway_mac.bytes, (uint8_t *) &gateway_mac,
Anurag Chouhan6d760662016-02-20 16:05:43 +05302151 QDF_MAC_ADDR_SIZE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002152
2153 params.rc4_key_len = strlen(rc4_key);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302154 qdf_mem_copy(params.rc4_key, rc4_key, params.rc4_key_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002155
2156 params.vdev_id = adapter->sessionId;
2157 params.tcp_src_port = (params.tcp_src_port != 0) ?
2158 params.tcp_src_port : hdd_ctx->config->extWowApp2TcpSrcPort;
2159 params.tcp_dst_port = (params.tcp_dst_port != 0) ?
2160 params.tcp_dst_port : hdd_ctx->config->extWowApp2TcpDstPort;
2161 params.keepalive_init = (params.keepalive_init != 0) ?
2162 params.keepalive_init : hdd_ctx->config->
2163 extWowApp2KAInitPingInterval;
2164 params.keepalive_min =
2165 (params.keepalive_min != 0) ?
2166 params.keepalive_min :
2167 hdd_ctx->config->extWowApp2KAMinPingInterval;
2168 params.keepalive_max =
2169 (params.keepalive_max != 0) ?
2170 params.keepalive_max :
2171 hdd_ctx->config->extWowApp2KAMaxPingInterval;
2172 params.keepalive_inc =
2173 (params.keepalive_inc != 0) ?
2174 params.keepalive_inc :
2175 hdd_ctx->config->extWowApp2KAIncPingInterval;
2176 params.tcp_tx_timeout_val =
2177 (params.tcp_tx_timeout_val != 0) ?
2178 params.tcp_tx_timeout_val :
2179 hdd_ctx->config->extWowApp2TcpTxTimeout;
2180 params.tcp_rx_timeout_val =
2181 (params.tcp_rx_timeout_val != 0) ?
2182 params.tcp_rx_timeout_val :
2183 hdd_ctx->config->extWowApp2TcpRxTimeout;
2184
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302185 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002186 "%s: %pM %.16s %u %u %u %u %u %u %u %u %u %u %u %u %u",
2187 __func__, gateway_mac, rc4_key, params.ip_id,
2188 params.ip_device_ip, params.ip_server_ip, params.tcp_seq,
2189 params.tcp_ack_seq, params.tcp_src_port, params.tcp_dst_port,
2190 params.keepalive_init, params.keepalive_min,
2191 params.keepalive_max, params.keepalive_inc,
2192 params.tcp_tx_timeout_val, params.tcp_rx_timeout_val);
2193
2194 return hdd_set_app_type2_params(hHal, &params);
2195}
2196#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
2197
2198/**
2199 * hdd_parse_setmaxtxpower_command() - HDD Parse MAXTXPOWER command
2200 * @pValue: Pointer to MAXTXPOWER command
2201 * @pDbm: Pointer to tx power
2202 *
2203 * This function parses the MAXTXPOWER command passed in the format
2204 * MAXTXPOWER<space>X(Tx power in dbm)
2205 *
2206 * For example input commands:
2207 * 1) MAXTXPOWER -8 -> This is translated into set max TX power to -8 dbm
2208 * 2) MAXTXPOWER -23 -> This is translated into set max TX power to -23 dbm
2209 *
2210 * Return: 0 for success non-zero for failure
2211 */
2212static int hdd_parse_setmaxtxpower_command(uint8_t *pValue, int *pTxPower)
2213{
2214 uint8_t *inPtr = pValue;
2215 int tempInt;
2216 int v = 0;
2217 *pTxPower = 0;
2218
2219 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2220 /* no argument after the command */
2221 if (NULL == inPtr) {
2222 return -EINVAL;
2223 }
2224
2225 /* no space after the command */
2226 else if (SPACE_ASCII_VALUE != *inPtr) {
2227 return -EINVAL;
2228 }
2229
2230 /* remove empty spaces */
2231 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2232 inPtr++;
2233
2234 /* no argument followed by spaces */
2235 if ('\0' == *inPtr) {
2236 return 0;
2237 }
2238
2239 v = kstrtos32(inPtr, 10, &tempInt);
2240
2241 /* Range checking for passed parameter */
2242 if ((tempInt < HDD_MIN_TX_POWER) || (tempInt > HDD_MAX_TX_POWER)) {
2243 return -EINVAL;
2244 }
2245
2246 *pTxPower = tempInt;
2247
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302248 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002249 "SETMAXTXPOWER: %d", *pTxPower);
2250
2251 return 0;
2252} /* End of hdd_parse_setmaxtxpower_command */
2253
2254static int hdd_get_dwell_time(struct hdd_config *pCfg, uint8_t *command,
2255 char *extra, uint8_t n, uint8_t *len)
2256{
2257 int ret = 0;
2258
2259 if (!pCfg || !command || !extra || !len) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302260 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002261 "%s: argument passed for GETDWELLTIME is incorrect",
2262 __func__);
2263 ret = -EINVAL;
2264 return ret;
2265 }
2266
2267 if (strncmp(command, "GETDWELLTIME ACTIVE MAX", 23) == 0) {
2268 *len = scnprintf(extra, n, "GETDWELLTIME ACTIVE MAX %u\n",
2269 (int)pCfg->nActiveMaxChnTime);
2270 return ret;
2271 } else if (strncmp(command, "GETDWELLTIME ACTIVE MIN", 23) == 0) {
2272 *len = scnprintf(extra, n, "GETDWELLTIME ACTIVE MIN %u\n",
2273 (int)pCfg->nActiveMinChnTime);
2274 return ret;
2275 } else if (strncmp(command, "GETDWELLTIME PASSIVE MAX", 24) == 0) {
2276 *len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MAX %u\n",
2277 (int)pCfg->nPassiveMaxChnTime);
2278 return ret;
2279 } else if (strncmp(command, "GETDWELLTIME PASSIVE MIN", 24) == 0) {
2280 *len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MIN %u\n",
2281 (int)pCfg->nPassiveMinChnTime);
2282 return ret;
2283 } else if (strncmp(command, "GETDWELLTIME", 12) == 0) {
2284 *len = scnprintf(extra, n, "GETDWELLTIME %u \n",
2285 (int)pCfg->nActiveMaxChnTime);
2286 return ret;
2287 } else {
2288 ret = -EINVAL;
2289 }
2290
2291 return ret;
2292}
2293
2294static int hdd_set_dwell_time(hdd_adapter_t *adapter, uint8_t *command)
2295{
2296 tHalHandle hHal;
2297 struct hdd_config *pCfg;
2298 uint8_t *value = command;
2299 tSmeConfigParams smeConfig;
2300 int val = 0, temp = 0;
2301
2302 pCfg = (WLAN_HDD_GET_CTX(adapter))->config;
2303 hHal = WLAN_HDD_GET_HAL_CTX(adapter);
2304 if (!pCfg || !hHal) {
2305 hddLog(LOGE,
2306 FL("argument passed for SETDWELLTIME is incorrect"));
2307 return -EINVAL;
2308 }
2309
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302310 qdf_mem_zero(&smeConfig, sizeof(smeConfig));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002311 sme_get_config_param(hHal, &smeConfig);
2312
2313 if (strncmp(command, "SETDWELLTIME ACTIVE MAX", 23) == 0) {
2314 value = value + 24;
2315 temp = kstrtou32(value, 10, &val);
2316 if (temp != 0 || val < CFG_ACTIVE_MAX_CHANNEL_TIME_MIN ||
2317 val > CFG_ACTIVE_MAX_CHANNEL_TIME_MAX) {
2318 hddLog(LOGE,
2319 FL("argument passed for SETDWELLTIME ACTIVE MAX is incorrect"));
2320 return -EFAULT;
2321 }
2322 pCfg->nActiveMaxChnTime = val;
2323 smeConfig.csrConfig.nActiveMaxChnTime = val;
2324 sme_update_config(hHal, &smeConfig);
2325 } else if (strncmp(command, "SETDWELLTIME ACTIVE MIN", 23) == 0) {
2326 value = value + 24;
2327 temp = kstrtou32(value, 10, &val);
2328 if (temp != 0 || val < CFG_ACTIVE_MIN_CHANNEL_TIME_MIN ||
2329 val > CFG_ACTIVE_MIN_CHANNEL_TIME_MAX) {
2330 hddLog(LOGE,
2331 FL("argument passed for SETDWELLTIME ACTIVE MIN is incorrect"));
2332 return -EFAULT;
2333 }
2334 pCfg->nActiveMinChnTime = val;
2335 smeConfig.csrConfig.nActiveMinChnTime = val;
2336 sme_update_config(hHal, &smeConfig);
2337 } else if (strncmp(command, "SETDWELLTIME PASSIVE MAX", 24) == 0) {
2338 value = value + 25;
2339 temp = kstrtou32(value, 10, &val);
2340 if (temp != 0 || val < CFG_PASSIVE_MAX_CHANNEL_TIME_MIN ||
2341 val > CFG_PASSIVE_MAX_CHANNEL_TIME_MAX) {
2342 hddLog(LOGE,
2343 FL("argument passed for SETDWELLTIME PASSIVE MAX is incorrect"));
2344 return -EFAULT;
2345 }
2346 pCfg->nPassiveMaxChnTime = val;
2347 smeConfig.csrConfig.nPassiveMaxChnTime = val;
2348 sme_update_config(hHal, &smeConfig);
2349 } else if (strncmp(command, "SETDWELLTIME PASSIVE MIN", 24) == 0) {
2350 value = value + 25;
2351 temp = kstrtou32(value, 10, &val);
2352 if (temp != 0 || val < CFG_PASSIVE_MIN_CHANNEL_TIME_MIN ||
2353 val > CFG_PASSIVE_MIN_CHANNEL_TIME_MAX) {
2354 hddLog(LOGE,
2355 FL("argument passed for SETDWELLTIME PASSIVE MIN is incorrect"));
2356 return -EFAULT;
2357 }
2358 pCfg->nPassiveMinChnTime = val;
2359 smeConfig.csrConfig.nPassiveMinChnTime = val;
2360 sme_update_config(hHal, &smeConfig);
2361 } else if (strncmp(command, "SETDWELLTIME", 12) == 0) {
2362 value = value + 13;
2363 temp = kstrtou32(value, 10, &val);
2364 if (temp != 0 || val < CFG_ACTIVE_MAX_CHANNEL_TIME_MIN ||
2365 val > CFG_ACTIVE_MAX_CHANNEL_TIME_MAX) {
2366 hddLog(LOGE,
2367 FL("argument passed for SETDWELLTIME is incorrect"));
2368 return -EFAULT;
2369 }
2370 pCfg->nActiveMaxChnTime = val;
2371 smeConfig.csrConfig.nActiveMaxChnTime = val;
2372 sme_update_config(hHal, &smeConfig);
2373 } else {
2374 return -EINVAL;
2375 }
2376
2377 return 0;
2378}
2379
2380static void hdd_get_link_status_cb(uint8_t status, void *context)
2381{
2382 struct statsContext *pLinkContext;
2383 hdd_adapter_t *adapter;
2384
2385 if (NULL == context) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302386 hddLog(QDF_TRACE_LEVEL_ERROR, "%s: Bad context [%p]",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002387 __func__, context);
2388 return;
2389 }
2390
2391 pLinkContext = context;
2392 adapter = pLinkContext->pAdapter;
2393
2394 spin_lock(&hdd_context_lock);
2395
2396 if ((NULL == adapter) ||
2397 (LINK_STATUS_MAGIC != pLinkContext->magic)) {
2398 /*
2399 * the caller presumably timed out so there is
2400 * nothing we can do
2401 */
2402 spin_unlock(&hdd_context_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302403 hddLog(QDF_TRACE_LEVEL_WARN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002404 "%s: Invalid context, adapter [%p] magic [%08x]",
2405 __func__, adapter, pLinkContext->magic);
2406 return;
2407 }
2408
2409 /* context is valid so caller is still waiting */
2410
2411 /* paranoia: invalidate the magic */
2412 pLinkContext->magic = 0;
2413
2414 /* copy over the status */
2415 adapter->linkStatus = status;
2416
2417 /* notify the caller */
2418 complete(&pLinkContext->completion);
2419
2420 /* serialization is complete */
2421 spin_unlock(&hdd_context_lock);
2422}
2423
2424/**
2425 * wlan_hdd_get_link_status() - get link status
2426 * @pAdapter: pointer to the adapter
2427 *
2428 * This function sends a request to query the link status and waits
2429 * on a timer to invoke the callback. if the callback is invoked then
2430 * latest link status shall be returned or otherwise cached value
2431 * will be returned.
2432 *
2433 * Return: On success, link status shall be returned.
2434 * On error or not associated, link status 0 will be returned.
2435 */
2436static int wlan_hdd_get_link_status(hdd_adapter_t *adapter)
2437{
2438
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002439 hdd_station_ctx_t *pHddStaCtx =
2440 WLAN_HDD_GET_STATION_CTX_PTR(adapter);
2441 struct statsContext context;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302442 QDF_STATUS hstatus;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002443 unsigned long rc;
2444
Prashanth Bhatta9e143052015-12-04 11:56:47 -08002445 if (cds_is_driver_recovering()) {
2446 hdd_warn("Recovery in Progress. State: 0x%x Ignore!!!",
2447 cds_get_driver_state());
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002448 return 0;
2449 }
2450
Krunal Sonibe766b02016-03-10 13:00:44 -08002451 if ((QDF_STA_MODE != adapter->device_mode) &&
2452 (QDF_P2P_CLIENT_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002453 hdd_warn("Unsupported in mode %s(%d)",
2454 hdd_device_mode_to_string(adapter->device_mode),
2455 adapter->device_mode);
2456 return 0;
2457 }
2458
2459 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
2460 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
2461 /* If not associated, then expected link status return
2462 * value is 0
2463 */
2464 hddLog(LOG1, FL("Not associated!"));
2465 return 0;
2466 }
2467
2468 init_completion(&context.completion);
2469 context.pAdapter = adapter;
2470 context.magic = LINK_STATUS_MAGIC;
2471 hstatus = sme_get_link_status(WLAN_HDD_GET_HAL_CTX(adapter),
2472 hdd_get_link_status_cb,
2473 &context, adapter->sessionId);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302474 if (QDF_STATUS_SUCCESS != hstatus) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302475 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002476 "%s: Unable to retrieve link status", __func__);
2477 /* return a cached value */
2478 } else {
2479 /* request is sent -- wait for the response */
2480 rc = wait_for_completion_timeout(&context.completion,
2481 msecs_to_jiffies(WLAN_WAIT_TIME_LINK_STATUS));
2482 if (!rc)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302483 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002484 FL("SME timed out while retrieving link status"));
2485 }
2486
2487 spin_lock(&hdd_context_lock);
2488 context.magic = 0;
2489 spin_unlock(&hdd_context_lock);
2490
2491 /* either callback updated adapter stats or it has cached data */
2492 return adapter->linkStatus;
2493}
2494
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002495static void hdd_tx_fail_ind_callback(uint8_t *MacAddr, uint8_t seqNo)
2496{
2497 int payload_len;
2498 struct sk_buff *skb;
2499 struct nlmsghdr *nlh;
2500 uint8_t *data;
2501
2502 payload_len = ETH_ALEN;
2503
2504 if (0 == cesium_pid) {
2505 hddLog(QDF_TRACE_LEVEL_ERROR,
2506 "%s: cesium process not registered", __func__);
2507 return;
2508 }
2509
2510 skb = nlmsg_new(payload_len, GFP_ATOMIC);
2511 if (skb == NULL) {
2512 hddLog(LOGE,
2513 FL("nlmsg_new() failed for msg size[%d]"),
2514 NLMSG_SPACE(payload_len));
2515 return;
2516 }
2517
2518 nlh = nlmsg_put(skb, cesium_pid, seqNo, 0, payload_len, NLM_F_REQUEST);
2519
2520 if (NULL == nlh) {
2521 hddLog(QDF_TRACE_LEVEL_ERROR,
2522 "%s: nlmsg_put() failed for msg size[%d]",
2523 __func__, NLMSG_SPACE(payload_len));
2524
2525 kfree_skb(skb);
2526 return;
2527 }
2528
2529 data = nlmsg_data(nlh);
2530 memcpy(data, MacAddr, ETH_ALEN);
2531
2532 if (nlmsg_unicast(cesium_nl_srv_sock, skb, cesium_pid) < 0) {
2533 hddLog(QDF_TRACE_LEVEL_ERROR,
2534 "%s: nlmsg_unicast() failed for msg size[%d]",
2535 __func__, NLMSG_SPACE(payload_len));
2536 }
2537
2538 return;
2539}
2540
2541
2542/**
2543 * hdd_ParseuserParams - return a pointer to the next argument
2544 * @pValue: Input argument string
2545 * @ppArg: Output pointer to the next argument
2546 *
2547 * This function parses argument stream and finds the pointer
2548 * to the next argument
2549 *
2550 * Return: 0 if the next argument found; -EINVAL otherwise
2551 */
2552static int hdd_parse_user_params(uint8_t *pValue, uint8_t **ppArg)
2553{
2554 uint8_t *pVal;
2555
2556 pVal = strnchr(pValue, strlen(pValue), ' ');
2557
2558 if (NULL == pVal) {
2559 /* no argument remains */
2560 return -EINVAL;
2561 } else if (SPACE_ASCII_VALUE != *pVal) {
2562 /* no space after the current argument */
2563 return -EINVAL;
2564 }
2565
2566 pVal++;
2567
2568 /* remove empty spaces */
2569 while ((SPACE_ASCII_VALUE == *pVal) && ('\0' != *pVal)) {
2570 pVal++;
2571 }
2572
2573 /* no argument followed by spaces */
2574 if ('\0' == *pVal) {
2575 return -EINVAL;
2576 }
2577
2578 *ppArg = pVal;
2579
2580 return 0;
2581}
2582
2583/**
2584 * hdd_parse_ibsstx_fail_event_params - Parse params
2585 * for SETIBSSTXFAILEVENT
2586 * @pValue: Input ibss tx fail event argument
2587 * @tx_fail_count: (Output parameter) Tx fail counter
2588 * @pid: (Output parameter) PID
2589 *
2590 * Return: 0 if the parsing succeeds; -EINVAL otherwise
2591 */
2592static int hdd_parse_ibsstx_fail_event_params(uint8_t *pValue,
2593 uint8_t *tx_fail_count,
2594 uint16_t *pid)
2595{
2596 uint8_t *param = NULL;
2597 int ret;
2598
2599 ret = hdd_parse_user_params(pValue, &param);
2600
2601 if (0 == ret && NULL != param) {
2602 if (1 != sscanf(param, "%hhu", tx_fail_count)) {
2603 ret = -EINVAL;
2604 goto done;
2605 }
2606 } else {
2607 goto done;
2608 }
2609
2610 if (0 == *tx_fail_count) {
2611 *pid = 0;
2612 goto done;
2613 }
2614
2615 pValue = param;
2616 pValue++;
2617
2618 ret = hdd_parse_user_params(pValue, &param);
2619
2620 if (0 == ret) {
2621 if (1 != sscanf(param, "%hu", pid)) {
2622 ret = -EINVAL;
2623 goto done;
2624 }
2625 } else {
2626 goto done;
2627 }
2628
2629done:
2630 return ret;
2631}
2632
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08002633#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002634/**
2635 * hdd_parse_ese_beacon_req() - Parse ese beacon request
2636 * @pValue: Pointer to data
2637 * @pEseBcnReq: Output pointer to store parsed ie information
2638 *
2639 * This function parses the ese beacon request passed in the format
2640 * CCXBEACONREQ<space><Number of fields><space><Measurement token>
2641 * <space>Channel 1<space>Scan Mode <space>Meas Duration<space>Channel N
2642 * <space>Scan Mode N<space>Meas Duration N
2643 *
2644 * If the Number of bcn req fields (N) does not match with the
2645 * actual number of fields passed then take N.
2646 * <Meas Token><Channel><Scan Mode> and <Meas Duration> are treated
2647 * as one pair. For example, CCXBEACONREQ 2 1 1 1 30 2 44 0 40.
2648 * This function does not take care of removing duplicate channels from the
2649 * list
2650 *
2651 * Return: 0 for success non-zero for failure
2652 */
2653static int hdd_parse_ese_beacon_req(uint8_t *pValue,
2654 tCsrEseBeaconReq *pEseBcnReq)
2655{
2656 uint8_t *inPtr = pValue;
2657 int tempInt = 0;
2658 int j = 0, i = 0, v = 0;
2659 char buf[32];
2660
2661 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2662 /* no argument after the command */
2663 if (NULL == inPtr) {
2664 return -EINVAL;
2665 }
2666 /* no space after the command */
2667 else if (SPACE_ASCII_VALUE != *inPtr) {
2668 return -EINVAL;
2669 }
2670
2671 /* remove empty spaces */
2672 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2673 inPtr++;
2674
2675 /* no argument followed by spaces */
2676 if ('\0' == *inPtr)
2677 return -EINVAL;
2678
2679 /* get the first argument ie measurement token */
2680 v = sscanf(inPtr, "%31s ", buf);
2681 if (1 != v)
2682 return -EINVAL;
2683
2684 v = kstrtos32(buf, 10, &tempInt);
2685 if (v < 0)
2686 return -EINVAL;
2687
2688 pEseBcnReq->numBcnReqIe = tempInt;
2689
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302690 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002691 "Number of Bcn Req Ie fields(%d)", pEseBcnReq->numBcnReqIe);
2692
2693 for (j = 0; j < (pEseBcnReq->numBcnReqIe); j++) {
2694 for (i = 0; i < 4; i++) {
2695 /*
2696 * inPtr pointing to the beginning of 1st space
2697 * after number of ie fields
2698 */
2699 inPtr = strpbrk(inPtr, " ");
2700 /* no ie data after the number of ie fields argument */
2701 if (NULL == inPtr)
2702 return -EINVAL;
2703
2704 /* remove empty space */
2705 while ((SPACE_ASCII_VALUE == *inPtr)
2706 && ('\0' != *inPtr))
2707 inPtr++;
2708
2709 /*
2710 * no ie data after the number of ie fields
2711 * argument and spaces
2712 */
2713 if ('\0' == *inPtr)
2714 return -EINVAL;
2715
2716 v = sscanf(inPtr, "%31s ", buf);
2717 if (1 != v)
2718 return -EINVAL;
2719
2720 v = kstrtos32(buf, 10, &tempInt);
2721 if (v < 0)
2722 return -EINVAL;
2723
2724 switch (i) {
2725 case 0: /* Measurement token */
2726 if (tempInt <= 0) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302727 QDF_TRACE(QDF_MODULE_ID_HDD,
2728 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002729 "Invalid Measurement Token(%d)",
2730 tempInt);
2731 return -EINVAL;
2732 }
2733 pEseBcnReq->bcnReq[j].measurementToken =
2734 tempInt;
2735 break;
2736
2737 case 1: /* Channel number */
2738 if ((tempInt <= 0) ||
2739 (tempInt >
2740 WNI_CFG_CURRENT_CHANNEL_STAMAX)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302741 QDF_TRACE(QDF_MODULE_ID_HDD,
2742 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002743 "Invalid Channel Number(%d)",
2744 tempInt);
2745 return -EINVAL;
2746 }
2747 pEseBcnReq->bcnReq[j].channel = tempInt;
2748 break;
2749
2750 case 2: /* Scan mode */
2751 if ((tempInt < eSIR_PASSIVE_SCAN)
2752 || (tempInt > eSIR_BEACON_TABLE)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302753 QDF_TRACE(QDF_MODULE_ID_HDD,
2754 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002755 "Invalid Scan Mode(%d) Expected{0|1|2}",
2756 tempInt);
2757 return -EINVAL;
2758 }
2759 pEseBcnReq->bcnReq[j].scanMode = tempInt;
2760 break;
2761
2762 case 3: /* Measurement duration */
2763 if (((tempInt <= 0)
2764 && (pEseBcnReq->bcnReq[j].scanMode !=
2765 eSIR_BEACON_TABLE)) ||
2766 ((tempInt < 0) &&
2767 (pEseBcnReq->bcnReq[j].scanMode ==
2768 eSIR_BEACON_TABLE))) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302769 QDF_TRACE(QDF_MODULE_ID_HDD,
2770 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002771 "Invalid Measurement Duration(%d)",
2772 tempInt);
2773 return -EINVAL;
2774 }
2775 pEseBcnReq->bcnReq[j].measurementDuration =
2776 tempInt;
2777 break;
2778 }
2779 }
2780 }
2781
2782 for (j = 0; j < pEseBcnReq->numBcnReqIe; j++) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302783 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002784 "Index(%d) Measurement Token(%u) Channel(%u) Scan Mode(%u) Measurement Duration(%u)",
2785 j,
2786 pEseBcnReq->bcnReq[j].measurementToken,
2787 pEseBcnReq->bcnReq[j].channel,
2788 pEseBcnReq->bcnReq[j].scanMode,
2789 pEseBcnReq->bcnReq[j].measurementDuration);
2790 }
2791
2792 return 0;
2793}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002794
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002795/**
2796 * hdd_parse_get_cckm_ie() - HDD Parse and fetch the CCKM IE
2797 * @pValue: Pointer to input data
2798 * @pCckmIe: Pointer to output cckm Ie
2799 * @pCckmIeLen: Pointer to output cckm ie length
2800 *
2801 * This function parses the SETCCKM IE command
2802 * SETCCKMIE<space><ie data>
2803 *
2804 * Return: 0 for success non-zero for failure
2805 */
2806static int hdd_parse_get_cckm_ie(uint8_t *pValue, uint8_t **pCckmIe,
2807 uint8_t *pCckmIeLen)
2808{
2809 uint8_t *inPtr = pValue;
2810 uint8_t *dataEnd;
2811 int j = 0;
2812 int i = 0;
2813 uint8_t tempByte = 0;
2814 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2815 /* no argument after the command */
2816 if (NULL == inPtr) {
2817 return -EINVAL;
2818 }
2819 /* no space after the command */
2820 else if (SPACE_ASCII_VALUE != *inPtr) {
2821 return -EINVAL;
2822 }
2823 /* remove empty spaces */
2824 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2825 inPtr++;
2826 /* no argument followed by spaces */
2827 if ('\0' == *inPtr) {
2828 return -EINVAL;
2829 }
2830 /* find the length of data */
2831 dataEnd = inPtr;
2832 while (('\0' != *dataEnd)) {
2833 dataEnd++;
2834 ++(*pCckmIeLen);
2835 }
2836 if (*pCckmIeLen <= 0)
2837 return -EINVAL;
2838 /*
2839 * Allocate the number of bytes based on the number of input characters
2840 * whether it is even or odd.
2841 * if the number of input characters are even, then we need N / 2 byte.
2842 * if the number of input characters are odd, then we need do
2843 * (N + 1) / 2 to compensate rounding off.
2844 * For example, if N = 18, then (18 + 1) / 2 = 9 bytes are enough.
2845 * If N = 19, then we need 10 bytes, hence (19 + 1) / 2 = 10 bytes
2846 */
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302847 *pCckmIe = qdf_mem_malloc((*pCckmIeLen + 1) / 2);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002848 if (NULL == *pCckmIe) {
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05302849 hddLog(LOGE, FL("qdf_mem_malloc failed"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002850 return -ENOMEM;
2851 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302852 qdf_mem_zero(*pCckmIe, (*pCckmIeLen + 1) / 2);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002853 /*
2854 * the buffer received from the upper layer is character buffer,
2855 * we need to prepare the buffer taking 2 characters in to a U8 hex
2856 * decimal number for example 7f0000f0...form a buffer to contain
2857 * 7f in 0th location, 00 in 1st and f0 in 3rd location
2858 */
2859 for (i = 0, j = 0; j < *pCckmIeLen; j += 2) {
2860 tempByte = (hex_to_bin(inPtr[j]) << 4) |
2861 (hex_to_bin(inPtr[j + 1]));
2862 (*pCckmIe)[i++] = tempByte;
2863 }
2864 *pCckmIeLen = i;
2865 return 0;
2866}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08002867#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002868
2869int wlan_hdd_set_mc_rate(hdd_adapter_t *pAdapter, int targetRate)
2870{
2871 tSirRateUpdateInd rateUpdate = {0};
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302872 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002873 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
2874 struct hdd_config *pConfig = NULL;
2875
2876 if (pHddCtx == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302877 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002878 "%s: HDD context is null", __func__);
2879 return -EINVAL;
2880 }
Krunal Sonibe766b02016-03-10 13:00:44 -08002881 if ((QDF_IBSS_MODE != pAdapter->device_mode) &&
2882 (QDF_SAP_MODE != pAdapter->device_mode) &&
2883 (QDF_STA_MODE != pAdapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002884 hddLog(LOGE,
2885 FL("Received SETMCRATE cmd in invalid mode %s(%d)"),
2886 hdd_device_mode_to_string(pAdapter->device_mode),
2887 pAdapter->device_mode);
2888 hddLog(LOGE,
2889 FL("SETMCRATE cmd is allowed only in STA, IBSS or SOFTAP mode"));
2890 return -EINVAL;
2891 }
2892 pConfig = pHddCtx->config;
2893 rateUpdate.nss = (pConfig->enable2x2 == 0) ? 0 : 1;
2894 rateUpdate.dev_mode = pAdapter->device_mode;
2895 rateUpdate.mcastDataRate24GHz = targetRate;
2896 rateUpdate.mcastDataRate24GHzTxFlag = 1;
2897 rateUpdate.mcastDataRate5GHz = targetRate;
2898 rateUpdate.bcastDataRate = -1;
Anurag Chouhanc5548422016-02-24 18:33:27 +05302899 qdf_copy_macaddr(&rateUpdate.bssid, &pAdapter->macAddressCurrent);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002900 hddLog(LOG1,
2901 FL("MC Target rate %d, mac = %pM, dev_mode %s(%d)"),
Srinivas Girigowdaafede182015-11-18 22:36:12 -08002902 rateUpdate.mcastDataRate24GHz, rateUpdate.bssid.bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002903 hdd_device_mode_to_string(pAdapter->device_mode),
2904 pAdapter->device_mode);
2905 status = sme_send_rate_update_ind(pHddCtx->hHal, &rateUpdate);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302906 if (QDF_STATUS_SUCCESS != status) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302907 hddLog(QDF_TRACE_LEVEL_ERROR, "%s: SETMCRATE failed",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002908 __func__);
2909 return -EFAULT;
2910 }
2911 return 0;
2912}
2913
2914static int drv_cmd_p2p_dev_addr(hdd_adapter_t *adapter,
2915 hdd_context_t *hdd_ctx,
2916 uint8_t *command,
2917 uint8_t command_len,
2918 hdd_priv_data_t *priv_data)
2919{
2920 int ret = 0;
2921
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302922 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002923 TRACE_CODE_HDD_P2P_DEV_ADDR_IOCTL,
2924 adapter->sessionId,
2925 (unsigned)(*(hdd_ctx->p2pDeviceAddress.bytes + 2)
2926 << 24 | *(hdd_ctx->p2pDeviceAddress.bytes
2927 + 3) << 16 | *(hdd_ctx->
2928 p2pDeviceAddress.bytes + 4) << 8 |
2929 *(hdd_ctx->p2pDeviceAddress.bytes +
2930 5))));
2931
2932 if (copy_to_user(priv_data->buf, hdd_ctx->p2pDeviceAddress.bytes,
2933 sizeof(tSirMacAddr))) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302934 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002935 "%s: failed to copy data to user buffer",
2936 __func__);
2937 ret = -EFAULT;
2938 }
2939
2940 return ret;
2941}
2942
2943/**
2944 * drv_cmd_p2p_set_noa() - Handler for P2P_SET_NOA driver command
2945 * @adapter: Adapter on which the command was received
2946 * @hdd_ctx: HDD global context
2947 * @command: Entire driver command received from userspace
2948 * @command_len: Length of @command
2949 * @priv_data: Pointer to ioctl private data structure
2950 *
2951 * This is a trivial command hander function which simply forwards the
2952 * command to the actual command processor within the P2P module.
2953 *
2954 * Return: 0 on success, non-zero on failure
2955 */
2956static int drv_cmd_p2p_set_noa(hdd_adapter_t *adapter,
2957 hdd_context_t *hdd_ctx,
2958 uint8_t *command,
2959 uint8_t command_len,
2960 hdd_priv_data_t *priv_data)
2961{
2962 return hdd_set_p2p_noa(adapter->dev, command);
2963}
2964
2965/**
2966 * drv_cmd_p2p_set_ps() - Handler for P2P_SET_PS driver command
2967 * @adapter: Adapter on which the command was received
2968 * @hdd_ctx: HDD global context
2969 * @command: Entire driver command received from userspace
2970 * @command_len: Length of @command
2971 * @priv_data: Pointer to ioctl private data structure
2972 *
2973 * This is a trivial command hander function which simply forwards the
2974 * command to the actual command processor within the P2P module.
2975 *
2976 * Return: 0 on success, non-zero on failure
2977 */
2978static int drv_cmd_p2p_set_ps(hdd_adapter_t *adapter,
2979 hdd_context_t *hdd_ctx,
2980 uint8_t *command,
2981 uint8_t command_len,
2982 hdd_priv_data_t *priv_data)
2983{
2984 return hdd_set_p2p_opps(adapter->dev, command);
2985}
2986
2987static int drv_cmd_set_band(hdd_adapter_t *adapter,
2988 hdd_context_t *hdd_ctx,
2989 uint8_t *command,
2990 uint8_t command_len,
2991 hdd_priv_data_t *priv_data)
2992{
2993 int ret = 0;
2994
2995 uint8_t *ptr = command;
2996
2997 /* Change band request received */
2998
2999 /*
3000 * First 8 bytes will have "SETBAND " and
3001 * 9 byte will have band setting value
3002 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303003 hddLog(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003004 "%s: SetBandCommand Info comm %s UL %d, TL %d",
3005 __func__, command, priv_data->used_len,
3006 priv_data->total_len);
3007
3008 /* Change band request received */
3009 ret = hdd_set_band_helper(adapter->dev, ptr);
3010
3011 return ret;
3012}
3013
3014static int drv_cmd_set_wmmps(hdd_adapter_t *adapter,
3015 hdd_context_t *hdd_ctx,
3016 uint8_t *command,
3017 uint8_t command_len,
3018 hdd_priv_data_t *priv_data)
3019{
3020 return hdd_wmmps_helper(adapter, command);
3021}
3022
3023static int drv_cmd_country(hdd_adapter_t *adapter,
3024 hdd_context_t *hdd_ctx,
3025 uint8_t *command,
3026 uint8_t command_len,
3027 hdd_priv_data_t *priv_data)
3028{
3029 int ret = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303030 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003031 unsigned long rc;
3032 char *country_code;
3033
3034 country_code = command + 8;
3035
3036 INIT_COMPLETION(adapter->change_country_code);
3037
3038 status = sme_change_country_code(hdd_ctx->hHal,
3039 wlan_hdd_change_country_code_callback,
3040 country_code,
3041 adapter,
3042 hdd_ctx->pcds_context,
3043 eSIR_TRUE,
3044 eSIR_TRUE);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303045 if (status == QDF_STATUS_SUCCESS) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003046 rc = wait_for_completion_timeout(
3047 &adapter->change_country_code,
3048 msecs_to_jiffies(WLAN_WAIT_TIME_COUNTRY));
3049 if (!rc)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303050 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003051 "%s: SME while setting country code timed out",
3052 __func__);
3053 } else {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303054 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003055 "%s: SME Change Country code fail, status=%d",
3056 __func__, status);
3057 ret = -EINVAL;
3058 }
3059
3060 return ret;
3061}
3062
3063static int drv_cmd_set_roam_trigger(hdd_adapter_t *adapter,
3064 hdd_context_t *hdd_ctx,
3065 uint8_t *command,
3066 uint8_t command_len,
3067 hdd_priv_data_t *priv_data)
3068{
3069 int ret = 0;
3070 uint8_t *value = command;
3071 int8_t rssi = 0;
3072 uint8_t lookUpThreshold = CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_DEFAULT;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303073 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003074
3075 /* Move pointer to ahead of SETROAMTRIGGER<delimiter> */
3076 value = value + command_len + 1;
3077
3078 /* Convert the value from ascii to integer */
3079 ret = kstrtos8(value, 10, &rssi);
3080 if (ret < 0) {
3081 /*
3082 * If the input value is greater than max value of datatype,
3083 * then also kstrtou8 fails
3084 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303085 QDF_TRACE(QDF_MODULE_ID_HDD,
3086 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003087 "%s: kstrtou8 failed Input value may be out of range[%d - %d]",
3088 __func__,
3089 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN,
3090 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX);
3091 ret = -EINVAL;
3092 goto exit;
3093 }
3094
3095 lookUpThreshold = abs(rssi);
3096
3097 if ((lookUpThreshold < CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN)
3098 || (lookUpThreshold > CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303099 QDF_TRACE(QDF_MODULE_ID_HDD,
3100 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003101 "Neighbor lookup threshold value %d is out of range (Min: %d Max: %d)",
3102 lookUpThreshold,
3103 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN,
3104 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX);
3105 ret = -EINVAL;
3106 goto exit;
3107 }
3108
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303109 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003110 TRACE_CODE_HDD_SETROAMTRIGGER_IOCTL,
3111 adapter->sessionId, lookUpThreshold));
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303112 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003113 "%s: Received Command to Set Roam trigger (Neighbor lookup threshold) = %d",
3114 __func__,
3115 lookUpThreshold);
3116
3117 hdd_ctx->config->nNeighborLookupRssiThreshold = lookUpThreshold;
3118 status = sme_set_neighbor_lookup_rssi_threshold(hdd_ctx->hHal,
3119 adapter->sessionId,
3120 lookUpThreshold);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303121 if (QDF_STATUS_SUCCESS != status) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303122 QDF_TRACE(QDF_MODULE_ID_HDD,
3123 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003124 "%s: Failed to set roam trigger, try again",
3125 __func__);
3126 ret = -EPERM;
3127 goto exit;
3128 }
3129
3130exit:
3131 return ret;
3132}
3133
3134static int drv_cmd_get_roam_trigger(hdd_adapter_t *adapter,
3135 hdd_context_t *hdd_ctx,
3136 uint8_t *command,
3137 uint8_t command_len,
3138 hdd_priv_data_t *priv_data)
3139{
3140 int ret = 0;
3141 uint8_t lookUpThreshold =
3142 sme_get_neighbor_lookup_rssi_threshold(hdd_ctx->hHal);
3143 int rssi = (-1) * lookUpThreshold;
3144 char extra[32];
3145 uint8_t len = 0;
3146
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303147 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003148 TRACE_CODE_HDD_GETROAMTRIGGER_IOCTL,
3149 adapter->sessionId, lookUpThreshold));
3150
3151 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303152 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003153 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303154 QDF_TRACE(QDF_MODULE_ID_HDD,
3155 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003156 "%s: failed to copy data to user buffer",
3157 __func__);
3158 ret = -EFAULT;
3159 }
3160
3161 return ret;
3162}
3163
3164static int drv_cmd_set_roam_scan_period(hdd_adapter_t *adapter,
3165 hdd_context_t *hdd_ctx,
3166 uint8_t *command,
3167 uint8_t command_len,
3168 hdd_priv_data_t *priv_data)
3169{
3170 int ret = 0;
3171 uint8_t *value = command;
3172 uint8_t roamScanPeriod = 0;
3173 uint16_t neighborEmptyScanRefreshPeriod =
3174 CFG_EMPTY_SCAN_REFRESH_PERIOD_DEFAULT;
3175
3176 /* input refresh period is in terms of seconds */
3177
3178 /* Move pointer to ahead of SETROAMSCANPERIOD<delimiter> */
3179 value = value + command_len + 1;
3180
3181 /* Convert the value from ascii to integer */
3182 ret = kstrtou8(value, 10, &roamScanPeriod);
3183 if (ret < 0) {
3184 /*
3185 * If the input value is greater than max value of datatype,
3186 * then also kstrtou8 fails
3187 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303188 QDF_TRACE(QDF_MODULE_ID_HDD,
3189 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003190 "%s: kstrtou8 failed Input value may be out of range[%d - %d]",
3191 __func__,
3192 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000),
3193 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000));
3194 ret = -EINVAL;
3195 goto exit;
3196 }
3197
3198 if ((roamScanPeriod < (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000))
3199 || (roamScanPeriod > (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000))) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303200 QDF_TRACE(QDF_MODULE_ID_HDD,
3201 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003202 "Roam scan period value %d is out of range (Min: %d Max: %d)",
3203 roamScanPeriod,
3204 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000),
3205 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000));
3206 ret = -EINVAL;
3207 goto exit;
3208 }
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303209 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003210 TRACE_CODE_HDD_SETROAMSCANPERIOD_IOCTL,
3211 adapter->sessionId, roamScanPeriod));
3212 neighborEmptyScanRefreshPeriod = roamScanPeriod * 1000;
3213
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303214 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003215 "%s: Received Command to Set roam scan period (Empty Scan refresh period) = %d",
3216 __func__,
3217 roamScanPeriod);
3218
3219 hdd_ctx->config->nEmptyScanRefreshPeriod =
3220 neighborEmptyScanRefreshPeriod;
3221 sme_update_empty_scan_refresh_period(hdd_ctx->hHal,
3222 adapter->sessionId,
3223 neighborEmptyScanRefreshPeriod);
3224
3225exit:
3226 return ret;
3227}
3228
3229static int drv_cmd_get_roam_scan_period(hdd_adapter_t *adapter,
3230 hdd_context_t *hdd_ctx,
3231 uint8_t *command,
3232 uint8_t command_len,
3233 hdd_priv_data_t *priv_data)
3234{
3235 int ret = 0;
3236 uint16_t nEmptyScanRefreshPeriod =
3237 sme_get_empty_scan_refresh_period(hdd_ctx->hHal);
3238 char extra[32];
3239 uint8_t len = 0;
3240
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303241 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003242 TRACE_CODE_HDD_GETROAMSCANPERIOD_IOCTL,
3243 adapter->sessionId,
3244 nEmptyScanRefreshPeriod));
3245 len = scnprintf(extra, sizeof(extra), "%s %d",
3246 "GETROAMSCANPERIOD",
3247 (nEmptyScanRefreshPeriod / 1000));
3248 /* Returned value is in units of seconds */
Anurag Chouhan6d760662016-02-20 16:05:43 +05303249 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003250 if (copy_to_user(priv_data->buf, &extra, len)) {
3251 hddLog(LOGE,
3252 FL("failed to copy data to user buffer"));
3253 ret = -EFAULT;
3254 }
3255
3256 return ret;
3257}
3258
3259static int drv_cmd_set_roam_scan_refresh_period(hdd_adapter_t *adapter,
3260 hdd_context_t *hdd_ctx,
3261 uint8_t *command,
3262 uint8_t command_len,
3263 hdd_priv_data_t *priv_data)
3264{
3265 int ret = 0;
3266 uint8_t *value = command;
3267 uint8_t roamScanRefreshPeriod = 0;
3268 uint16_t neighborScanRefreshPeriod =
3269 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_DEFAULT;
3270
3271 /* input refresh period is in terms of seconds */
3272 /* Move pointer to ahead of SETROAMSCANREFRESHPERIOD<delimiter> */
3273 value = value + command_len + 1;
3274
3275 /* Convert the value from ascii to integer */
3276 ret = kstrtou8(value, 10, &roamScanRefreshPeriod);
3277 if (ret < 0) {
3278 /*
3279 * If the input value is greater than max value of datatype,
3280 * then also kstrtou8 fails
3281 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303282 QDF_TRACE(QDF_MODULE_ID_HDD,
3283 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003284 "%s: kstrtou8 failed Input value may be out of range[%d - %d]",
3285 __func__,
3286 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN / 1000,
3287 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX / 1000);
3288 ret = -EINVAL;
3289 goto exit;
3290 }
3291
3292 if ((roamScanRefreshPeriod <
3293 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN / 1000))
3294 || (roamScanRefreshPeriod >
3295 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX / 1000))) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303296 QDF_TRACE(QDF_MODULE_ID_HDD,
3297 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003298 "Neighbor scan results refresh period value %d is out of range (Min: %d Max: %d)",
3299 roamScanRefreshPeriod,
3300 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN
3301 / 1000),
3302 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX
3303 / 1000));
3304 ret = -EINVAL;
3305 goto exit;
3306 }
3307 neighborScanRefreshPeriod = roamScanRefreshPeriod * 1000;
3308
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303309 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003310 "%s: Received Command to Set roam scan refresh period (Scan refresh period) = %d",
3311 __func__,
3312 roamScanRefreshPeriod);
3313
3314 hdd_ctx->config->nNeighborResultsRefreshPeriod =
3315 neighborScanRefreshPeriod;
3316 sme_set_neighbor_scan_refresh_period(hdd_ctx->hHal,
3317 adapter->sessionId,
3318 neighborScanRefreshPeriod);
3319
3320exit:
3321 return ret;
3322}
3323
3324static int drv_cmd_get_roam_scan_refresh_period(hdd_adapter_t *adapter,
3325 hdd_context_t *hdd_ctx,
3326 uint8_t *command,
3327 uint8_t command_len,
3328 hdd_priv_data_t *priv_data)
3329{
3330 int ret = 0;
3331 uint16_t value =
3332 sme_get_neighbor_scan_refresh_period(hdd_ctx->hHal);
3333 char extra[32];
3334 uint8_t len = 0;
3335
3336 len = scnprintf(extra, sizeof(extra), "%s %d",
3337 "GETROAMSCANREFRESHPERIOD",
3338 (value / 1000));
3339 /* Returned value is in units of seconds */
Anurag Chouhan6d760662016-02-20 16:05:43 +05303340 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003341 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303342 QDF_TRACE(QDF_MODULE_ID_HDD,
3343 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003344 "%s: failed to copy data to user buffer",
3345 __func__);
3346 ret = -EFAULT;
3347 }
3348
3349 return ret;
3350}
3351
3352static int drv_cmd_set_roam_mode(hdd_adapter_t *adapter,
3353 hdd_context_t *hdd_ctx,
3354 uint8_t *command,
3355 uint8_t command_len,
3356 hdd_priv_data_t *priv_data)
3357{
3358 int ret = 0;
3359 uint8_t *value = command;
3360 uint8_t roamMode = CFG_LFR_FEATURE_ENABLED_DEFAULT;
3361
3362 /* Move pointer to ahead of SETROAMMODE<delimiter> */
3363 value = value + SIZE_OF_SETROAMMODE + 1;
3364
3365 /* Convert the value from ascii to integer */
3366 ret = kstrtou8(value, SIZE_OF_SETROAMMODE, &roamMode);
3367 if (ret < 0) {
3368 /*
3369 * If the input value is greater than max value of datatype,
3370 * then also kstrtou8 fails
3371 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303372 QDF_TRACE(QDF_MODULE_ID_HDD,
3373 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003374 "%s: kstrtou8 failed range [%d - %d]",
3375 __func__, CFG_LFR_FEATURE_ENABLED_MIN,
3376 CFG_LFR_FEATURE_ENABLED_MAX);
3377 ret = -EINVAL;
3378 goto exit;
3379 }
3380 if ((roamMode < CFG_LFR_FEATURE_ENABLED_MIN) ||
3381 (roamMode > CFG_LFR_FEATURE_ENABLED_MAX)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303382 QDF_TRACE(QDF_MODULE_ID_HDD,
3383 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003384 "Roam Mode value %d is out of range (Min: %d Max: %d)",
3385 roamMode,
3386 CFG_LFR_FEATURE_ENABLED_MIN,
3387 CFG_LFR_FEATURE_ENABLED_MAX);
3388 ret = -EINVAL;
3389 goto exit;
3390 }
3391
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303392 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003393 "%s: Received Command to Set Roam Mode = %d",
3394 __func__, roamMode);
3395 /*
3396 * Note that
3397 * SETROAMMODE 0 is to enable LFR while
3398 * SETROAMMODE 1 is to disable LFR, but
3399 * notify_is_fast_roam_ini_feature_enabled 0/1 is to
3400 * enable/disable. So, we have to invert the value
3401 * to call sme_update_is_fast_roam_ini_feature_enabled.
3402 */
3403 if (CFG_LFR_FEATURE_ENABLED_MIN == roamMode)
3404 roamMode = CFG_LFR_FEATURE_ENABLED_MAX; /* Roam enable */
3405 else
3406 roamMode = CFG_LFR_FEATURE_ENABLED_MIN; /* Roam disable */
3407
3408 hdd_ctx->config->isFastRoamIniFeatureEnabled = roamMode;
3409 if (roamMode) {
3410 hdd_ctx->config->isRoamOffloadScanEnabled = roamMode;
3411 sme_update_roam_scan_offload_enabled(
3412 (tHalHandle)(hdd_ctx->hHal),
3413 hdd_ctx->config->isRoamOffloadScanEnabled);
3414 sme_update_is_fast_roam_ini_feature_enabled(
3415 hdd_ctx->hHal,
3416 adapter->sessionId,
3417 roamMode);
3418 } else {
3419 sme_update_is_fast_roam_ini_feature_enabled(
3420 hdd_ctx->hHal,
3421 adapter->sessionId,
3422 roamMode);
3423 hdd_ctx->config->isRoamOffloadScanEnabled = roamMode;
3424 sme_update_roam_scan_offload_enabled(
3425 (tHalHandle)(hdd_ctx->hHal),
3426 hdd_ctx->config->isRoamOffloadScanEnabled);
3427 }
3428
3429
3430exit:
3431 return ret;
3432}
3433
3434static int drv_cmd_get_roam_mode(hdd_adapter_t *adapter,
3435 hdd_context_t *hdd_ctx,
3436 uint8_t *command,
3437 uint8_t command_len,
3438 hdd_priv_data_t *priv_data)
3439{
3440 int ret = 0;
3441 bool roamMode = sme_get_is_lfr_feature_enabled(hdd_ctx->hHal);
3442 char extra[32];
3443 uint8_t len = 0;
3444
3445 /*
3446 * roamMode value shall be inverted because the sementics is different.
3447 */
3448 if (CFG_LFR_FEATURE_ENABLED_MIN == roamMode)
3449 roamMode = CFG_LFR_FEATURE_ENABLED_MAX;
3450 else
3451 roamMode = CFG_LFR_FEATURE_ENABLED_MIN;
3452
3453 len = scnprintf(extra, sizeof(extra), "%s %d", command, roamMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303454 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003455 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303456 QDF_TRACE(QDF_MODULE_ID_HDD,
3457 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003458 "%s: failed to copy data to user buffer",
3459 __func__);
3460 ret = -EFAULT;
3461 }
3462
3463 return ret;
3464}
3465
3466static int drv_cmd_set_roam_delta(hdd_adapter_t *adapter,
3467 hdd_context_t *hdd_ctx,
3468 uint8_t *command,
3469 uint8_t command_len,
3470 hdd_priv_data_t *priv_data)
3471{
3472 int ret = 0;
3473 uint8_t *value = command;
3474 uint8_t roamRssiDiff = CFG_ROAM_RSSI_DIFF_DEFAULT;
3475
3476 /* Move pointer to ahead of SETROAMDELTA<delimiter> */
3477 value = value + command_len + 1;
3478
3479 /* Convert the value from ascii to integer */
3480 ret = kstrtou8(value, 10, &roamRssiDiff);
3481 if (ret < 0) {
3482 /*
3483 * If the input value is greater than max value of datatype,
3484 * then also kstrtou8 fails
3485 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303486 QDF_TRACE(QDF_MODULE_ID_HDD,
3487 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003488 "%s: kstrtou8 failed range [%d - %d]",
3489 __func__, CFG_ROAM_RSSI_DIFF_MIN,
3490 CFG_ROAM_RSSI_DIFF_MAX);
3491 ret = -EINVAL;
3492 goto exit;
3493 }
3494
3495 if ((roamRssiDiff < CFG_ROAM_RSSI_DIFF_MIN) ||
3496 (roamRssiDiff > CFG_ROAM_RSSI_DIFF_MAX)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303497 QDF_TRACE(QDF_MODULE_ID_HDD,
3498 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003499 "Roam rssi diff value %d is out of range (Min: %d Max: %d)",
3500 roamRssiDiff,
3501 CFG_ROAM_RSSI_DIFF_MIN,
3502 CFG_ROAM_RSSI_DIFF_MAX);
3503 ret = -EINVAL;
3504 goto exit;
3505 }
3506
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303507 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003508 "%s: Received Command to Set roam rssi diff = %d",
3509 __func__, roamRssiDiff);
3510
3511 hdd_ctx->config->RoamRssiDiff = roamRssiDiff;
3512 sme_update_roam_rssi_diff(hdd_ctx->hHal,
3513 adapter->sessionId,
3514 roamRssiDiff);
3515
3516exit:
3517 return ret;
3518}
3519
3520static int drv_cmd_get_roam_delta(hdd_adapter_t *adapter,
3521 hdd_context_t *hdd_ctx,
3522 uint8_t *command,
3523 uint8_t command_len,
3524 hdd_priv_data_t *priv_data)
3525{
3526 int ret = 0;
3527 uint8_t roamRssiDiff =
3528 sme_get_roam_rssi_diff(hdd_ctx->hHal);
3529 char extra[32];
3530 uint8_t len = 0;
3531
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303532 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003533 TRACE_CODE_HDD_GETROAMDELTA_IOCTL,
3534 adapter->sessionId, roamRssiDiff));
3535
3536 len = scnprintf(extra, sizeof(extra), "%s %d",
3537 command, roamRssiDiff);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303538 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003539
3540 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303541 QDF_TRACE(QDF_MODULE_ID_HDD,
3542 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003543 "%s: failed to copy data to user buffer",
3544 __func__);
3545 ret = -EFAULT;
3546 }
3547
3548 return ret;
3549}
3550
3551static int drv_cmd_get_band(hdd_adapter_t *adapter,
3552 hdd_context_t *hdd_ctx,
3553 uint8_t *command,
3554 uint8_t command_len,
3555 hdd_priv_data_t *priv_data)
3556{
3557 int ret = 0;
3558 int band = -1;
3559 char extra[32];
3560 uint8_t len = 0;
3561
3562 hdd_get_band_helper(hdd_ctx, &band);
3563
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303564 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003565 TRACE_CODE_HDD_GETBAND_IOCTL,
3566 adapter->sessionId, band));
3567
3568 len = scnprintf(extra, sizeof(extra), "%s %d", command, band);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303569 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003570
3571 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303572 QDF_TRACE(QDF_MODULE_ID_HDD,
3573 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003574 "%s: failed to copy data to user buffer",
3575 __func__);
3576 ret = -EFAULT;
3577 }
3578
3579 return ret;
3580}
3581
3582static int drv_cmd_set_roam_scan_channels(hdd_adapter_t *adapter,
3583 hdd_context_t *hdd_ctx,
3584 uint8_t *command,
3585 uint8_t command_len,
3586 hdd_priv_data_t *priv_data)
3587{
3588 return hdd_parse_set_roam_scan_channels(adapter, command);
3589}
3590
3591static int drv_cmd_get_roam_scan_channels(hdd_adapter_t *adapter,
3592 hdd_context_t *hdd_ctx,
3593 uint8_t *command,
3594 uint8_t command_len,
3595 hdd_priv_data_t *priv_data)
3596{
3597 int ret = 0;
3598 uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
3599 uint8_t numChannels = 0;
3600 uint8_t j = 0;
3601 char extra[128] = { 0 };
3602 int len;
3603
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303604 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003605 sme_get_roam_scan_channel_list(hdd_ctx->hHal,
3606 ChannelList,
3607 &numChannels,
3608 adapter->sessionId)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303609 QDF_TRACE(QDF_MODULE_ID_HDD,
3610 QDF_TRACE_LEVEL_FATAL,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003611 "%s: failed to get roam scan channel list",
3612 __func__);
3613 ret = -EFAULT;
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_GETROAMSCANCHANNELS_IOCTL,
3619 adapter->sessionId, numChannels));
3620 /*
3621 * output channel list is of the format
3622 * [Number of roam scan channels][Channel1][Channel2]...
3623 * copy the number of channels in the 0th index
3624 */
3625 len = scnprintf(extra, sizeof(extra), "%s %d", command,
3626 numChannels);
3627 for (j = 0; (j < numChannels); j++)
3628 len += scnprintf(extra + len, sizeof(extra) - len,
3629 " %d", ChannelList[j]);
3630
Anurag Chouhan6d760662016-02-20 16:05:43 +05303631 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003632 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303633 QDF_TRACE(QDF_MODULE_ID_HDD,
3634 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003635 "%s: failed to copy data to user buffer",
3636 __func__);
3637 ret = -EFAULT;
3638 goto exit;
3639 }
3640
3641exit:
3642 return ret;
3643}
3644
3645static int drv_cmd_get_ccx_mode(hdd_adapter_t *adapter,
3646 hdd_context_t *hdd_ctx,
3647 uint8_t *command,
3648 uint8_t command_len,
3649 hdd_priv_data_t *priv_data)
3650{
3651 int ret = 0;
3652 bool eseMode = sme_get_is_ese_feature_enabled(hdd_ctx->hHal);
3653 char extra[32];
3654 uint8_t len = 0;
3655
3656 /*
3657 * Check if the features OKC/ESE/11R are supported simultaneously,
3658 * then this operation is not permitted (return FAILURE)
3659 */
3660 if (eseMode &&
3661 hdd_is_okc_mode_enabled(hdd_ctx) &&
3662 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303663 QDF_TRACE(QDF_MODULE_ID_HDD,
3664 QDF_TRACE_LEVEL_WARN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003665 "%s: OKC/ESE/11R are supported simultaneously hence this operation is not permitted!",
3666 __func__);
3667 ret = -EPERM;
3668 goto exit;
3669 }
3670
3671 len = scnprintf(extra, sizeof(extra), "%s %d",
3672 "GETCCXMODE", eseMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303673 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003674 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303675 QDF_TRACE(QDF_MODULE_ID_HDD,
3676 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003677 "%s: failed to copy data to user buffer",
3678 __func__);
3679 ret = -EFAULT;
3680 goto exit;
3681 }
3682
3683exit:
3684 return ret;
3685}
3686
3687static int drv_cmd_get_okc_mode(hdd_adapter_t *adapter,
3688 hdd_context_t *hdd_ctx,
3689 uint8_t *command,
3690 uint8_t command_len,
3691 hdd_priv_data_t *priv_data)
3692{
3693 int ret = 0;
3694 bool okcMode = hdd_is_okc_mode_enabled(hdd_ctx);
3695 char extra[32];
3696 uint8_t len = 0;
3697
3698 /*
3699 * Check if the features OKC/ESE/11R are supported simultaneously,
3700 * then this operation is not permitted (return FAILURE)
3701 */
3702 if (okcMode &&
3703 sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
3704 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303705 QDF_TRACE(QDF_MODULE_ID_HDD,
3706 QDF_TRACE_LEVEL_WARN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003707 "%s: OKC/ESE/11R are supported simultaneously hence this operation is not permitted!",
3708 __func__);
3709 ret = -EPERM;
3710 goto exit;
3711 }
3712
3713 len = scnprintf(extra, sizeof(extra), "%s %d",
3714 "GETOKCMODE", okcMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303715 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003716
3717 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303718 QDF_TRACE(QDF_MODULE_ID_HDD,
3719 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003720 "%s: failed to copy data to user buffer",
3721 __func__);
3722 ret = -EFAULT;
3723 goto exit;
3724 }
3725
3726exit:
3727 return ret;
3728}
3729
3730static int drv_cmd_get_fast_roam(hdd_adapter_t *adapter,
3731 hdd_context_t *hdd_ctx,
3732 uint8_t *command,
3733 uint8_t command_len,
3734 hdd_priv_data_t *priv_data)
3735{
3736 int ret = 0;
3737 bool lfrMode = sme_get_is_lfr_feature_enabled(hdd_ctx->hHal);
3738 char extra[32];
3739 uint8_t len = 0;
3740
3741 len = scnprintf(extra, sizeof(extra), "%s %d",
3742 "GETFASTROAM", lfrMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303743 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003744
3745 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303746 QDF_TRACE(QDF_MODULE_ID_HDD,
3747 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003748 "%s: failed to copy data to user buffer",
3749 __func__);
3750 ret = -EFAULT;
3751 }
3752
3753 return ret;
3754}
3755
3756static int drv_cmd_get_fast_transition(hdd_adapter_t *adapter,
3757 hdd_context_t *hdd_ctx,
3758 uint8_t *command,
3759 uint8_t command_len,
3760 hdd_priv_data_t *priv_data)
3761{
3762 int ret = 0;
3763 bool ft = sme_get_is_ft_feature_enabled(hdd_ctx->hHal);
3764 char extra[32];
3765 uint8_t len = 0;
3766
3767 len = scnprintf(extra, sizeof(extra), "%s %d",
3768 "GETFASTTRANSITION", ft);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303769 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003770
3771 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303772 QDF_TRACE(QDF_MODULE_ID_HDD,
3773 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003774 "%s: failed to copy data to user buffer",
3775 __func__);
3776 ret = -EFAULT;
3777 }
3778
3779 return ret;
3780}
3781
3782static int drv_cmd_set_roam_scan_channel_min_time(hdd_adapter_t *adapter,
3783 hdd_context_t *hdd_ctx,
3784 uint8_t *command,
3785 uint8_t command_len,
3786 hdd_priv_data_t *priv_data)
3787{
3788 int ret = 0;
3789 uint8_t *value = command;
3790 uint8_t minTime = CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_DEFAULT;
3791
3792 /* Move pointer to ahead of SETROAMSCANCHANNELMINTIME<delimiter> */
3793 value = value + command_len + 1;
3794
3795 /* Convert the value from ascii to integer */
3796 ret = kstrtou8(value, 10, &minTime);
3797 if (ret < 0) {
3798 /*
3799 * If the input value is greater than max value of datatype,
3800 * then also kstrtou8 fails
3801 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303802 QDF_TRACE(QDF_MODULE_ID_HDD,
3803 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003804 "%s: kstrtou8 failed range [%d - %d]",
3805 __func__,
3806 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN,
3807 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX);
3808 ret = -EINVAL;
3809 goto exit;
3810 }
3811
3812 if ((minTime < CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN) ||
3813 (minTime > CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303814 QDF_TRACE(QDF_MODULE_ID_HDD,
3815 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003816 "scan min channel time value %d is out of range (Min: %d Max: %d)",
3817 minTime,
3818 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN,
3819 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX);
3820 ret = -EINVAL;
3821 goto exit;
3822 }
3823
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303824 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003825 TRACE_CODE_HDD_SETROAMSCANCHANNELMINTIME_IOCTL,
3826 adapter->sessionId, minTime));
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303827 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003828 "%s: Received Command to change channel min time = %d",
3829 __func__, minTime);
3830
3831 hdd_ctx->config->nNeighborScanMinChanTime = minTime;
3832 sme_set_neighbor_scan_min_chan_time(hdd_ctx->hHal,
3833 minTime,
3834 adapter->sessionId);
3835
3836exit:
3837 return ret;
3838}
3839
3840static int drv_cmd_send_action_frame(hdd_adapter_t *adapter,
3841 hdd_context_t *hdd_ctx,
3842 uint8_t *command,
3843 uint8_t command_len,
3844 hdd_priv_data_t *priv_data)
3845{
3846 return hdd_parse_sendactionframe(adapter, command);
3847}
3848
3849static int drv_cmd_get_roam_scan_channel_min_time(hdd_adapter_t *adapter,
3850 hdd_context_t *hdd_ctx,
3851 uint8_t *command,
3852 uint8_t command_len,
3853 hdd_priv_data_t *priv_data)
3854{
3855 int ret = 0;
3856 uint16_t val = sme_get_neighbor_scan_min_chan_time(hdd_ctx->hHal,
3857 adapter->sessionId);
3858 char extra[32];
3859 uint8_t len = 0;
3860
3861 /* value is interms of msec */
3862 len = scnprintf(extra, sizeof(extra), "%s %d",
3863 "GETROAMSCANCHANNELMINTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303864 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003865
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303866 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003867 TRACE_CODE_HDD_GETROAMSCANCHANNELMINTIME_IOCTL,
3868 adapter->sessionId, val));
3869
3870 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303871 QDF_TRACE(QDF_MODULE_ID_HDD,
3872 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003873 "%s: failed to copy data to user buffer",
3874 __func__);
3875 ret = -EFAULT;
3876 }
3877
3878 return ret;
3879}
3880
3881static int drv_cmd_set_scan_channel_time(hdd_adapter_t *adapter,
3882 hdd_context_t *hdd_ctx,
3883 uint8_t *command,
3884 uint8_t command_len,
3885 hdd_priv_data_t *priv_data)
3886{
3887 int ret = 0;
3888 uint8_t *value = command;
3889 uint16_t maxTime = CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_DEFAULT;
3890
3891 /* Move pointer to ahead of SETSCANCHANNELTIME<delimiter> */
3892 value = value + command_len + 1;
3893
3894 /* Convert the value from ascii to integer */
3895 ret = kstrtou16(value, 10, &maxTime);
3896 if (ret < 0) {
3897 /*
3898 * If the input value is greater than max value of datatype,
3899 * then also kstrtou8 fails
3900 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303901 QDF_TRACE(QDF_MODULE_ID_HDD,
3902 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003903 "%s: kstrtou16 failed range [%d - %d]",
3904 __func__,
3905 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN,
3906 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX);
3907 ret = -EINVAL;
3908 goto exit;
3909 }
3910
3911 if ((maxTime < CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN) ||
3912 (maxTime > CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303913 QDF_TRACE(QDF_MODULE_ID_HDD,
3914 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003915 "lfr mode value %d is out of range (Min: %d Max: %d)",
3916 maxTime,
3917 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN,
3918 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX);
3919 ret = -EINVAL;
3920 goto exit;
3921 }
3922
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303923 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003924 "%s: Received Command to change channel max time = %d",
3925 __func__, maxTime);
3926
3927 hdd_ctx->config->nNeighborScanMaxChanTime = maxTime;
3928 sme_set_neighbor_scan_max_chan_time(hdd_ctx->hHal,
3929 adapter->sessionId,
3930 maxTime);
3931
3932exit:
3933 return ret;
3934}
3935
3936static int drv_cmd_get_scan_channel_time(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 uint16_t val = sme_get_neighbor_scan_max_chan_time(hdd_ctx->hHal,
3944 adapter->sessionId);
3945 char extra[32];
3946 uint8_t len = 0;
3947
3948 /* value is interms of msec */
3949 len = scnprintf(extra, sizeof(extra), "%s %d",
3950 "GETSCANCHANNELTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303951 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003952
3953 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303954 QDF_TRACE(QDF_MODULE_ID_HDD,
3955 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003956 "%s: failed to copy data to user buffer",
3957 __func__);
3958 ret = -EFAULT;
3959 }
3960
3961 return ret;
3962}
3963
3964static int drv_cmd_set_scan_home_time(hdd_adapter_t *adapter,
3965 hdd_context_t *hdd_ctx,
3966 uint8_t *command,
3967 uint8_t command_len,
3968 hdd_priv_data_t *priv_data)
3969{
3970 int ret = 0;
3971 uint8_t *value = command;
3972 uint16_t val = CFG_NEIGHBOR_SCAN_TIMER_PERIOD_DEFAULT;
3973
3974 /* Move pointer to ahead of SETSCANHOMETIME<delimiter> */
3975 value = value + command_len + 1;
3976
3977 /* Convert the value from ascii to integer */
3978 ret = kstrtou16(value, 10, &val);
3979 if (ret < 0) {
3980 /*
3981 * If the input value is greater than max value of datatype,
3982 * then also kstrtou8 fails
3983 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303984 QDF_TRACE(QDF_MODULE_ID_HDD,
3985 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003986 "%s: kstrtou16 failed range [%d - %d]",
3987 __func__,
3988 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN,
3989 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX);
3990 ret = -EINVAL;
3991 goto exit;
3992 }
3993
3994 if ((val < CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN) ||
3995 (val > CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303996 QDF_TRACE(QDF_MODULE_ID_HDD,
3997 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003998 "scan home time value %d is out of range (Min: %d Max: %d)",
3999 val,
4000 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN,
4001 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX);
4002 ret = -EINVAL;
4003 goto exit;
4004 }
4005
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304006 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004007 "%s: Received Command to change scan home time = %d",
4008 __func__, val);
4009
4010 hdd_ctx->config->nNeighborScanPeriod = val;
4011 sme_set_neighbor_scan_period(hdd_ctx->hHal,
4012 adapter->sessionId, val);
4013
4014exit:
4015 return ret;
4016}
4017
4018static int drv_cmd_get_scan_home_time(hdd_adapter_t *adapter,
4019 hdd_context_t *hdd_ctx,
4020 uint8_t *command,
4021 uint8_t command_len,
4022 hdd_priv_data_t *priv_data)
4023{
4024 int ret = 0;
4025 uint16_t val = sme_get_neighbor_scan_period(hdd_ctx->hHal,
4026 adapter->
4027 sessionId);
4028 char extra[32];
4029 uint8_t len = 0;
4030
4031 /* value is interms of msec */
4032 len = scnprintf(extra, sizeof(extra), "%s %d",
4033 "GETSCANHOMETIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304034 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004035
4036 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304037 QDF_TRACE(QDF_MODULE_ID_HDD,
4038 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004039 "%s: failed to copy data to user buffer",
4040 __func__);
4041 ret = -EFAULT;
4042 }
4043
4044 return ret;
4045}
4046
4047static int drv_cmd_set_roam_intra_band(hdd_adapter_t *adapter,
4048 hdd_context_t *hdd_ctx,
4049 uint8_t *command,
4050 uint8_t command_len,
4051 hdd_priv_data_t *priv_data)
4052{
4053 int ret = 0;
4054 uint8_t *value = command;
4055 uint8_t val = CFG_ROAM_INTRA_BAND_DEFAULT;
4056
4057 /* Move pointer to ahead of SETROAMINTRABAND<delimiter> */
4058 value = value + command_len + 1;
4059
4060 /* Convert the value from ascii to integer */
4061 ret = kstrtou8(value, 10, &val);
4062 if (ret < 0) {
4063 /*
4064 * If the input value is greater than max value of datatype,
4065 * then also kstrtou8 fails
4066 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304067 QDF_TRACE(QDF_MODULE_ID_HDD,
4068 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004069 "%s: kstrtou8 failed range [%d - %d]",
4070 __func__, CFG_ROAM_INTRA_BAND_MIN,
4071 CFG_ROAM_INTRA_BAND_MAX);
4072 ret = -EINVAL;
4073 goto exit;
4074 }
4075
4076 if ((val < CFG_ROAM_INTRA_BAND_MIN) ||
4077 (val > CFG_ROAM_INTRA_BAND_MAX)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304078 QDF_TRACE(QDF_MODULE_ID_HDD,
4079 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004080 "intra band mode value %d is out of range (Min: %d Max: %d)",
4081 val,
4082 CFG_ROAM_INTRA_BAND_MIN,
4083 CFG_ROAM_INTRA_BAND_MAX);
4084 ret = -EINVAL;
4085 goto exit;
4086 }
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304087 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004088 "%s: Received Command to change intra band = %d",
4089 __func__, val);
4090
4091 hdd_ctx->config->nRoamIntraBand = val;
4092 sme_set_roam_intra_band(hdd_ctx->hHal, val);
4093
4094exit:
4095 return ret;
4096}
4097
4098static int drv_cmd_get_roam_intra_band(hdd_adapter_t *adapter,
4099 hdd_context_t *hdd_ctx,
4100 uint8_t *command,
4101 uint8_t command_len,
4102 hdd_priv_data_t *priv_data)
4103{
4104 int ret = 0;
4105 uint16_t val = sme_get_roam_intra_band(hdd_ctx->hHal);
4106 char extra[32];
4107 uint8_t len = 0;
4108
4109 /* value is interms of msec */
4110 len = scnprintf(extra, sizeof(extra), "%s %d",
4111 "GETROAMINTRABAND", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304112 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004113 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304114 QDF_TRACE(QDF_MODULE_ID_HDD,
4115 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004116 "%s: failed to copy data to user buffer",
4117 __func__);
4118 ret = -EFAULT;
4119 }
4120
4121 return ret;
4122}
4123
4124static int drv_cmd_set_scan_n_probes(hdd_adapter_t *adapter,
4125 hdd_context_t *hdd_ctx,
4126 uint8_t *command,
4127 uint8_t command_len,
4128 hdd_priv_data_t *priv_data)
4129{
4130 int ret = 0;
4131 uint8_t *value = command;
4132 uint8_t nProbes = CFG_ROAM_SCAN_N_PROBES_DEFAULT;
4133
4134 /* Move pointer to ahead of SETSCANNPROBES<delimiter> */
4135 value = value + command_len + 1;
4136
4137 /* Convert the value from ascii to integer */
4138 ret = kstrtou8(value, 10, &nProbes);
4139 if (ret < 0) {
4140 /*
4141 * If the input value is greater than max value of datatype,
4142 * then also kstrtou8 fails
4143 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304144 QDF_TRACE(QDF_MODULE_ID_HDD,
4145 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004146 "%s: kstrtou8 failed range [%d - %d]",
4147 __func__, CFG_ROAM_SCAN_N_PROBES_MIN,
4148 CFG_ROAM_SCAN_N_PROBES_MAX);
4149 ret = -EINVAL;
4150 goto exit;
4151 }
4152
4153 if ((nProbes < CFG_ROAM_SCAN_N_PROBES_MIN) ||
4154 (nProbes > CFG_ROAM_SCAN_N_PROBES_MAX)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304155 QDF_TRACE(QDF_MODULE_ID_HDD,
4156 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004157 "NProbes value %d is out of range (Min: %d Max: %d)",
4158 nProbes,
4159 CFG_ROAM_SCAN_N_PROBES_MIN,
4160 CFG_ROAM_SCAN_N_PROBES_MAX);
4161 ret = -EINVAL;
4162 goto exit;
4163 }
4164
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304165 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004166 "%s: Received Command to Set nProbes = %d",
4167 __func__, nProbes);
4168
4169 hdd_ctx->config->nProbes = nProbes;
4170 sme_update_roam_scan_n_probes(hdd_ctx->hHal,
4171 adapter->sessionId, nProbes);
4172
4173exit:
4174 return ret;
4175}
4176
4177static int drv_cmd_get_scan_n_probes(hdd_adapter_t *adapter,
4178 hdd_context_t *hdd_ctx,
4179 uint8_t *command,
4180 uint8_t command_len,
4181 hdd_priv_data_t *priv_data)
4182{
4183 int ret = 0;
4184 uint8_t val = sme_get_roam_scan_n_probes(hdd_ctx->hHal);
4185 char extra[32];
4186 uint8_t len = 0;
4187
4188 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304189 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004190 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304191 QDF_TRACE(QDF_MODULE_ID_HDD,
4192 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004193 "%s: failed to copy data to user buffer",
4194 __func__);
4195 ret = -EFAULT;
4196 }
4197
4198 return ret;
4199}
4200
4201static int drv_cmd_set_scan_home_away_time(hdd_adapter_t *adapter,
4202 hdd_context_t *hdd_ctx,
4203 uint8_t *command,
4204 uint8_t command_len,
4205 hdd_priv_data_t *priv_data)
4206{
4207 int ret = 0;
4208 uint8_t *value = command;
4209 uint16_t homeAwayTime = CFG_ROAM_SCAN_HOME_AWAY_TIME_DEFAULT;
4210
4211 /* input value is in units of msec */
4212
4213 /* Move pointer to ahead of SETSCANHOMEAWAYTIME<delimiter> */
4214 value = value + command_len + 1;
4215
4216 /* Convert the value from ascii to integer */
4217 ret = kstrtou16(value, 10, &homeAwayTime);
4218 if (ret < 0) {
4219 /*
4220 * If the input value is greater than max value of datatype,
4221 * then also kstrtou8 fails
4222 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304223 QDF_TRACE(QDF_MODULE_ID_HDD,
4224 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004225 "%s: kstrtou8 failed range [%d - %d]",
4226 __func__,
4227 CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN,
4228 CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX);
4229 ret = -EINVAL;
4230 goto exit;
4231 }
4232
4233 if ((homeAwayTime < CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN) ||
4234 (homeAwayTime > CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304235 QDF_TRACE(QDF_MODULE_ID_HDD,
4236 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004237 "homeAwayTime value %d is out of range (Min: %d Max: %d)",
4238 homeAwayTime,
4239 CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN,
4240 CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX);
4241 ret = -EINVAL;
4242 goto exit;
4243 }
4244
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304245 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004246 "%s: Received Command to Set scan away time = %d",
4247 __func__, homeAwayTime);
4248
4249 if (hdd_ctx->config->nRoamScanHomeAwayTime !=
4250 homeAwayTime) {
4251 hdd_ctx->config->nRoamScanHomeAwayTime = homeAwayTime;
4252 sme_update_roam_scan_home_away_time(hdd_ctx->hHal,
4253 adapter->sessionId,
4254 homeAwayTime,
4255 true);
4256 }
4257
4258exit:
4259 return ret;
4260}
4261
4262static int drv_cmd_get_scan_home_away_time(hdd_adapter_t *adapter,
4263 hdd_context_t *hdd_ctx,
4264 uint8_t *command,
4265 uint8_t command_len,
4266 hdd_priv_data_t *priv_data)
4267{
4268 int ret = 0;
4269 uint16_t val = sme_get_roam_scan_home_away_time(hdd_ctx->hHal);
4270 char extra[32];
4271 uint8_t len = 0;
4272
4273 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304274 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004275
4276 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304277 QDF_TRACE(QDF_MODULE_ID_HDD,
4278 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004279 "%s: failed to copy data to user buffer",
4280 __func__);
4281 ret = -EFAULT;
4282 }
4283
4284 return ret;
4285}
4286
4287static int drv_cmd_reassoc(hdd_adapter_t *adapter,
4288 hdd_context_t *hdd_ctx,
4289 uint8_t *command,
4290 uint8_t command_len,
4291 hdd_priv_data_t *priv_data)
4292{
4293 return hdd_parse_reassoc(adapter, command);
4294}
4295
4296static int drv_cmd_set_wes_mode(hdd_adapter_t *adapter,
4297 hdd_context_t *hdd_ctx,
4298 uint8_t *command,
4299 uint8_t command_len,
4300 hdd_priv_data_t *priv_data)
4301{
4302 int ret = 0;
4303 uint8_t *value = command;
4304 uint8_t wesMode = CFG_ENABLE_WES_MODE_NAME_DEFAULT;
4305
4306 /* Move pointer to ahead of SETWESMODE<delimiter> */
4307 value = value + command_len + 1;
4308
4309 /* Convert the value from ascii to integer */
4310 ret = kstrtou8(value, 10, &wesMode);
4311 if (ret < 0) {
4312 /*
4313 * If the input value is greater than max value of datatype,
4314 * then also kstrtou8 fails
4315 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304316 QDF_TRACE(QDF_MODULE_ID_HDD,
4317 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004318 "%s: kstrtou8 failed range [%d - %d]",
4319 __func__,
4320 CFG_ENABLE_WES_MODE_NAME_MIN,
4321 CFG_ENABLE_WES_MODE_NAME_MAX);
4322 ret = -EINVAL;
4323 goto exit;
4324 }
4325
4326 if ((wesMode < CFG_ENABLE_WES_MODE_NAME_MIN) ||
4327 (wesMode > CFG_ENABLE_WES_MODE_NAME_MAX)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304328 QDF_TRACE(QDF_MODULE_ID_HDD,
4329 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004330 "WES Mode value %d is out of range (Min: %d Max: %d)",
4331 wesMode,
4332 CFG_ENABLE_WES_MODE_NAME_MIN,
4333 CFG_ENABLE_WES_MODE_NAME_MAX);
4334 ret = -EINVAL;
4335 goto exit;
4336 }
4337
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304338 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004339 "%s: Received Command to Set WES Mode rssi diff = %d",
4340 __func__, wesMode);
4341
4342 hdd_ctx->config->isWESModeEnabled = wesMode;
4343 sme_update_wes_mode(hdd_ctx->hHal, wesMode, adapter->sessionId);
4344
4345exit:
4346 return ret;
4347}
4348
4349static int drv_cmd_get_wes_mode(hdd_adapter_t *adapter,
4350 hdd_context_t *hdd_ctx,
4351 uint8_t *command,
4352 uint8_t command_len,
4353 hdd_priv_data_t *priv_data)
4354{
4355 int ret = 0;
4356 bool wesMode = sme_get_wes_mode(hdd_ctx->hHal);
4357 char extra[32];
4358 uint8_t len = 0;
4359
4360 len = scnprintf(extra, sizeof(extra), "%s %d", command, wesMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304361 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004362 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304363 QDF_TRACE(QDF_MODULE_ID_HDD,
4364 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004365 "%s: failed to copy data to user buffer",
4366 __func__);
4367 ret = -EFAULT;
4368 }
4369
4370 return ret;
4371}
4372
4373static int drv_cmd_set_opportunistic_rssi_diff(hdd_adapter_t *adapter,
4374 hdd_context_t *hdd_ctx,
4375 uint8_t *command,
4376 uint8_t command_len,
4377 hdd_priv_data_t *priv_data)
4378{
4379 int ret = 0;
4380 uint8_t *value = command;
4381 uint8_t nOpportunisticThresholdDiff =
4382 CFG_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF_DEFAULT;
4383
4384 /* Move pointer to ahead of SETOPPORTUNISTICRSSIDIFF<delimiter> */
4385 value = value + command_len + 1;
4386
4387 /* Convert the value from ascii to integer */
4388 ret = kstrtou8(value, 10, &nOpportunisticThresholdDiff);
4389 if (ret < 0) {
4390 /*
4391 * If the input value is greater than max value of datatype,
4392 * then also kstrtou8 fails
4393 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304394 QDF_TRACE(QDF_MODULE_ID_HDD,
4395 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004396 "%s: kstrtou8 failed.", __func__);
4397 ret = -EINVAL;
4398 goto exit;
4399 }
4400
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304401 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004402 "%s: Received Command to Set Opportunistic Threshold diff = %d",
4403 __func__, nOpportunisticThresholdDiff);
4404
4405 sme_set_roam_opportunistic_scan_threshold_diff(hdd_ctx->hHal,
4406 adapter->sessionId,
4407 nOpportunisticThresholdDiff);
4408
4409exit:
4410 return ret;
4411}
4412
4413static int drv_cmd_get_opportunistic_rssi_diff(hdd_adapter_t *adapter,
4414 hdd_context_t *hdd_ctx,
4415 uint8_t *command,
4416 uint8_t command_len,
4417 hdd_priv_data_t *priv_data)
4418{
4419 int ret = 0;
4420 int8_t val = sme_get_roam_opportunistic_scan_threshold_diff(
4421 hdd_ctx->hHal);
4422 char extra[32];
4423 uint8_t len = 0;
4424
4425 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304426 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004427 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304428 QDF_TRACE(QDF_MODULE_ID_HDD,
4429 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004430 "%s: failed to copy data to user buffer",
4431 __func__);
4432 ret = -EFAULT;
4433 }
4434
4435 return ret;
4436}
4437
4438static int drv_cmd_set_roam_rescan_rssi_diff(hdd_adapter_t *adapter,
4439 hdd_context_t *hdd_ctx,
4440 uint8_t *command,
4441 uint8_t command_len,
4442 hdd_priv_data_t *priv_data)
4443{
4444 int ret = 0;
4445 uint8_t *value = command;
4446 uint8_t nRoamRescanRssiDiff = CFG_ROAM_RESCAN_RSSI_DIFF_DEFAULT;
4447
4448 /* Move pointer to ahead of SETROAMRESCANRSSIDIFF<delimiter> */
4449 value = value + command_len + 1;
4450
4451 /* Convert the value from ascii to integer */
4452 ret = kstrtou8(value, 10, &nRoamRescanRssiDiff);
4453 if (ret < 0) {
4454 /*
4455 * If the input value is greater than max value of datatype,
4456 * then also kstrtou8 fails
4457 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304458 QDF_TRACE(QDF_MODULE_ID_HDD,
4459 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004460 "%s: kstrtou8 failed.", __func__);
4461 ret = -EINVAL;
4462 goto exit;
4463 }
4464
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304465 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004466 "%s: Received Command to Set Roam Rescan RSSI Diff = %d",
4467 __func__, nRoamRescanRssiDiff);
4468
4469 sme_set_roam_rescan_rssi_diff(hdd_ctx->hHal,
4470 adapter->sessionId,
4471 nRoamRescanRssiDiff);
4472
4473exit:
4474 return ret;
4475}
4476
4477static int drv_cmd_get_roam_rescan_rssi_diff(hdd_adapter_t *adapter,
4478 hdd_context_t *hdd_ctx,
4479 uint8_t *command,
4480 uint8_t command_len,
4481 hdd_priv_data_t *priv_data)
4482{
4483 int ret = 0;
4484 uint8_t val = sme_get_roam_rescan_rssi_diff(hdd_ctx->hHal);
4485 char extra[32];
4486 uint8_t len = 0;
4487
4488 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304489 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004490 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304491 QDF_TRACE(QDF_MODULE_ID_HDD,
4492 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004493 "%s: failed to copy data to user buffer",
4494 __func__);
4495 ret = -EFAULT;
4496 }
4497
4498 return ret;
4499}
4500
4501static int drv_cmd_set_fast_roam(hdd_adapter_t *adapter,
4502 hdd_context_t *hdd_ctx,
4503 uint8_t *command,
4504 uint8_t command_len,
4505 hdd_priv_data_t *priv_data)
4506{
4507 int ret = 0;
4508 uint8_t *value = command;
4509 uint8_t lfrMode = CFG_LFR_FEATURE_ENABLED_DEFAULT;
4510
4511 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4512 value = value + command_len + 1;
4513
4514 /* Convert the value from ascii to integer */
4515 ret = kstrtou8(value, 10, &lfrMode);
4516 if (ret < 0) {
4517 /*
4518 * If the input value is greater than max value of datatype,
4519 * then also kstrtou8 fails
4520 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304521 QDF_TRACE(QDF_MODULE_ID_HDD,
4522 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004523 "%s: kstrtou8 failed range [%d - %d]",
4524 __func__, CFG_LFR_FEATURE_ENABLED_MIN,
4525 CFG_LFR_FEATURE_ENABLED_MAX);
4526 ret = -EINVAL;
4527 goto exit;
4528 }
4529
4530 if ((lfrMode < CFG_LFR_FEATURE_ENABLED_MIN) ||
4531 (lfrMode > CFG_LFR_FEATURE_ENABLED_MAX)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304532 QDF_TRACE(QDF_MODULE_ID_HDD,
4533 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004534 "lfr mode value %d is out of range (Min: %d Max: %d)",
4535 lfrMode,
4536 CFG_LFR_FEATURE_ENABLED_MIN,
4537 CFG_LFR_FEATURE_ENABLED_MAX);
4538 ret = -EINVAL;
4539 goto exit;
4540 }
4541
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304542 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004543 "%s: Received Command to change lfr mode = %d",
4544 __func__, lfrMode);
4545
4546 hdd_ctx->config->isFastRoamIniFeatureEnabled = lfrMode;
4547 sme_update_is_fast_roam_ini_feature_enabled(hdd_ctx->hHal,
4548 adapter->
4549 sessionId,
4550 lfrMode);
4551
4552exit:
4553 return ret;
4554}
4555
4556static int drv_cmd_set_fast_transition(hdd_adapter_t *adapter,
4557 hdd_context_t *hdd_ctx,
4558 uint8_t *command,
4559 uint8_t command_len,
4560 hdd_priv_data_t *priv_data)
4561{
4562 int ret = 0;
4563 uint8_t *value = command;
4564 uint8_t ft = CFG_FAST_TRANSITION_ENABLED_NAME_DEFAULT;
4565
4566 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4567 value = value + command_len + 1;
4568
4569 /* Convert the value from ascii to integer */
4570 ret = kstrtou8(value, 10, &ft);
4571 if (ret < 0) {
4572 /*
4573 * If the input value is greater than max value of datatype,
4574 * then also kstrtou8 fails
4575 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304576 QDF_TRACE(QDF_MODULE_ID_HDD,
4577 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004578 "%s: kstrtou8 failed range [%d - %d]",
4579 __func__,
4580 CFG_FAST_TRANSITION_ENABLED_NAME_MIN,
4581 CFG_FAST_TRANSITION_ENABLED_NAME_MAX);
4582 ret = -EINVAL;
4583 goto exit;
4584 }
4585
4586 if ((ft < CFG_FAST_TRANSITION_ENABLED_NAME_MIN) ||
4587 (ft > CFG_FAST_TRANSITION_ENABLED_NAME_MAX)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304588 QDF_TRACE(QDF_MODULE_ID_HDD,
4589 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004590 "ft mode value %d is out of range (Min: %d Max: %d)",
4591 ft,
4592 CFG_FAST_TRANSITION_ENABLED_NAME_MIN,
4593 CFG_FAST_TRANSITION_ENABLED_NAME_MAX);
4594 ret = -EINVAL;
4595 goto exit;
4596 }
4597
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304598 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004599 "%s: Received Command to change ft mode = %d",
4600 __func__, ft);
4601
4602 hdd_ctx->config->isFastTransitionEnabled = ft;
4603 sme_update_fast_transition_enabled(hdd_ctx->hHal, ft);
4604
4605exit:
4606 return ret;
4607}
4608
4609#ifdef WLAN_FEATURE_ROAM_OFFLOAD
4610static void hdd_wma_send_fastreassoc_cmd(int sessionId, tSirMacAddr bssid,
4611 int channel)
4612{
4613 struct wma_roam_invoke_cmd *fastreassoc;
4614 cds_msg_t msg = {0};
4615
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304616 fastreassoc = qdf_mem_malloc(sizeof(*fastreassoc));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004617 if (NULL == fastreassoc) {
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05304618 hddLog(LOGE, FL("qdf_mem_malloc failed for fastreassoc"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004619 return;
4620 }
4621 fastreassoc->vdev_id = sessionId;
4622 fastreassoc->channel = channel;
4623 fastreassoc->bssid[0] = bssid[0];
4624 fastreassoc->bssid[1] = bssid[1];
4625 fastreassoc->bssid[2] = bssid[2];
4626 fastreassoc->bssid[3] = bssid[3];
4627 fastreassoc->bssid[4] = bssid[4];
4628 fastreassoc->bssid[5] = bssid[5];
4629
4630 msg.type = SIR_HAL_ROAM_INVOKE;
4631 msg.reserved = 0;
4632 msg.bodyptr = fastreassoc;
Anurag Chouhan6d760662016-02-20 16:05:43 +05304633 if (QDF_STATUS_SUCCESS != cds_mq_post_message(QDF_MODULE_ID_WMA,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004634 &msg)) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304635 qdf_mem_free(fastreassoc);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304636 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004637 FL("Not able to post ROAM_INVOKE_CMD message to WMA"));
4638 }
4639}
Varun Reddy Yeturubbbbe232016-02-29 14:01:57 -08004640#else
4641static inline void hdd_wma_send_fastreassoc_cmd(int sessionId,
4642 tSirMacAddr bssid, int channel)
4643{}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004644#endif
4645static int drv_cmd_fast_reassoc(hdd_adapter_t *adapter,
4646 hdd_context_t *hdd_ctx,
4647 uint8_t *command,
4648 uint8_t command_len,
4649 hdd_priv_data_t *priv_data)
4650{
4651 int ret = 0;
4652 uint8_t *value = command;
4653 uint8_t channel = 0;
4654 tSirMacAddr targetApBssid;
4655 uint32_t roamId = 0;
4656 tCsrRoamModifyProfileFields modProfileFields;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004657 tCsrHandoffRequest handoffInfo;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004658 hdd_station_ctx_t *pHddStaCtx;
4659
Krunal Sonibe766b02016-03-10 13:00:44 -08004660 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004661 hdd_warn("Unsupported in mode %s(%d)",
4662 hdd_device_mode_to_string(adapter->device_mode),
4663 adapter->device_mode);
4664 return -EINVAL;
4665 }
4666
4667 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
4668
4669 /* if not associated, no need to proceed with reassoc */
4670 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304671 QDF_TRACE(QDF_MODULE_ID_HDD,
4672 QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004673 "%s:Not associated!", __func__);
4674 ret = -EINVAL;
4675 goto exit;
4676 }
4677
4678 ret = hdd_parse_reassoc_command_v1_data(value, targetApBssid,
4679 &channel);
4680 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304681 QDF_TRACE(QDF_MODULE_ID_HDD,
4682 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004683 "%s: Failed to parse reassoc command data",
4684 __func__);
4685 goto exit;
4686 }
4687
4688 /*
4689 * if the target bssid is same as currently associated AP,
4690 * issue reassoc to same AP
4691 */
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304692 if (true != qdf_mem_cmp(targetApBssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004693 pHddStaCtx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05304694 QDF_MAC_ADDR_SIZE)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004695 /* Reassoc to same AP, only supported for Open Security*/
4696 if ((pHddStaCtx->conn_info.ucEncryptionType ||
4697 pHddStaCtx->conn_info.mcEncryptionType)) {
4698 hddLog(LOGE,
4699 FL("Reassoc to same AP, only supported for Open Security"));
4700 return -ENOTSUPP;
4701 }
4702 hddLog(LOG1,
4703 FL("Reassoc BSSID is same as currently associated AP bssid"));
4704 sme_get_modify_profile_fields(hdd_ctx->hHal, adapter->sessionId,
4705 &modProfileFields);
4706 sme_roam_reassoc(hdd_ctx->hHal, adapter->sessionId,
4707 NULL, modProfileFields, &roamId, 1);
4708 return 0;
4709 }
4710
4711 /* Check channel number is a valid channel number */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304712 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004713 wlan_hdd_validate_operation_channel(adapter, channel)) {
4714 hddLog(LOGE, FL("Invalid Channel [%d]"), channel);
4715 return -EINVAL;
4716 }
Varun Reddy Yeturud351a6c2016-03-16 14:01:00 -07004717 if (roaming_offload_enabled(hdd_ctx)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004718 hdd_wma_send_fastreassoc_cmd((int)adapter->sessionId,
4719 targetApBssid, (int)channel);
4720 goto exit;
4721 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004722 /* Proceed with reassoc */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004723 handoffInfo.channel = channel;
4724 handoffInfo.src = FASTREASSOC;
Varun Reddy Yeturua66f9c52016-02-17 09:58:40 -08004725 qdf_mem_copy(handoffInfo.bssid.bytes, targetApBssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004726 sizeof(tSirMacAddr));
4727 sme_handoff_request(hdd_ctx->hHal, adapter->sessionId,
4728 &handoffInfo);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004729exit:
4730 return ret;
4731}
4732
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004733static int drv_cmd_set_roam_scan_control(hdd_adapter_t *adapter,
4734 hdd_context_t *hdd_ctx,
4735 uint8_t *command,
4736 uint8_t command_len,
4737 hdd_priv_data_t *priv_data)
4738{
4739 int ret = 0;
4740 uint8_t *value = command;
4741 uint8_t roamScanControl = 0;
4742
4743 /* Move pointer to ahead of SETROAMSCANCONTROL<delimiter> */
4744 value = value + command_len + 1;
4745
4746 /* Convert the value from ascii to integer */
4747 ret = kstrtou8(value, 10, &roamScanControl);
4748 if (ret < 0) {
4749 /*
4750 * If the input value is greater than max value of datatype,
4751 * then also kstrtou8 fails
4752 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304753 QDF_TRACE(QDF_MODULE_ID_HDD,
4754 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004755 "%s: kstrtou8 failed ", __func__);
4756 ret = -EINVAL;
4757 goto exit;
4758 }
4759
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304760 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004761 "%s: Received Command to Set roam scan control = %d",
4762 __func__, roamScanControl);
4763
4764 if (0 != roamScanControl) {
4765 ret = 0; /* return success but ignore param value "true" */
4766 goto exit;
4767 }
4768
4769 sme_set_roam_scan_control(hdd_ctx->hHal,
4770 adapter->sessionId,
4771 roamScanControl);
4772
4773exit:
4774 return ret;
4775}
4776
4777static int drv_cmd_set_okc_mode(hdd_adapter_t *adapter,
4778 hdd_context_t *hdd_ctx,
4779 uint8_t *command,
4780 uint8_t command_len,
4781 hdd_priv_data_t *priv_data)
4782{
4783 int ret = 0;
4784 uint8_t *value = command;
4785 uint8_t okcMode = CFG_OKC_FEATURE_ENABLED_DEFAULT;
4786
4787 /*
4788 * Check if the features OKC/ESE/11R are supported simultaneously,
4789 * then this operation is not permitted (return FAILURE)
4790 */
4791 if (sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
4792 hdd_is_okc_mode_enabled(hdd_ctx) &&
4793 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304794 QDF_TRACE(QDF_MODULE_ID_HDD,
4795 QDF_TRACE_LEVEL_WARN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004796 "%s: OKC/ESE/11R are supported simultaneously hence this operation is not permitted!",
4797 __func__);
4798 ret = -EPERM;
4799 goto exit;
4800 }
4801
4802 /* Move pointer to ahead of SETOKCMODE<delimiter> */
4803 value = value + command_len + 1;
4804
4805 /* Convert the value from ascii to integer */
4806 ret = kstrtou8(value, 10, &okcMode);
4807 if (ret < 0) {
4808 /*
4809 * If the input value is greater than max value of datatype,
4810 * then also kstrtou8 fails
4811 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304812 QDF_TRACE(QDF_MODULE_ID_HDD,
4813 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004814 "%s: kstrtou8 failed range [%d - %d]",
4815 __func__, CFG_OKC_FEATURE_ENABLED_MIN,
4816 CFG_OKC_FEATURE_ENABLED_MAX);
4817 ret = -EINVAL;
4818 goto exit;
4819 }
4820
4821 if ((okcMode < CFG_OKC_FEATURE_ENABLED_MIN) ||
4822 (okcMode > CFG_OKC_FEATURE_ENABLED_MAX)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304823 QDF_TRACE(QDF_MODULE_ID_HDD,
4824 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004825 "Okc mode value %d is out of range (Min: %d Max: %d)",
4826 okcMode,
4827 CFG_OKC_FEATURE_ENABLED_MIN,
4828 CFG_OKC_FEATURE_ENABLED_MAX);
4829 ret = -EINVAL;
4830 goto exit;
4831 }
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304832 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004833 "%s: Received Command to change okc mode = %d",
4834 __func__, okcMode);
4835
4836 hdd_ctx->config->isOkcIniFeatureEnabled = okcMode;
4837
4838exit:
4839 return ret;
4840}
4841
4842static int drv_cmd_get_roam_scan_control(hdd_adapter_t *adapter,
4843 hdd_context_t *hdd_ctx,
4844 uint8_t *command,
4845 uint8_t command_len,
4846 hdd_priv_data_t *priv_data)
4847{
4848 int ret = 0;
4849 bool roamScanControl = sme_get_roam_scan_control(hdd_ctx->hHal);
4850 char extra[32];
4851 uint8_t len = 0;
4852
4853 len = scnprintf(extra, sizeof(extra), "%s %d",
4854 command, roamScanControl);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304855 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004856 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304857 QDF_TRACE(QDF_MODULE_ID_HDD,
4858 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004859 "%s: failed to copy data to user buffer",
4860 __func__);
4861 ret = -EFAULT;
4862 }
4863
4864 return ret;
4865}
4866
4867static int drv_cmd_bt_coex_mode(hdd_adapter_t *adapter,
4868 hdd_context_t *hdd_ctx,
4869 uint8_t *command,
4870 uint8_t command_len,
4871 hdd_priv_data_t *priv_data)
4872{
4873 int ret = 0;
4874 char *bcMode;
4875
4876 bcMode = command + 11;
4877 if ('1' == *bcMode) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304878 QDF_TRACE(QDF_MODULE_ID_HDD,
4879 QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004880 FL("BTCOEXMODE %d"), *bcMode);
4881 hdd_ctx->btCoexModeSet = true;
4882 ret = wlan_hdd_scan_abort(adapter);
4883 if (ret < 0) {
4884 hddLog(LOGE,
4885 FL("Failed to abort existing scan status:%d"), ret);
4886 }
4887 } else if ('2' == *bcMode) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304888 QDF_TRACE(QDF_MODULE_ID_HDD,
4889 QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004890 FL("BTCOEXMODE %d"), *bcMode);
4891 hdd_ctx->btCoexModeSet = false;
4892 }
4893
4894 return ret;
4895}
4896
4897static int drv_cmd_scan_active(hdd_adapter_t *adapter,
4898 hdd_context_t *hdd_ctx,
4899 uint8_t *command,
4900 uint8_t command_len,
4901 hdd_priv_data_t *priv_data)
4902{
4903 hdd_ctx->ioctl_scan_mode = eSIR_ACTIVE_SCAN;
4904 return 0;
4905}
4906
4907static int drv_cmd_scan_passive(hdd_adapter_t *adapter,
4908 hdd_context_t *hdd_ctx,
4909 uint8_t *command,
4910 uint8_t command_len,
4911 hdd_priv_data_t *priv_data)
4912{
4913 hdd_ctx->ioctl_scan_mode = eSIR_PASSIVE_SCAN;
4914 return 0;
4915}
4916
4917static int drv_cmd_get_dwell_time(hdd_adapter_t *adapter,
4918 hdd_context_t *hdd_ctx,
4919 uint8_t *command,
4920 uint8_t command_len,
4921 hdd_priv_data_t *priv_data)
4922{
4923 int ret = 0;
4924 struct hdd_config *pCfg =
4925 (WLAN_HDD_GET_CTX(adapter))->config;
4926 char extra[32];
4927 uint8_t len = 0;
4928
4929 memset(extra, 0, sizeof(extra));
4930 ret = hdd_get_dwell_time(pCfg, command, extra, sizeof(extra), &len);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304931 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004932 if (ret != 0 || copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304933 QDF_TRACE(QDF_MODULE_ID_HDD,
4934 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004935 "%s: failed to copy data to user buffer",
4936 __func__);
4937 ret = -EFAULT;
4938 goto exit;
4939 }
4940 ret = len;
4941exit:
4942 return ret;
4943}
4944
4945static int drv_cmd_set_dwell_time(hdd_adapter_t *adapter,
4946 hdd_context_t *hdd_ctx,
4947 uint8_t *command,
4948 uint8_t command_len,
4949 hdd_priv_data_t *priv_data)
4950{
4951 return hdd_set_dwell_time(adapter, command);
4952}
4953
4954static int drv_cmd_miracast(hdd_adapter_t *adapter,
4955 hdd_context_t *hdd_ctx,
4956 uint8_t *command,
4957 uint8_t command_len,
4958 hdd_priv_data_t *priv_data)
4959{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304960 QDF_STATUS ret_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004961 int ret = 0;
4962 tHalHandle hHal;
4963 uint8_t filterType = 0;
4964 hdd_context_t *pHddCtx = NULL;
4965 uint8_t *value;
4966
4967 pHddCtx = WLAN_HDD_GET_CTX(adapter);
4968 if (0 != wlan_hdd_validate_context(pHddCtx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304969 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004970 "%s pHddCtx is not valid, Unable to set miracast mode",
4971 __func__);
4972 return -EINVAL;
4973 }
4974
4975 hHal = pHddCtx->hHal;
4976 value = command + 9;
4977
4978 /* Convert the value from ascii to integer */
4979 ret = kstrtou8(value, 10, &filterType);
4980 if (ret < 0) {
4981 /*
4982 * If the input value is greater than max value of datatype,
4983 * then also kstrtou8 fails
4984 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304985 QDF_TRACE(QDF_MODULE_ID_HDD,
4986 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004987 "%s: kstrtou8 failed range ",
4988 __func__);
4989 ret = -EINVAL;
4990 goto exit;
4991 }
4992 if ((filterType < WLAN_HDD_DRIVER_MIRACAST_CFG_MIN_VAL)
4993 || (filterType >
4994 WLAN_HDD_DRIVER_MIRACAST_CFG_MAX_VAL)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304995 QDF_TRACE(QDF_MODULE_ID_HDD,
4996 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004997 "%s: Accepted Values are 0 to 2. 0-Disabled, 1-Source, 2-Sink ",
4998 __func__);
4999 ret = -EINVAL;
5000 goto exit;
5001 }
5002 /* Filtertype value should be either 0-Disabled, 1-Source, 2-sink */
5003 pHddCtx->miracast_value = filterType;
5004
5005 ret_status = sme_set_miracast(hHal, filterType);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305006 if (QDF_STATUS_SUCCESS != ret_status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005007 hddLog(LOGE, "Failed to set miracast");
5008 return -EBUSY;
5009 }
5010
Tushnim Bhattacharyyaca50b322015-12-28 17:14:36 -08005011 if (cds_is_mcc_in_24G())
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005012 return cds_set_mas(adapter, filterType);
5013
5014exit:
5015 return ret;
5016}
5017
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005018/* Function header is left blank intentionally */
5019static int hdd_parse_set_ibss_oui_data_command(uint8_t *command, uint8_t *ie,
5020 int32_t *oui_length, int32_t limit)
5021{
5022 uint8_t len;
5023 uint8_t data;
5024
5025 while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) {
5026 command++;
5027 limit--;
5028 }
5029
5030 len = 2;
5031
5032 while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) &&
5033 (limit > 1)) {
5034 sscanf(command, "%02x", (unsigned int *)&data);
5035 ie[len++] = data;
5036 command += 2;
5037 limit -= 2;
5038 }
5039
5040 *oui_length = len - 2;
5041
5042 while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) {
5043 command++;
5044 limit--;
5045 }
5046
5047 while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) &&
5048 (limit > 1)) {
5049 sscanf(command, "%02x", (unsigned int *)&data);
5050 ie[len++] = data;
5051 command += 2;
5052 limit -= 2;
5053 }
5054
5055 ie[0] = IE_EID_VENDOR;
5056 ie[1] = len - 2;
5057
5058 return len;
5059}
5060
5061/**
5062 * drv_cmd_set_ibss_beacon_oui_data() - set ibss oui data command
5063 * @adapter: Pointer to adapter
5064 * @hdd_ctx: Pointer to HDD context
5065 * @command: Pointer to command string
5066 * @command_len : Command length
5067 * @priv_data : Pointer to priv data
5068 *
5069 * Return:
5070 * int status code
5071 */
5072static int drv_cmd_set_ibss_beacon_oui_data(hdd_adapter_t *adapter,
5073 hdd_context_t *hdd_ctx,
5074 uint8_t *command,
5075 uint8_t command_len,
5076 hdd_priv_data_t *priv_data)
5077{
5078 int i = 0;
5079 int status;
5080 int ret = 0;
5081 uint8_t *ibss_ie;
5082 int32_t oui_length = 0;
5083 uint32_t ibss_ie_length;
5084 uint8_t *value = command;
5085 tSirModifyIE ibssModifyIE;
5086 tCsrRoamProfile *pRoamProfile;
5087 hdd_wext_state_t *pWextState;
5088
5089
Krunal Sonibe766b02016-03-10 13:00:44 -08005090 if (QDF_IBSS_MODE != adapter->device_mode) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005091 hddLog(LOG1, FL("Device_mode %s(%d) not IBSS"),
5092 hdd_device_mode_to_string(adapter->device_mode),
5093 adapter->device_mode);
5094 return ret;
5095 }
5096
5097 pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(adapter);
5098
5099 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
5100 "%s: received command %s", __func__,
5101 ((char *)value));
5102
5103
5104 /* validate argument of command */
5105 if (strlen(value) <= command_len) {
5106 hddLog(LOGE,
5107 FL("No arguements in command length %zu"),
5108 strlen(value));
5109 ret = -EFAULT;
5110 goto exit;
5111 }
5112
5113 /* moving to arguments of commands */
5114 value = value + command_len;
5115 command_len = strlen(value);
5116
5117 /* oui_data can't be less than 3 bytes */
5118 if (command_len < (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) {
5119 hddLog(LOGE,
5120 FL("Invalid SETIBSSBEACONOUIDATA command length %d"),
5121 command_len);
5122 ret = -EFAULT;
5123 goto exit;
5124 }
5125
5126 ibss_ie = qdf_mem_malloc(command_len);
5127 if (!ibss_ie) {
5128 hddLog(LOGE,
5129 FL("Could not allocate memory for command length %d"),
5130 command_len);
5131 ret = -ENOMEM;
5132 goto exit;
5133 }
5134 qdf_mem_zero(ibss_ie, command_len);
5135
5136 ibss_ie_length = hdd_parse_set_ibss_oui_data_command(value, ibss_ie,
5137 &oui_length,
5138 command_len);
5139 if (ibss_ie_length <= (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) {
5140 hddLog(LOGE, FL("Could not parse command %s return length %d"),
5141 value, ibss_ie_length);
5142 ret = -EFAULT;
5143 qdf_mem_free(ibss_ie);
5144 goto exit;
5145 }
5146
5147 pRoamProfile = &pWextState->roamProfile;
5148
5149 qdf_copy_macaddr(&ibssModifyIE.bssid,
5150 pRoamProfile->BSSIDs.bssid);
5151
5152 ibssModifyIE.smeSessionId = adapter->sessionId;
5153 ibssModifyIE.notify = true;
5154 ibssModifyIE.ieID = IE_EID_VENDOR;
5155 ibssModifyIE.ieIDLen = ibss_ie_length;
5156 ibssModifyIE.ieBufferlength = ibss_ie_length;
5157 ibssModifyIE.pIEBuffer = ibss_ie;
5158 ibssModifyIE.oui_length = oui_length;
5159
5160 hddLog(LOGW, FL("ibss_ie length %d oui_length %d ibss_ie:"),
5161 ibss_ie_length, oui_length);
5162 while (i < ibssModifyIE.ieBufferlength)
5163 hddLog(LOGW, FL("0x%x"), ibss_ie[i++]);
5164
5165 /* Probe Bcn modification */
5166 sme_modify_add_ie(WLAN_HDD_GET_HAL_CTX(adapter),
5167 &ibssModifyIE, eUPDATE_IE_PROBE_BCN);
5168
5169 /* Populating probe resp frame */
5170 sme_modify_add_ie(WLAN_HDD_GET_HAL_CTX(adapter),
5171 &ibssModifyIE, eUPDATE_IE_PROBE_RESP);
5172
5173 qdf_mem_free(ibss_ie);
5174
5175 status = sme_send_cesium_enable_ind((tHalHandle)(hdd_ctx->hHal),
5176 adapter->sessionId);
5177 if (QDF_STATUS_SUCCESS != status) {
5178 QDF_TRACE(QDF_MODULE_ID_HDD,
5179 QDF_TRACE_LEVEL_ERROR,
5180 "Could not send cesium enable indication %d",
5181 status);
5182 ret = -EINVAL;
5183 goto exit;
5184 }
5185
5186exit:
5187 return ret;
5188}
5189
5190static int drv_cmd_set_rmc_enable(hdd_adapter_t *adapter,
5191 hdd_context_t *hdd_ctx,
5192 uint8_t *command,
5193 uint8_t command_len,
5194 hdd_priv_data_t *priv_data)
5195{
5196 int ret = 0;
5197 uint8_t *value = command;
5198 uint8_t ucRmcEnable = 0;
5199 int status;
5200
Krunal Sonibe766b02016-03-10 13:00:44 -08005201 if ((QDF_IBSS_MODE != adapter->device_mode) &&
5202 (QDF_SAP_MODE != adapter->device_mode)) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005203 hddLog(LOGE,
5204 "Received SETRMCENABLE cmd in invalid mode %s(%d)",
5205 hdd_device_mode_to_string(adapter->device_mode),
5206 adapter->device_mode);
5207 hddLog(LOGE,
5208 "SETRMCENABLE cmd is allowed only in IBSS/SOFTAP mode");
5209 ret = -EINVAL;
5210 goto exit;
5211 }
5212
5213 status = hdd_parse_setrmcenable_command(value, &ucRmcEnable);
5214 if (status) {
5215 QDF_TRACE(QDF_MODULE_ID_HDD,
5216 QDF_TRACE_LEVEL_ERROR,
5217 "Invalid SETRMCENABLE command ");
5218 ret = -EINVAL;
5219 goto exit;
5220 }
5221
5222 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
5223 "%s: ucRmcEnable %d ", __func__, ucRmcEnable);
5224
5225 if (true == ucRmcEnable) {
5226 status = sme_enable_rmc((tHalHandle)
5227 (hdd_ctx->hHal),
5228 adapter->sessionId);
5229 } else if (false == ucRmcEnable) {
5230 status = sme_disable_rmc((tHalHandle)
5231 (hdd_ctx->hHal),
5232 adapter->sessionId);
5233 } else {
5234 QDF_TRACE(QDF_MODULE_ID_HDD,
5235 QDF_TRACE_LEVEL_ERROR,
5236 "Invalid SETRMCENABLE command %d",
5237 ucRmcEnable);
5238 ret = -EINVAL;
5239 goto exit;
5240 }
5241
5242 if (QDF_STATUS_SUCCESS != status) {
5243 QDF_TRACE(QDF_MODULE_ID_HDD,
5244 QDF_TRACE_LEVEL_ERROR,
5245 "%s: SETRMC %d failed status %d",
5246 __func__, ucRmcEnable, status);
5247 ret = -EINVAL;
5248 goto exit;
5249 }
5250
5251exit:
5252 return ret;
5253}
5254
5255static int drv_cmd_set_rmc_action_period(hdd_adapter_t *adapter,
5256 hdd_context_t *hdd_ctx,
5257 uint8_t *command,
5258 uint8_t command_len,
5259 hdd_priv_data_t *priv_data)
5260{
5261 int ret = 0;
5262 uint8_t *value = command;
5263 uint32_t uActionPeriod = 0;
5264 int status;
5265
Krunal Sonibe766b02016-03-10 13:00:44 -08005266 if ((QDF_IBSS_MODE != adapter->device_mode) &&
5267 (QDF_SAP_MODE != adapter->device_mode)) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005268 hddLog(LOGE, "Received SETRMC cmd in invalid mode %s(%d)",
5269 hdd_device_mode_to_string(adapter->device_mode),
5270 adapter->device_mode);
5271 hddLog(LOGE,
5272 "SETRMC cmd is allowed only in IBSS/SOFTAP mode");
5273 ret = -EINVAL;
5274 goto exit;
5275 }
5276
5277 status = hdd_parse_setrmcactionperiod_command(value, &uActionPeriod);
5278 if (status) {
5279 QDF_TRACE(QDF_MODULE_ID_HDD,
5280 QDF_TRACE_LEVEL_ERROR,
5281 "Invalid SETRMCACTIONPERIOD command ");
5282 ret = -EINVAL;
5283 goto exit;
5284 }
5285
5286 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
5287 "%s: uActionPeriod %d ", __func__,
5288 uActionPeriod);
5289
5290 if (sme_cfg_set_int(hdd_ctx->hHal,
5291 WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY,
5292 uActionPeriod)) {
5293 QDF_TRACE(QDF_MODULE_ID_HDD,
5294 QDF_TRACE_LEVEL_ERROR,
5295 "%s: Could not set SETRMCACTIONPERIOD %d",
5296 __func__, uActionPeriod);
5297 ret = -EINVAL;
5298 goto exit;
5299 }
5300
5301 status = sme_send_rmc_action_period((tHalHandle)(hdd_ctx->hHal),
5302 adapter->sessionId);
5303 if (QDF_STATUS_SUCCESS != status) {
5304 QDF_TRACE(QDF_MODULE_ID_HDD,
5305 QDF_TRACE_LEVEL_ERROR,
5306 "Could not send cesium enable indication %d",
5307 status);
5308 ret = -EINVAL;
5309 goto exit;
5310 }
5311
5312exit:
5313 return ret;
5314}
5315
5316static int drv_cmd_get_ibss_peer_info_all(hdd_adapter_t *adapter,
5317 hdd_context_t *hdd_ctx,
5318 uint8_t *command,
5319 uint8_t command_len,
5320 hdd_priv_data_t *priv_data)
5321{
5322 int ret = 0;
5323 int status = QDF_STATUS_SUCCESS;
5324 hdd_station_ctx_t *pHddStaCtx = NULL;
5325 char *extra = NULL;
5326 int idx = 0;
5327 int length = 0;
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005328 uint8_t mac_addr[QDF_MAC_ADDR_SIZE];
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005329 uint32_t numOfBytestoPrint = 0;
5330
Krunal Sonibe766b02016-03-10 13:00:44 -08005331 if (QDF_IBSS_MODE != adapter->device_mode) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005332 hdd_warn("Unsupported in mode %s(%d)",
5333 hdd_device_mode_to_string(adapter->device_mode),
5334 adapter->device_mode);
5335 return -EINVAL;
5336 }
5337
5338 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5339 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
5340 "%s: Received GETIBSSPEERINFOALL Command",
5341 __func__);
5342
5343 /* Handle the command */
5344 status = hdd_cfg80211_get_ibss_peer_info_all(adapter);
5345 if (QDF_STATUS_SUCCESS == status) {
5346 /*
5347 * The variable extra needed to be allocated on the heap since
5348 * amount of memory required to copy the data for 32 devices
5349 * exceeds the size of 1024 bytes of default stack size. On
5350 * 64 bit devices, the default max stack size of 2048 bytes
5351 */
5352 extra = kmalloc(WLAN_MAX_BUF_SIZE, GFP_KERNEL);
5353
5354 if (NULL == extra) {
5355 QDF_TRACE(QDF_MODULE_ID_HDD,
5356 QDF_TRACE_LEVEL_ERROR,
5357 "%s:kmalloc failed",
5358 __func__);
5359 ret = -EINVAL;
5360 goto exit;
5361 }
5362
5363 /* Copy number of stations */
5364 length = scnprintf(extra, WLAN_MAX_BUF_SIZE, "%d ",
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005365 pHddStaCtx->ibss_peer_info.numPeers);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005366 numOfBytestoPrint = length;
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005367 for (idx = 0; idx < pHddStaCtx->ibss_peer_info.numPeers;
5368 idx++) {
5369 int8_t rssi;
5370 uint32_t tx_rate;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005371
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005372 qdf_mem_copy(mac_addr,
5373 pHddStaCtx->ibss_peer_info.peerInfoParams[idx].
5374 mac_addr, sizeof(mac_addr));
5375
5376 tx_rate =
5377 pHddStaCtx->ibss_peer_info.peerInfoParams[idx].
5378 txRate;
5379 rssi = pHddStaCtx->ibss_peer_info.peerInfoParams[idx].
5380 rssi;
5381
5382 length += scnprintf((extra + length),
5383 WLAN_MAX_BUF_SIZE - length,
5384 "%02x:%02x:%02x:%02x:%02x:%02x %d %d ",
5385 mac_addr[0], mac_addr[1], mac_addr[2],
5386 mac_addr[3], mac_addr[4], mac_addr[5],
5387 tx_rate, rssi);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005388 /*
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005389 * cdf_trace_msg has limitation of 512 bytes for the
5390 * print buffer. Hence printing the data in two chunks.
5391 * The first chunk will have the data for 16 devices
5392 * and the second chunk will have the rest.
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005393 */
5394 if (idx < NUM_OF_STA_DATA_TO_PRINT)
5395 numOfBytestoPrint = length;
5396 }
5397
5398 /*
5399 * Copy the data back into buffer, if the data to copy is
5400 * more than 512 bytes than we will split the data and do
5401 * it in two shots
5402 */
5403 if (copy_to_user(priv_data->buf, extra, numOfBytestoPrint)) {
5404 QDF_TRACE(QDF_MODULE_ID_HDD,
5405 QDF_TRACE_LEVEL_ERROR,
5406 "%s: Copy into user data buffer failed ",
5407 __func__);
5408 ret = -EFAULT;
5409 goto exit;
5410 }
5411
5412 priv_data->buf[numOfBytestoPrint] = '\0';
5413 QDF_TRACE(QDF_MODULE_ID_HDD,
5414 QDF_TRACE_LEVEL_INFO_MED, "%s",
5415 priv_data->buf);
5416
5417 if (length > numOfBytestoPrint) {
5418 if (copy_to_user
5419 (priv_data->buf + numOfBytestoPrint,
5420 extra + numOfBytestoPrint,
5421 length - numOfBytestoPrint + 1)) {
5422 QDF_TRACE(QDF_MODULE_ID_HDD,
5423 QDF_TRACE_LEVEL_ERROR,
5424 "%s: Copy into user data buffer failed ",
5425 __func__);
5426 ret = -EFAULT;
5427 goto exit;
5428 }
5429 QDF_TRACE(QDF_MODULE_ID_HDD,
5430 QDF_TRACE_LEVEL_INFO_MED,
5431 "%s",
5432 &priv_data->buf[numOfBytestoPrint]);
5433 }
5434
5435 /* Free temporary buffer */
5436 kfree(extra);
5437 } else {
5438 /* Command failed, log error */
5439 QDF_TRACE(QDF_MODULE_ID_HDD,
5440 QDF_TRACE_LEVEL_ERROR,
5441 "%s: GETIBSSPEERINFOALL command failed with status code %d",
5442 __func__, status);
5443 ret = -EINVAL;
5444 goto exit;
5445 }
5446 ret = 0;
5447
5448exit:
5449 return ret;
5450}
5451
5452/* Peer Info <Peer Addr> command */
5453static int drv_cmd_get_ibss_peer_info(hdd_adapter_t *adapter,
5454 hdd_context_t *hdd_ctx,
5455 uint8_t *command,
5456 uint8_t command_len,
5457 hdd_priv_data_t *priv_data)
5458{
5459 int ret = 0;
5460 uint8_t *value = command;
5461 QDF_STATUS status;
5462 hdd_station_ctx_t *pHddStaCtx = NULL;
5463 char extra[128] = { 0 };
5464 uint32_t length = 0;
5465 uint8_t staIdx = 0;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005466 struct qdf_mac_addr peerMacAddr;
5467
Krunal Sonibe766b02016-03-10 13:00:44 -08005468 if (QDF_IBSS_MODE != adapter->device_mode) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005469 hdd_warn("Unsupported in mode %s(%d)",
5470 hdd_device_mode_to_string(adapter->device_mode),
5471 adapter->device_mode);
5472 return -EINVAL;
5473 }
5474
5475 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5476
5477 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
5478 "%s: Received GETIBSSPEERINFO Command",
5479 __func__);
5480
5481 /* if there are no peers, no need to continue with the command */
5482 if (eConnectionState_IbssConnected !=
5483 pHddStaCtx->conn_info.connState) {
5484 QDF_TRACE(QDF_MODULE_ID_HDD,
5485 QDF_TRACE_LEVEL_INFO,
5486 "%s:No IBSS Peers coalesced",
5487 __func__);
5488 ret = -EINVAL;
5489 goto exit;
5490 }
5491
5492 /* Parse the incoming command buffer */
5493 status = hdd_parse_get_ibss_peer_info(value, &peerMacAddr);
5494 if (QDF_STATUS_SUCCESS != status) {
5495 QDF_TRACE(QDF_MODULE_ID_HDD,
5496 QDF_TRACE_LEVEL_ERROR,
5497 "%s: Invalid GETIBSSPEERINFO command",
5498 __func__);
5499 ret = -EINVAL;
5500 goto exit;
5501 }
5502
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005503 /* Get station index for the peer mac address and sanitize it */
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005504 hdd_ibss_get_sta_id(pHddStaCtx, &peerMacAddr, &staIdx);
5505
5506 if (staIdx > MAX_IBSS_PEERS) {
5507 QDF_TRACE(QDF_MODULE_ID_HDD,
5508 QDF_TRACE_LEVEL_ERROR,
5509 "%s: Invalid StaIdx %d returned",
5510 __func__, staIdx);
5511 ret = -EINVAL;
5512 goto exit;
5513 }
5514
5515 /* Handle the command */
5516 status = hdd_cfg80211_get_ibss_peer_info(adapter, staIdx);
5517 if (QDF_STATUS_SUCCESS == status) {
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005518 uint32_t txRate =
5519 pHddStaCtx->ibss_peer_info.peerInfoParams[0].txRate;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005520
5521 length = scnprintf(extra, sizeof(extra), "%d %d",
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005522 (int)txRate,
5523 (int)pHddStaCtx->ibss_peer_info.
5524 peerInfoParams[0].rssi);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005525
5526 /* Copy the data back into buffer */
5527 if (copy_to_user(priv_data->buf, &extra, length + 1)) {
5528 QDF_TRACE(QDF_MODULE_ID_HDD,
5529 QDF_TRACE_LEVEL_ERROR,
5530 "%s: copy data to user buffer failed GETIBSSPEERINFO command",
5531 __func__);
5532 ret = -EFAULT;
5533 goto exit;
5534 }
5535 } else {
5536 /* Command failed, log error */
5537 QDF_TRACE(QDF_MODULE_ID_HDD,
5538 QDF_TRACE_LEVEL_ERROR,
5539 "%s: GETIBSSPEERINFO command failed with status code %d",
5540 __func__, status);
5541 ret = -EINVAL;
5542 goto exit;
5543 }
5544
5545 /* Success ! */
5546 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO_MED,
5547 "%s", priv_data->buf);
5548 ret = 0;
5549
5550exit:
5551 return ret;
5552}
5553
5554static int drv_cmd_set_rmc_tx_rate(hdd_adapter_t *adapter,
5555 hdd_context_t *hdd_ctx,
5556 uint8_t *command,
5557 uint8_t command_len,
5558 hdd_priv_data_t *priv_data)
5559{
5560 int ret = 0;
5561 uint8_t *value = command;
5562 uint32_t uRate = 0;
5563 tTxrateinfoflags txFlags = 0;
5564 tSirRateUpdateInd rateUpdateParams = {0};
5565 int status;
5566 struct hdd_config *pConfig = hdd_ctx->config;
5567
Krunal Sonibe766b02016-03-10 13:00:44 -08005568 if ((QDF_IBSS_MODE != adapter->device_mode) &&
5569 (QDF_SAP_MODE != adapter->device_mode)) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005570 hddLog(LOGE,
5571 "Received SETRMCTXRATE cmd in invalid mode %s(%d)",
5572 hdd_device_mode_to_string(adapter->device_mode),
5573 adapter->device_mode);
5574 hddLog(LOGE,
5575 "SETRMCTXRATE cmd is allowed only in IBSS/SOFTAP mode");
5576 ret = -EINVAL;
5577 goto exit;
5578 }
5579
5580 status = hdd_parse_setrmcrate_command(value, &uRate, &txFlags);
5581 if (status) {
5582 QDF_TRACE(QDF_MODULE_ID_HDD,
5583 QDF_TRACE_LEVEL_ERROR,
5584 "Invalid SETRMCTXRATE command ");
5585 ret = -EINVAL;
5586 goto exit;
5587 }
5588 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
5589 "%s: uRate %d ", __func__, uRate);
5590 /* -1 implies ignore this param */
5591 rateUpdateParams.ucastDataRate = -1;
5592
5593 /*
5594 * Fill the user specifieed RMC rate param
5595 * and the derived tx flags.
5596 */
5597 rateUpdateParams.nss = (pConfig->enable2x2 == 0) ? 0 : 1;
5598 rateUpdateParams.reliableMcastDataRate = uRate;
5599 rateUpdateParams.reliableMcastDataRateTxFlag = txFlags;
5600 rateUpdateParams.dev_mode = adapter->device_mode;
5601 rateUpdateParams.bcastDataRate = -1;
5602 memcpy(rateUpdateParams.bssid.bytes,
5603 adapter->macAddressCurrent.bytes,
5604 sizeof(rateUpdateParams.bssid));
5605 status = sme_send_rate_update_ind((tHalHandle) (hdd_ctx->hHal),
5606 &rateUpdateParams);
5607
5608exit:
5609 return ret;
5610}
5611
5612static int drv_cmd_set_ibss_tx_fail_event(hdd_adapter_t *adapter,
5613 hdd_context_t *hdd_ctx,
5614 uint8_t *command,
5615 uint8_t command_len,
5616 hdd_priv_data_t *priv_data)
5617{
5618 int ret = 0;
5619 char *value;
5620 uint8_t tx_fail_count = 0;
5621 uint16_t pid = 0;
5622
5623 value = command;
5624
5625 ret = hdd_parse_ibsstx_fail_event_params(value, &tx_fail_count, &pid);
5626
5627 if (0 != ret) {
5628 hddLog(QDF_TRACE_LEVEL_INFO,
5629 "%s: Failed to parse SETIBSSTXFAILEVENT arguments",
5630 __func__);
5631 goto exit;
5632 }
5633
5634 hddLog(QDF_TRACE_LEVEL_INFO,
5635 "%s: tx_fail_cnt=%hhu, pid=%hu", __func__,
5636 tx_fail_count, pid);
5637
5638 if (0 == tx_fail_count) {
5639 /* Disable TX Fail Indication */
5640 if (QDF_STATUS_SUCCESS ==
5641 sme_tx_fail_monitor_start_stop_ind(hdd_ctx->hHal,
5642 tx_fail_count,
5643 NULL)) {
5644 cesium_pid = 0;
5645 } else {
5646 QDF_TRACE(QDF_MODULE_ID_HDD,
5647 QDF_TRACE_LEVEL_ERROR,
5648 "%s: failed to disable TX Fail Event ",
5649 __func__);
5650 ret = -EINVAL;
5651 }
5652 } else {
5653 if (QDF_STATUS_SUCCESS ==
5654 sme_tx_fail_monitor_start_stop_ind(hdd_ctx->hHal,
5655 tx_fail_count,
5656 (void *)hdd_tx_fail_ind_callback)) {
5657 cesium_pid = pid;
5658 QDF_TRACE(QDF_MODULE_ID_HDD,
5659 QDF_TRACE_LEVEL_INFO,
5660 "%s: Registered Cesium pid %u",
5661 __func__, cesium_pid);
5662 } else {
5663 QDF_TRACE(QDF_MODULE_ID_HDD,
5664 QDF_TRACE_LEVEL_ERROR,
5665 "%s: Failed to enable TX Fail Monitoring",
5666 __func__);
5667 ret = -EINVAL;
5668 }
5669 }
5670
5671exit:
5672 return ret;
5673}
5674
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08005675#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005676static int drv_cmd_set_ccx_roam_scan_channels(hdd_adapter_t *adapter,
5677 hdd_context_t *hdd_ctx,
5678 uint8_t *command,
5679 uint8_t command_len,
5680 hdd_priv_data_t *priv_data)
5681{
5682 int ret = 0;
5683 uint8_t *value = command;
5684 uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
5685 uint8_t numChannels = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305686 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005687
5688 ret = hdd_parse_channellist(value, ChannelList, &numChannels);
5689 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305690 QDF_TRACE(QDF_MODULE_ID_HDD,
5691 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005692 "%s: Failed to parse channel list information",
5693 __func__);
5694 goto exit;
5695 }
5696 if (numChannels > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305697 QDF_TRACE(QDF_MODULE_ID_HDD,
5698 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005699 "%s: number of channels (%d) supported exceeded max (%d)",
5700 __func__,
5701 numChannels,
5702 WNI_CFG_VALID_CHANNEL_LIST_LEN);
5703 ret = -EINVAL;
5704 goto exit;
5705 }
5706 status = sme_set_ese_roam_scan_channel_list(hdd_ctx->hHal,
5707 adapter->sessionId,
5708 ChannelList,
5709 numChannels);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305710 if (QDF_STATUS_SUCCESS != status) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305711 QDF_TRACE(QDF_MODULE_ID_HDD,
5712 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005713 "%s: Failed to update channel list information",
5714 __func__);
5715 ret = -EINVAL;
5716 goto exit;
5717 }
5718
5719exit:
5720 return ret;
5721}
5722
5723static int drv_cmd_get_tsm_stats(hdd_adapter_t *adapter,
5724 hdd_context_t *hdd_ctx,
5725 uint8_t *command,
5726 uint8_t command_len,
5727 hdd_priv_data_t *priv_data)
5728{
5729 int ret = 0;
5730 uint8_t *value = command;
5731 char extra[128] = { 0 };
5732 int len = 0;
5733 uint8_t tid = 0;
5734 hdd_station_ctx_t *pHddStaCtx;
5735 tAniTrafStrmMetrics tsm_metrics;
5736
Krunal Sonibe766b02016-03-10 13:00:44 -08005737 if ((QDF_STA_MODE != adapter->device_mode) &&
5738 (QDF_P2P_CLIENT_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005739 hdd_warn("Unsupported in mode %s(%d)",
5740 hdd_device_mode_to_string(adapter->device_mode),
5741 adapter->device_mode);
5742 return -EINVAL;
5743 }
5744
5745 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5746
5747 /* if not associated, return error */
5748 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305749 QDF_TRACE(QDF_MODULE_ID_HDD,
5750 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005751 "%s:Not associated!", __func__);
5752 ret = -EINVAL;
5753 goto exit;
5754 }
5755
5756 /* Move pointer to ahead of GETTSMSTATS<delimiter> */
5757 value = value + command_len + 1;
5758
5759 /* Convert the value from ascii to integer */
5760 ret = kstrtou8(value, 10, &tid);
5761 if (ret < 0) {
5762 /*
5763 * If the input value is greater than max value of datatype,
5764 * then also kstrtou8 fails
5765 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305766 QDF_TRACE(QDF_MODULE_ID_HDD,
5767 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005768 "%s: kstrtou8 failed range [%d - %d]",
5769 __func__, TID_MIN_VALUE,
5770 TID_MAX_VALUE);
5771 ret = -EINVAL;
5772 goto exit;
5773 }
5774 if ((tid < TID_MIN_VALUE) || (tid > TID_MAX_VALUE)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305775 QDF_TRACE(QDF_MODULE_ID_HDD,
5776 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005777 "tid value %d is out of range (Min: %d Max: %d)",
5778 tid, TID_MIN_VALUE, TID_MAX_VALUE);
5779 ret = -EINVAL;
5780 goto exit;
5781 }
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305782 QDF_TRACE(QDF_MODULE_ID_HDD,
5783 QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005784 "%s: Received Command to get tsm stats tid = %d",
5785 __func__, tid);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305786 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005787 hdd_get_tsm_stats(adapter, tid, &tsm_metrics)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305788 QDF_TRACE(QDF_MODULE_ID_HDD,
5789 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005790 "%s: failed to get tsm stats",
5791 __func__);
5792 ret = -EFAULT;
5793 goto exit;
5794 }
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305795 QDF_TRACE(QDF_MODULE_ID_HDD,
5796 QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005797 "UplinkPktQueueDly(%d) UplinkPktQueueDlyHist[0](%d) UplinkPktQueueDlyHist[1](%d) UplinkPktQueueDlyHist[2](%d) UplinkPktQueueDlyHist[3](%d) UplinkPktTxDly(%u) UplinkPktLoss(%d) UplinkPktCount(%d) RoamingCount(%d) RoamingDly(%d)",
5798 tsm_metrics.UplinkPktQueueDly,
5799 tsm_metrics.UplinkPktQueueDlyHist[0],
5800 tsm_metrics.UplinkPktQueueDlyHist[1],
5801 tsm_metrics.UplinkPktQueueDlyHist[2],
5802 tsm_metrics.UplinkPktQueueDlyHist[3],
5803 tsm_metrics.UplinkPktTxDly,
5804 tsm_metrics.UplinkPktLoss,
5805 tsm_metrics.UplinkPktCount,
5806 tsm_metrics.RoamingCount,
5807 tsm_metrics.RoamingDly);
5808 /*
5809 * Output TSM stats is of the format
5810 * GETTSMSTATS [PktQueueDly]
5811 * [PktQueueDlyHist[0]]:[PktQueueDlyHist[1]] ...[RoamingDly]
5812 * eg., GETTSMSTATS 10 1:0:0:161 20 1 17 8 39800
5813 */
5814 len = scnprintf(extra,
5815 sizeof(extra),
5816 "%s %d %d:%d:%d:%d %u %d %d %d %d",
5817 command,
5818 tsm_metrics.UplinkPktQueueDly,
5819 tsm_metrics.UplinkPktQueueDlyHist[0],
5820 tsm_metrics.UplinkPktQueueDlyHist[1],
5821 tsm_metrics.UplinkPktQueueDlyHist[2],
5822 tsm_metrics.UplinkPktQueueDlyHist[3],
5823 tsm_metrics.UplinkPktTxDly,
5824 tsm_metrics.UplinkPktLoss,
5825 tsm_metrics.UplinkPktCount,
5826 tsm_metrics.RoamingCount,
5827 tsm_metrics.RoamingDly);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305828 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005829 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305830 QDF_TRACE(QDF_MODULE_ID_HDD,
5831 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005832 "%s: failed to copy data to user buffer",
5833 __func__);
5834 ret = -EFAULT;
5835 goto exit;
5836 }
5837
5838exit:
5839 return ret;
5840}
5841
5842static int drv_cmd_set_cckm_ie(hdd_adapter_t *adapter,
5843 hdd_context_t *hdd_ctx,
5844 uint8_t *command,
5845 uint8_t command_len,
5846 hdd_priv_data_t *priv_data)
5847{
5848 int ret;
5849 uint8_t *value = command;
5850 uint8_t *cckmIe = NULL;
5851 uint8_t cckmIeLen = 0;
5852
5853 ret = hdd_parse_get_cckm_ie(value, &cckmIe, &cckmIeLen);
5854 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305855 QDF_TRACE(QDF_MODULE_ID_HDD,
5856 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005857 "%s: Failed to parse cckm ie data",
5858 __func__);
5859 goto exit;
5860 }
5861
5862 if (cckmIeLen > DOT11F_IE_RSN_MAX_LEN) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305863 QDF_TRACE(QDF_MODULE_ID_HDD,
5864 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005865 "%s: CCKM Ie input length is more than max[%d]",
5866 __func__, DOT11F_IE_RSN_MAX_LEN);
5867 if (NULL != cckmIe) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305868 qdf_mem_free(cckmIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005869 cckmIe = NULL;
5870 }
5871 ret = -EINVAL;
5872 goto exit;
5873 }
5874
5875 sme_set_cckm_ie(hdd_ctx->hHal, adapter->sessionId,
5876 cckmIe, cckmIeLen);
5877 if (NULL != cckmIe) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305878 qdf_mem_free(cckmIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005879 cckmIe = NULL;
5880 }
5881
5882exit:
5883 return ret;
5884}
5885
5886static int drv_cmd_ccx_beacon_req(hdd_adapter_t *adapter,
5887 hdd_context_t *hdd_ctx,
5888 uint8_t *command,
5889 uint8_t command_len,
5890 hdd_priv_data_t *priv_data)
5891{
5892 int ret;
5893 uint8_t *value = command;
5894 tCsrEseBeaconReq eseBcnReq;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305895 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005896
Krunal Sonibe766b02016-03-10 13:00:44 -08005897 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005898 hdd_warn("Unsupported in mode %s(%d)",
5899 hdd_device_mode_to_string(adapter->device_mode),
5900 adapter->device_mode);
5901 return -EINVAL;
5902 }
5903
5904 ret = hdd_parse_ese_beacon_req(value, &eseBcnReq);
5905 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305906 QDF_TRACE(QDF_MODULE_ID_HDD,
5907 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005908 "%s: Failed to parse ese beacon req",
5909 __func__);
5910 goto exit;
5911 }
5912
5913 if (!hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305914 hddLog(QDF_TRACE_LEVEL_INFO, FL("Not associated"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005915 hdd_indicate_ese_bcn_report_no_results(adapter,
5916 eseBcnReq.bcnReq[0].measurementToken,
5917 0x02, /* BIT(1) set for measurement done */
5918 0); /* no BSS */
5919 goto exit;
5920 }
5921
5922 status = sme_set_ese_beacon_request(hdd_ctx->hHal,
5923 adapter->sessionId,
5924 &eseBcnReq);
5925
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305926 if (QDF_STATUS_E_RESOURCES == status) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305927 hddLog(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005928 FL("sme_set_ese_beacon_request failed (%d), a request already in progress"),
5929 status);
5930 ret = -EBUSY;
5931 goto exit;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305932 } else if (QDF_STATUS_SUCCESS != status) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305933 QDF_TRACE(QDF_MODULE_ID_HDD,
5934 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005935 "%s: sme_set_ese_beacon_request failed (%d)",
5936 __func__, status);
5937 ret = -EINVAL;
5938 goto exit;
5939 }
5940
5941exit:
5942 return ret;
5943}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08005944#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005945
5946static int drv_cmd_set_mc_rate(hdd_adapter_t *adapter,
5947 hdd_context_t *hdd_ctx,
5948 uint8_t *command,
5949 uint8_t command_len,
5950 hdd_priv_data_t *priv_data)
5951{
5952 int ret = 0;
5953 uint8_t *value = command;
5954 int targetRate;
5955
5956 /* input value is in units of hundred kbps */
5957
5958 /* Move pointer to ahead of SETMCRATE<delimiter> */
5959 value = value + command_len + 1;
5960
5961 /* Convert the value from ascii to integer, decimal base */
5962 ret = kstrtouint(value, 10, &targetRate);
5963
5964 ret = wlan_hdd_set_mc_rate(adapter, targetRate);
5965 return ret;
5966}
5967
5968static int drv_cmd_max_tx_power(hdd_adapter_t *adapter,
5969 hdd_context_t *hdd_ctx,
5970 uint8_t *command,
5971 uint8_t command_len,
5972 hdd_priv_data_t *priv_data)
5973{
5974 int ret = 0;
5975 int status;
5976 int txPower;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305977 QDF_STATUS qdf_status;
5978 QDF_STATUS smeStatus;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005979 uint8_t *value = command;
Anurag Chouhan6d760662016-02-20 16:05:43 +05305980 struct qdf_mac_addr bssid = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
5981 struct qdf_mac_addr selfMac = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005982 hdd_adapter_list_node_t *pAdapterNode = NULL;
5983 hdd_adapter_list_node_t *pNext = NULL;
5984
5985 status = hdd_parse_setmaxtxpower_command(value, &txPower);
5986 if (status) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305987 QDF_TRACE(QDF_MODULE_ID_HDD,
5988 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005989 "Invalid MAXTXPOWER command ");
5990 ret = -EINVAL;
5991 goto exit;
5992 }
5993
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305994 qdf_status = hdd_get_front_adapter(hdd_ctx, &pAdapterNode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005995 while (NULL != pAdapterNode
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305996 && QDF_STATUS_SUCCESS == qdf_status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005997 adapter = pAdapterNode->pAdapter;
5998 /* Assign correct self MAC address */
Anurag Chouhanc5548422016-02-24 18:33:27 +05305999 qdf_copy_macaddr(&bssid,
Srinivas Girigowda97215232015-09-24 12:26:28 -07006000 &adapter->macAddressCurrent);
Anurag Chouhanc5548422016-02-24 18:33:27 +05306001 qdf_copy_macaddr(&selfMac,
Srinivas Girigowda97215232015-09-24 12:26:28 -07006002 &adapter->macAddressCurrent);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006003
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306004 hddLog(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006005 "Device mode %d max tx power %d selfMac: " MAC_ADDRESS_STR " bssId: " MAC_ADDRESS_STR " ",
6006 adapter->device_mode, txPower,
Srinivas Girigowda97215232015-09-24 12:26:28 -07006007 MAC_ADDR_ARRAY(selfMac.bytes),
6008 MAC_ADDR_ARRAY(bssid.bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006009
Srinivas Girigowda97215232015-09-24 12:26:28 -07006010 smeStatus = sme_set_max_tx_power(hdd_ctx->hHal,
6011 bssid, selfMac, txPower);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306012 if (QDF_STATUS_SUCCESS != status) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306013 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006014 "%s:Set max tx power failed",
6015 __func__);
6016 ret = -EINVAL;
6017 goto exit;
6018 }
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306019 hddLog(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006020 "%s: Set max tx power success",
6021 __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306022 qdf_status = hdd_get_next_adapter(hdd_ctx, pAdapterNode,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006023 &pNext);
6024 pAdapterNode = pNext;
6025 }
6026
6027exit:
6028 return ret;
6029}
6030
6031static int drv_cmd_set_dfs_scan_mode(hdd_adapter_t *adapter,
6032 hdd_context_t *hdd_ctx,
6033 uint8_t *command,
6034 uint8_t command_len,
6035 hdd_priv_data_t *priv_data)
6036{
6037 int ret = 0;
6038 uint8_t *value = command;
6039 uint8_t dfsScanMode = CFG_ROAMING_DFS_CHANNEL_DEFAULT;
6040
6041 /* Move pointer to ahead of SETDFSSCANMODE<delimiter> */
6042 value = value + command_len + 1;
6043
6044 /* Convert the value from ascii to integer */
6045 ret = kstrtou8(value, 10, &dfsScanMode);
6046 if (ret < 0) {
6047 /*
6048 * If the input value is greater than max value of datatype,
6049 * then also kstrtou8 fails
6050 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306051 QDF_TRACE(QDF_MODULE_ID_HDD,
6052 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006053 "%s: kstrtou8 failed range [%d - %d]",
6054 __func__, CFG_ROAMING_DFS_CHANNEL_MIN,
6055 CFG_ROAMING_DFS_CHANNEL_MAX);
6056 ret = -EINVAL;
6057 goto exit;
6058 }
6059
6060 if ((dfsScanMode < CFG_ROAMING_DFS_CHANNEL_MIN) ||
6061 (dfsScanMode > CFG_ROAMING_DFS_CHANNEL_MAX)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306062 QDF_TRACE(QDF_MODULE_ID_HDD,
6063 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006064 "dfsScanMode value %d is out of range (Min: %d Max: %d)",
6065 dfsScanMode,
6066 CFG_ROAMING_DFS_CHANNEL_MIN,
6067 CFG_ROAMING_DFS_CHANNEL_MAX);
6068 ret = -EINVAL;
6069 goto exit;
6070 }
6071
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306072 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006073 "%s: Received Command to Set DFS Scan Mode = %d",
6074 __func__, dfsScanMode);
6075
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08006076 /* When DFS scanning is disabled, the DFS channels need to be
6077 * removed from the operation of device.
6078 */
6079 ret = wlan_hdd_disable_dfs_chan_scan(hdd_ctx, adapter,
6080 (dfsScanMode == CFG_ROAMING_DFS_CHANNEL_DISABLED));
6081 if (ret < 0) {
6082 /* Some conditions prevented it from disabling DFS channels */
6083 hddLog(LOGE,
6084 FL("disable/enable DFS channel request was denied"));
6085 goto exit;
6086 }
6087
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006088 hdd_ctx->config->allowDFSChannelRoam = dfsScanMode;
6089 sme_update_dfs_scan_mode(hdd_ctx->hHal, adapter->sessionId,
6090 dfsScanMode);
6091
6092exit:
6093 return ret;
6094}
6095
6096static int drv_cmd_get_dfs_scan_mode(hdd_adapter_t *adapter,
6097 hdd_context_t *hdd_ctx,
6098 uint8_t *command,
6099 uint8_t command_len,
6100 hdd_priv_data_t *priv_data)
6101{
6102 int ret = 0;
6103 uint8_t dfsScanMode = sme_get_dfs_scan_mode(hdd_ctx->hHal);
6104 char extra[32];
6105 uint8_t len = 0;
6106
6107 len = scnprintf(extra, sizeof(extra), "%s %d", command, dfsScanMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05306108 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006109 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306110 QDF_TRACE(QDF_MODULE_ID_HDD,
6111 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006112 "%s: failed to copy data to user buffer",
6113 __func__);
6114 ret = -EFAULT;
6115 }
6116
6117 return ret;
6118}
6119
6120static int drv_cmd_get_link_status(hdd_adapter_t *adapter,
6121 hdd_context_t *hdd_ctx,
6122 uint8_t *command,
6123 uint8_t command_len,
6124 hdd_priv_data_t *priv_data)
6125{
6126 int ret = 0;
6127 int value = wlan_hdd_get_link_status(adapter);
6128 char extra[32];
6129 uint8_t len;
6130
6131 len = scnprintf(extra, sizeof(extra), "%s %d", command, value);
Anurag Chouhan6d760662016-02-20 16:05:43 +05306132 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006133 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306134 QDF_TRACE(QDF_MODULE_ID_HDD,
6135 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006136 "%s: failed to copy data to user buffer",
6137 __func__);
6138 ret = -EFAULT;
6139 }
6140
6141 return ret;
6142}
6143
6144#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
6145static int drv_cmd_enable_ext_wow(hdd_adapter_t *adapter,
6146 hdd_context_t *hdd_ctx,
6147 uint8_t *command,
6148 uint8_t command_len,
6149 hdd_priv_data_t *priv_data)
6150{
6151 uint8_t *value = command;
6152 int set_value;
6153
6154 /* Move pointer to ahead of ENABLEEXTWOW */
6155 value = value + command_len;
6156
6157 sscanf(value, "%d", &set_value);
6158
6159 return hdd_enable_ext_wow_parser(adapter,
6160 adapter->sessionId,
6161 set_value);
6162}
6163
6164static int drv_cmd_set_app1_params(hdd_adapter_t *adapter,
6165 hdd_context_t *hdd_ctx,
6166 uint8_t *command,
6167 uint8_t command_len,
6168 hdd_priv_data_t *priv_data)
6169{
6170 int ret;
6171 uint8_t *value = command;
6172
6173 /* Move pointer to ahead of SETAPP1PARAMS */
6174 value = value + command_len;
6175
6176 ret = hdd_set_app_type1_parser(adapter,
6177 value, strlen(value));
6178 if (ret >= 0)
6179 hdd_ctx->is_extwow_app_type1_param_set = true;
6180
6181 return ret;
6182}
6183
6184static int drv_cmd_set_app2_params(hdd_adapter_t *adapter,
6185 hdd_context_t *hdd_ctx,
6186 uint8_t *command,
6187 uint8_t command_len,
6188 hdd_priv_data_t *priv_data)
6189{
6190 int ret;
6191 uint8_t *value = command;
6192
6193 /* Move pointer to ahead of SETAPP2PARAMS */
6194 value = value + command_len;
6195
6196 ret = hdd_set_app_type2_parser(adapter, value, strlen(value));
6197 if (ret >= 0)
6198 hdd_ctx->is_extwow_app_type2_param_set = true;
6199
6200 return ret;
6201}
6202#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
6203
6204#ifdef FEATURE_WLAN_TDLS
6205/**
6206 * drv_cmd_tdls_secondary_channel_offset() - secondary tdls off channel offset
6207 * @adapter: Pointer to the HDD adapter
6208 * @hdd_ctx: Pointer to the HDD context
6209 * @command: Driver command string
6210 * @command_len: Driver command string length
6211 * @priv_data: Private data coming with the driver command. Unused here
6212 *
6213 * This function handles driver command that sets the secondary tdls off channel
6214 * offset
6215 *
6216 * Return: 0 on success; negative errno otherwise
6217 */
6218static int drv_cmd_tdls_secondary_channel_offset(hdd_adapter_t *adapter,
6219 hdd_context_t *hdd_ctx,
6220 uint8_t *command,
6221 uint8_t command_len,
6222 hdd_priv_data_t *priv_data)
6223{
6224 int ret;
6225 uint8_t *value = command;
6226 int set_value;
6227
6228 /* Move pointer to point the string */
6229 value += command_len;
6230
6231 ret = sscanf(value, "%d", &set_value);
6232 if (ret != 1)
6233 return -EINVAL;
6234
6235 hddLog(LOG1, FL("Tdls offchannel offset:%d"), set_value);
6236
6237 ret = hdd_set_tdls_secoffchanneloffset(hdd_ctx, set_value);
6238
6239 return ret;
6240}
6241
6242/**
6243 * drv_cmd_tdls_off_channel_mode() - set tdls off channel mode
6244 * @adapter: Pointer to the HDD adapter
6245 * @hdd_ctx: Pointer to the HDD context
6246 * @command: Driver command string
6247 * @command_len: Driver command string length
6248 * @priv_data: Private data coming with the driver command. Unused here
6249 *
6250 * This function handles driver command that sets tdls off channel mode
6251 *
6252 * Return: 0 on success; negative errno otherwise
6253 */
6254static int drv_cmd_tdls_off_channel_mode(hdd_adapter_t *adapter,
6255 hdd_context_t *hdd_ctx,
6256 uint8_t *command,
6257 uint8_t command_len,
6258 hdd_priv_data_t *priv_data)
6259{
6260 int ret;
6261 uint8_t *value = command;
6262 int set_value;
6263
6264 /* Move pointer to point the string */
6265 value += command_len;
6266
6267 ret = sscanf(value, "%d", &set_value);
6268 if (ret != 1)
6269 return -EINVAL;
6270
6271 hddLog(LOG1, FL("Tdls offchannel mode:%d"), set_value);
6272
6273 ret = hdd_set_tdls_offchannelmode(adapter, set_value);
6274
6275 return ret;
6276}
6277
6278/**
6279 * drv_cmd_tdls_off_channel() - set tdls off channel number
6280 * @adapter: Pointer to the HDD adapter
6281 * @hdd_ctx: Pointer to the HDD context
6282 * @command: Driver command string
6283 * @command_len: Driver command string length
6284 * @priv_data: Private data coming with the driver command. Unused here
6285 *
6286 * This function handles driver command that sets tdls off channel number
6287 *
6288 * Return: 0 on success; negative errno otherwise
6289 */
6290static int drv_cmd_tdls_off_channel(hdd_adapter_t *adapter,
6291 hdd_context_t *hdd_ctx,
6292 uint8_t *command,
6293 uint8_t command_len,
6294 hdd_priv_data_t *priv_data)
6295{
6296 int ret;
6297 uint8_t *value = command;
6298 int set_value;
6299
6300 /* Move pointer to point the string */
6301 value += command_len;
6302
6303 ret = sscanf(value, "%d", &set_value);
6304 if (ret != 1)
6305 return -EINVAL;
6306
Krishna Kumaar Natarajan4d090352015-10-26 18:30:53 -07006307 if (CDS_IS_DFS_CH(set_value)) {
6308 hdd_err("DFS channel %d is passed for hdd_set_tdls_offchannel",
6309 set_value);
6310 return -EINVAL;
6311 }
6312
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006313 hddLog(LOG1, FL("Tdls offchannel num: %d"), set_value);
6314
6315 ret = hdd_set_tdls_offchannel(hdd_ctx, set_value);
6316
6317 return ret;
6318}
6319
6320/**
6321 * drv_cmd_tdls_scan() - set tdls scan type
6322 * @adapter: Pointer to the HDD adapter
6323 * @hdd_ctx: Pointer to the HDD context
6324 * @command: Driver command string
6325 * @command_len: Driver command string length
6326 * @priv_data: Private data coming with the driver command. Unused here
6327 *
6328 * This function handles driver command that sets tdls scan type
6329 *
6330 * Return: 0 on success; negative errno otherwise
6331 */
6332static int drv_cmd_tdls_scan(hdd_adapter_t *adapter,
6333 hdd_context_t *hdd_ctx,
6334 uint8_t *command,
6335 uint8_t command_len,
6336 hdd_priv_data_t *priv_data)
6337{
6338 int ret;
6339 uint8_t *value = command;
6340 int set_value;
6341
6342 /* Move pointer to point the string */
6343 value += command_len;
6344
6345 ret = sscanf(value, "%d", &set_value);
6346 if (ret != 1)
6347 return -EINVAL;
6348
6349 hddLog(LOG1, FL("Tdls scan type val: %d"), set_value);
6350
6351 ret = hdd_set_tdls_scan_type(hdd_ctx, set_value);
6352
6353 return ret;
6354}
6355#endif
6356
6357static int drv_cmd_get_rssi(hdd_adapter_t *adapter,
6358 hdd_context_t *hdd_ctx,
6359 uint8_t *command,
6360 uint8_t command_len,
6361 hdd_priv_data_t *priv_data)
6362{
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006363 int ret = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006364 int8_t rssi = 0;
6365 char extra[32];
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006366
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006367 uint8_t len = 0;
6368
6369 wlan_hdd_get_rssi(adapter, &rssi);
6370
6371 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
Anurag Chouhan6d760662016-02-20 16:05:43 +05306372 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006373
6374 if (copy_to_user(priv_data->buf, &extra, len)) {
6375 hddLog(LOGE, FL("Failed to copy data to user buffer"));
6376 ret = -EFAULT;
6377 }
6378
6379 return ret;
6380}
6381
6382static int drv_cmd_get_linkspeed(hdd_adapter_t *adapter,
6383 hdd_context_t *hdd_ctx,
6384 uint8_t *command,
6385 uint8_t command_len,
6386 hdd_priv_data_t *priv_data)
6387{
6388 int ret;
6389 uint32_t link_speed = 0;
6390 char extra[32];
6391 uint8_t len = 0;
6392
6393 ret = wlan_hdd_get_link_speed(adapter, &link_speed);
6394 if (0 != ret)
6395 return ret;
6396
6397 len = scnprintf(extra, sizeof(extra), "%s %d", command, link_speed);
Anurag Chouhan6d760662016-02-20 16:05:43 +05306398 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006399 if (copy_to_user(priv_data->buf, &extra, len)) {
6400 hddLog(LOGE, FL("Failed to copy data to user buffer"));
6401 ret = -EFAULT;
6402 }
6403
6404 return ret;
6405}
6406
6407#ifdef FEATURE_NAPI
6408/**
6409 * hdd_parse_napi() - helper functions to drv_cmd_napi
6410 * @str : source string to parse
6411 * @cmd : pointer to cmd part after parsing
6412 * @sub : pointer to subcmd part after parsing
6413 * @aux : pointer to optional aux part after parsing
6414 *
6415 * Example:
6416 * NAPI SCALE <n> +-- IN str
6417 * | | +------ OUT aux
6418 * | +------------ OUT subcmd
6419 * +----------------- OUT cmd
6420 *
6421 * Return: ==0: success; !=0: failure
6422 */
6423static int hdd_parse_napi(char **str, char **cmd, char **sub, char **aux)
6424{
6425 int rc;
6426 char *token, *lcmd = NULL, *lsub = NULL, *laux = NULL;
6427
6428 NAPI_DEBUG("-->\n");
6429
6430 token = strsep(str, " \t");
6431 if (NULL == token) {
6432 hdd_err("cannot parse cmd");
6433 goto parse_end;
6434 }
6435 lcmd = token;
6436
6437 token = strsep(str, " \t");
6438 if (NULL == token) {
6439 hdd_err("cannot parse subcmd");
6440 goto parse_end;
6441 }
6442 lsub = token;
6443
6444 token = strsep(str, " \t");
6445 if (NULL == token)
6446 hdd_warn("cannot parse aux\n");
6447 else
6448 laux = token;
6449
6450parse_end:
6451 if ((NULL == lcmd) || (NULL == lsub))
6452 rc = -EINVAL;
6453 else {
6454 rc = 0;
6455 *cmd = lcmd;
6456 *sub = lsub;
6457 if (NULL != aux)
6458 *aux = laux;
6459 }
6460 NAPI_DEBUG("<--[rc=%d]\n", rc);
6461 return rc;
6462}
6463
6464
6465/**
6466 * hdd_parse_stats() - print NAPI stats into a buffer
6467 * @buf : buffer to write stats into
6468 * @max : "size of buffer"
6469 * @idp : NULL: all stats, otherwise, ptr to the NAPI instance
6470 * @napid: binary structure to retrieve the stats from
6471 *
6472 * Return: number of bytes written into the buffer
6473 */
6474int hdd_napi_stats(char *buf,
6475 int max,
6476 char *indp,
6477 struct qca_napi_data *napid)
6478{
6479 int n = 0;
6480 int i, j, k; /* NAPI, CPU, bucket indices */
6481 int from, to;
6482 struct qca_napi_info *napii;
6483 struct qca_napi_stat *napis;
6484
6485 NAPI_DEBUG("-->\n");
6486
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006487 if (NULL == napid)
6488 return n;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006489 if (NULL == indp) {
6490 from = 0;
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006491 to = CE_COUNT_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006492 } else {
6493 if (0 > kstrtoint(indp, 10, &to)) {
6494 from = 0;
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006495 to = CE_COUNT_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006496 } else
6497 from = to;
6498 }
6499
6500 for (i = from; i < to; i++)
6501 if (napid->ce_map & (0x01 << i)) {
6502 napii = &(napid->napis[i]);
6503 for (j = 0; j < NR_CPUS; j++) {
6504 napis = &(napii->stats[j]);
6505 n += scnprintf(buf + n, max - n,
6506 "STATS: NAPI[%d] CPU: %d scheds: %d polls: %d completes: %d done: %d ",
6507 i, j,
6508 napis->napi_schedules,
6509 napis->napi_polls,
6510 napis->napi_completes,
6511 napis->napi_workdone);
6512
6513 for (k = 0; k < QCA_NAPI_NUM_BUCKETS; k++) {
6514 n += scnprintf(
6515 buf + n, max - n,
6516 " %d",
6517 napis->napi_budget_uses[k]);
6518 }
6519 n += scnprintf(buf+n, max - n, "\n");
6520 }
6521 }
6522
6523 NAPI_DEBUG("<--[n=%d]\n", n);
6524 return n;
6525}
6526
6527/**
6528 * napi_set_scale() - sets the scale attribute in all NAPI entries
6529 * @sc : scale to set
6530 *
6531 * Return: void
6532 */
6533static void napi_set_scale(uint8_t sc)
6534{
6535 uint32_t i;
6536 struct qca_napi_data *napi_data;
6537
6538 napi_data = hdd_napi_get_all();
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006539 if (likely(NULL != napi_data))
6540 for (i = 0; i < CE_COUNT_MAX; i++)
6541 if (napi_data->ce_map & (0x01 << i))
6542 napi_data->napis[i].scale = sc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006543
6544 return;
6545}
6546/**
6547 * drv_cmd_napi() - processes NAPI commands
6548 * @adapter : net_device
6549 * @hdd_ctx : HDD context
6550 * @command : command string from user command (including "NAPI")
6551 * @command_len: length of command
6552 * @priv_data : ifr_data
6553 *
6554 * Commands supported:
6555 * NAPI ENABLE : enables NAPI administratively. Note that this may not
6556 * enable NAPI functionally, as some other conditions
6557 * may not have been satisfied yet
6558 * NAPI DISABLE : reverse operation of "enable"
6559 * NAPI STATUS : get global status of NAPI instances
6560 * NAPI STATS [<n>] : get the stats for a given NAPI instance
6561 * NAPI SCALE <n> : set the scale factor
6562 *
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006563 * Return: 0: success; !0: failure
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006564 */
6565static int drv_cmd_napi(hdd_adapter_t *adapter,
6566 hdd_context_t *hdd_ctx,
6567 uint8_t *command,
6568 uint8_t command_len,
6569 hdd_priv_data_t *priv_data)
6570{
6571 int rc = 0;
6572 int n, l;
6573 char *cmd = NULL, *subcmd = NULL, *aux = NULL;
6574 char *synopsis = "NAPI ENABLE\n"
6575 "NAPI DISABLE\n"
6576 "NAPI STATUS\n"
6577 "NAPI STATS [<n>] -- if no <n> then all\n"
6578 "NAPI SCALE <n> -- set the scale\n";
6579 char *reply = NULL;
6580
6581 /* make a local copy, as strsep modifies the str in place */
6582 char *str = NULL;
6583
6584 NAPI_DEBUG("-->\n");
6585
6586 /**
6587 * NOTE TO MAINTAINER: from this point to the end of the function,
6588 * please do not return anywhere in the code except the very end
6589 * to avoid memory leakage (goto end_drv_napi instead)
6590 * or make sure that reply+str is freed
6591 */
6592 reply = kmalloc(MAX_USER_COMMAND_SIZE, GFP_KERNEL);
6593 if (NULL == reply) {
6594 hdd_err("could not allocate reply buffer");
6595 rc = -ENOMEM;
6596 goto end_drv_napi;
6597 }
6598
6599 str = kmalloc(strlen(command) + 1, GFP_KERNEL);
6600 if (NULL == str) {
6601 hdd_err("could not allocate copy of input buffer");
6602 rc = -ENOMEM;
6603 goto end_drv_napi;
6604 }
6605
6606 strlcpy(str, command, strlen(command) + 1);
6607 hdd_debug("parsing command into cmd=0x%p sub=0x%p aux=0x%p\n",
6608 cmd, subcmd, aux);
6609
6610
6611 rc = hdd_parse_napi(&str, &cmd, &subcmd, &aux);
6612
6613 if (0 != rc) {
6614 const char *msg = "unknown or badly formatted cmd\n%s";
Anurag Chouhan6d760662016-02-20 16:05:43 +05306615 l = QDF_MIN(MAX_USER_COMMAND_SIZE,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006616 strlen(msg)+strlen(synopsis));
6617 n = scnprintf(reply, l, msg, synopsis);
6618
6619 if (copy_to_user(priv_data->buf, reply,
Anurag Chouhan6d760662016-02-20 16:05:43 +05306620 QDF_MIN(priv_data->total_len, l)))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006621 hdd_err("failed to copy data to user buffer");
6622 hdd_debug("reply: %s", reply);
6623
6624 rc = -EINVAL;
6625 } else {
6626 hdd_debug("cmd=(%s) subcmd=(%s) aux=(%s)\n",
6627 cmd, subcmd, aux);
6628 if (!strcmp(subcmd, "ENABLE"))
6629 hdd_napi_event(NAPI_EVT_CMD_STATE, (void *)1);
6630 else if (!strcmp(subcmd, "DISABLE"))
6631 hdd_napi_event(NAPI_EVT_CMD_STATE, (void *)0);
6632 else if (!strcmp(subcmd, "STATUS")) {
6633 int n = 0;
6634 uint32_t i;
6635 struct qca_napi_data *napi_data;
6636
6637 napi_data = hdd_napi_get_all();
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006638 if (unlikely(NULL == napi_data))
6639 goto status_end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006640 n += scnprintf(reply+n, MAX_USER_COMMAND_SIZE - n,
6641 "NAPI state: 0x%08x map: 0x%08x\n",
6642 napi_data->state,
6643 napi_data->ce_map);
6644
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006645 for (i = 0; i < CE_COUNT_MAX; i++)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006646 if (napi_data->ce_map & (0x01 << i)) {
6647 n += scnprintf(
6648 reply + n,
6649 MAX_USER_COMMAND_SIZE - n,
6650 "#%d: id: %d, scale=%d\n",
6651 i,
6652 napi_data->napis[i].id,
6653 napi_data->napis[i].scale);
6654 }
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006655 status_end:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006656 hdd_info("wlan: STATUS DATA:\n%s", reply);
6657 if (copy_to_user(priv_data->buf, reply,
Anurag Chouhan6d760662016-02-20 16:05:43 +05306658 QDF_MIN(n, priv_data->total_len)))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006659 rc = -EINVAL;
6660 } else if (!strcmp(subcmd, "STATS")) {
6661 int n = 0;
6662 struct qca_napi_data *napi_data;
6663
6664 napi_data = hdd_napi_get_all();
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006665 if (NULL != napi_data) {
6666 n = hdd_napi_stats(reply, MAX_USER_COMMAND_SIZE,
6667 aux, napi_data);
6668 NAPI_DEBUG("STATS: returns %d\n", n);
6669 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006670 if (n > 0) {
6671 if (copy_to_user(priv_data->buf, reply,
Anurag Chouhan6d760662016-02-20 16:05:43 +05306672 QDF_MIN(priv_data->total_len,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006673 n)))
6674 rc = -EINVAL;
6675 hdd_info("wlan: STATS_DATA\n%s\n", reply);
6676 } else
6677 rc = -EINVAL;
6678 } else if (!strcmp(subcmd, "SCALE")) {
6679 if (NULL == aux) {
6680 rc = -EINVAL;
6681 hdd_err("wlan: SCALE cmd requires <n>");
6682 } else {
6683 uint8_t sc;
6684 rc = kstrtou8(aux, 10, &sc);
6685 if (rc) {
6686 hdd_err("wlan: bad scale (%s)", aux);
6687 rc = -EINVAL;
6688 } else
6689 napi_set_scale(sc);
6690 }
6691 } /* SCALE */
6692 }
6693end_drv_napi:
6694 if (NULL != str)
6695 kfree(str);
6696 if (NULL != reply)
6697 kfree(reply);
6698
6699 NAPI_DEBUG("<--[rc=%d]\n", rc);
6700 return rc;
6701}
6702#endif /* FEATURE_NAPI */
6703
6704/**
6705 * hdd_set_rx_filter() - set RX filter
6706 * @adapter: Pointer to adapter
6707 * @action: Filter action
6708 * @pattern: Address pattern
6709 *
6710 * Address pattern is most significant byte of address for example
6711 * 0x01 for IPV4 multicast address
6712 * 0x33 for IPV6 multicast address
6713 * 0xFF for broadcast address
6714 *
6715 * Return: 0 for success, non-zero for failure
6716 */
6717static int hdd_set_rx_filter(hdd_adapter_t *adapter, bool action,
6718 uint8_t pattern)
6719{
6720 int ret;
6721 uint8_t i;
6722 tHalHandle handle;
6723 tSirRcvFltMcAddrList *filter;
6724 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
6725
6726 ret = wlan_hdd_validate_context(hdd_ctx);
6727 if (0 != ret)
6728 return ret;
6729
6730 handle = hdd_ctx->hHal;
6731
6732 if (NULL == handle) {
6733 hdd_err("HAL Handle is NULL");
6734 return -EINVAL;
6735 }
6736
6737 /*
6738 * If action is false it means start dropping packets
6739 * Set addr_filter_pattern which will be used when sending
6740 * MC/BC address list to target
6741 */
6742 if (!action)
6743 adapter->addr_filter_pattern = pattern;
6744 else
6745 adapter->addr_filter_pattern = 0;
6746
Krunal Sonibe766b02016-03-10 13:00:44 -08006747 if (((adapter->device_mode == QDF_STA_MODE) ||
6748 (adapter->device_mode == QDF_P2P_CLIENT_MODE)) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006749 adapter->mc_addr_list.mc_cnt &&
6750 hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
6751
6752
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306753 filter = qdf_mem_malloc(sizeof(*filter));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006754 if (NULL == filter) {
6755 hdd_err("Could not allocate Memory");
6756 return -ENOMEM;
6757 }
6758 filter->action = action;
6759 for (i = 0; i < adapter->mc_addr_list.mc_cnt; i++) {
6760 if (!memcmp(adapter->mc_addr_list.addr[i],
6761 &pattern, 1)) {
Srinivas Girigowda98530492015-11-20 17:39:24 -08006762 memcpy(filter->multicastAddr[i].bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006763 adapter->mc_addr_list.addr[i],
6764 sizeof(adapter->mc_addr_list.addr[i]));
6765 filter->ulMulticastAddrCnt++;
Srinivas Girigowdaf2599dd2015-11-16 18:20:46 -08006766 hdd_info("%s RX filter : addr ="
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006767 MAC_ADDRESS_STR,
6768 action ? "setting" : "clearing",
Srinivas Girigowda98530492015-11-20 17:39:24 -08006769 MAC_ADDR_ARRAY(filter->multicastAddr[i].bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006770 }
6771 }
6772 /* Set rx filter */
6773 sme_8023_multicast_list(handle, adapter->sessionId, filter);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306774 qdf_mem_free(filter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006775 } else {
Srinivas Girigowdaf2599dd2015-11-16 18:20:46 -08006776 hdd_info("mode %d mc_cnt %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006777 adapter->device_mode, adapter->mc_addr_list.mc_cnt);
6778 }
6779
6780 return 0;
6781}
6782
6783/**
6784 * hdd_driver_rxfilter_comand_handler() - RXFILTER driver command handler
6785 * @command: Pointer to input string driver command
6786 * @adapter: Pointer to adapter
6787 * @action: Action to enable/disable filtering
6788 *
6789 * If action == false
6790 * Start filtering out data packets based on type
6791 * RXFILTER-REMOVE 0 -> Start filtering out unicast data packets
6792 * RXFILTER-REMOVE 1 -> Start filtering out broadcast data packets
6793 * RXFILTER-REMOVE 2 -> Start filtering out IPV4 mcast data packets
6794 * RXFILTER-REMOVE 3 -> Start filtering out IPV6 mcast data packets
6795 *
6796 * if action == true
6797 * Stop filtering data packets based on type
6798 * RXFILTER-ADD 0 -> Stop filtering unicast data packets
6799 * RXFILTER-ADD 1 -> Stop filtering broadcast data packets
6800 * RXFILTER-ADD 2 -> Stop filtering IPV4 mcast data packets
6801 * RXFILTER-ADD 3 -> Stop filtering IPV6 mcast data packets
6802 *
6803 * Current implementation only supports IPV4 address filtering by
6804 * selectively allowing IPV4 multicast data packest based on
6805 * address list received in .ndo_set_rx_mode
6806 *
6807 * Return: 0 for success, non-zero for failure
6808 */
6809static int hdd_driver_rxfilter_comand_handler(uint8_t *command,
6810 hdd_adapter_t *adapter,
6811 bool action)
6812{
6813 int ret = 0;
6814 uint8_t *value;
6815 uint8_t type;
6816
6817 value = command;
6818 /* Skip space after RXFILTER-REMOVE OR RXFILTER-ADD based on action */
6819 if (!action)
6820 value = command + 16;
6821 else
6822 value = command + 13;
6823 ret = kstrtou8(value, 10, &type);
6824 if (ret < 0) {
6825 hdd_err("kstrtou8 failed invalid input value %d", type);
6826 return -EINVAL;
6827 }
6828
6829 switch (type) {
6830 case 2:
6831 /* Set rx filter for IPV4 multicast data packets */
6832 ret = hdd_set_rx_filter(adapter, action, 0x01);
6833 break;
6834 default:
6835 hdd_info("Unsupported RXFILTER type %d", type);
6836 break;
6837 }
6838
6839 return ret;
6840}
6841
6842/**
6843 * drv_cmd_rx_filter_remove() - RXFILTER REMOVE driver command handler
6844 * @adapter: Pointer to network adapter
6845 * @hdd_ctx: Pointer to hdd context
6846 * @command: Pointer to input command
6847 * @command_len: Command length
6848 * @priv_data: Pointer to private data in command
6849 */
6850static int drv_cmd_rx_filter_remove(hdd_adapter_t *adapter,
6851 hdd_context_t *hdd_ctx,
6852 uint8_t *command,
6853 uint8_t command_len,
6854 hdd_priv_data_t *priv_data)
6855{
6856 return hdd_driver_rxfilter_comand_handler(command, adapter, false);
6857}
6858
6859/**
6860 * drv_cmd_rx_filter_add() - RXFILTER ADD driver command handler
6861 * @adapter: Pointer to network adapter
6862 * @hdd_ctx: Pointer to hdd context
6863 * @command: Pointer to input command
6864 * @command_len: Command length
6865 * @priv_data: Pointer to private data in command
6866 */
6867static int drv_cmd_rx_filter_add(hdd_adapter_t *adapter,
6868 hdd_context_t *hdd_ctx,
6869 uint8_t *command,
6870 uint8_t command_len,
6871 hdd_priv_data_t *priv_data)
6872{
6873 return hdd_driver_rxfilter_comand_handler(command, adapter, true);
6874}
6875
Archana Ramachandran393f3792015-11-13 17:13:21 -08006876/**
6877 * hdd_parse_setantennamode_command() - HDD Parse SETANTENNAMODE
6878 * command
6879 * @value: Pointer to SETANTENNAMODE command
6880 * @mode: Pointer to antenna mode
6881 * @reason: Pointer to reason for set antenna mode
6882 *
6883 * This function parses the SETANTENNAMODE command passed in the format
6884 * SETANTENNAMODE<space>mode
6885 *
6886 * Return: 0 for success non-zero for failure
6887 */
6888static int hdd_parse_setantennamode_command(const uint8_t *value)
6889{
6890 const uint8_t *in_ptr = value;
6891 int tmp, v;
6892 char arg1[32];
6893
6894 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
6895
6896 /* no argument after the command */
6897 if (NULL == in_ptr) {
6898 hddLog(LOGE, FL("No argument after the command"));
6899 return -EINVAL;
6900 }
6901
6902 /* no space after the command */
6903 if (SPACE_ASCII_VALUE != *in_ptr) {
6904 hddLog(LOGE, FL("No space after the command"));
6905 return -EINVAL;
6906 }
6907
6908 /* remove empty spaces */
6909 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
6910 in_ptr++;
6911
6912 /* no argument followed by spaces */
6913 if ('\0' == *in_ptr) {
6914 hddLog(LOGE, FL("No argument followed by spaces"));
6915 return -EINVAL;
6916 }
6917
6918 /* get the argument i.e. antenna mode */
6919 v = sscanf(in_ptr, "%31s ", arg1);
6920 if (1 != v) {
6921 hddLog(LOGE, FL("argument retrieval from cmd string failed"));
6922 return -EINVAL;
6923 }
6924
6925 v = kstrtos32(arg1, 10, &tmp);
6926 if (v < 0) {
6927 hddLog(LOGE, FL("argument string to int conversion failed"));
6928 return -EINVAL;
6929 }
6930
6931 return tmp;
6932}
6933
6934/**
6935 * hdd_is_supported_chain_mask_2x2() - Verify if supported chain
6936 * mask is 2x2 mode
6937 * @hdd_ctx: Pointer to hdd contex
6938 *
6939 * Return: true if supported chain mask 2x2 else false
6940 */
6941static bool hdd_is_supported_chain_mask_2x2(hdd_context_t *hdd_ctx)
6942{
6943 /*
6944 * Revisit and the update logic to determine the number
6945 * of TX/RX chains supported in the system when
6946 * antenna sharing per band chain mask support is
6947 * brought in
6948 */
6949 return (hdd_ctx->config->enable2x2 == 0x01) ? true : false;
6950}
6951
6952/**
6953 * hdd_is_supported_chain_mask_1x1() - Verify if the supported
6954 * chain mask is 1x1
6955 * @hdd_ctx: Pointer to hdd contex
6956 *
6957 * Return: true if supported chain mask 1x1 else false
6958 */
6959static bool hdd_is_supported_chain_mask_1x1(hdd_context_t *hdd_ctx)
6960{
6961 /*
6962 * Revisit and update the logic to determine the number
6963 * of TX/RX chains supported in the system when
6964 * antenna sharing per band chain mask support is
6965 * brought in
6966 */
6967 return (!hdd_ctx->config->enable2x2) ? true : false;
6968}
6969
6970/**
6971 * drv_cmd_set_antenna_mode() - SET ANTENNA MODE driver command
6972 * handler
6973 * @adapter: Pointer to network adapter
6974 * @hdd_ctx: Pointer to hdd context
6975 * @command: Pointer to input command
6976 * @command_len: Command length
6977 * @priv_data: Pointer to private data in command
6978 */
6979static int drv_cmd_set_antenna_mode(hdd_adapter_t *adapter,
6980 hdd_context_t *hdd_ctx,
6981 uint8_t *command,
6982 uint8_t command_len,
6983 hdd_priv_data_t *priv_data)
6984{
6985 struct sir_antenna_mode_param params;
6986 QDF_STATUS status;
6987 int ret = 0;
6988 int mode;
6989 uint8_t *value = command;
6990 uint8_t smps_mode;
6991 uint8_t smps_enable;
6992
6993 if (((1 << QDF_STA_MODE) != hdd_ctx->concurrency_mode) ||
6994 (hdd_ctx->no_of_active_sessions[QDF_STA_MODE] > 1)) {
6995 hdd_err("Operation invalid in non sta or concurrent mode");
6996 ret = -EPERM;
6997 goto exit;
6998 }
6999
7000 mode = hdd_parse_setantennamode_command(value);
7001 if (mode < 0) {
7002 hdd_err("Invalid SETANTENNA command");
7003 ret = mode;
7004 goto exit;
7005 }
7006
7007 hdd_info("Processing antenna mode switch to: %d", mode);
7008
7009 if (hdd_ctx->current_antenna_mode == mode) {
7010 hdd_err("System already in the requested mode");
7011 ret = 0;
7012 goto exit;
7013 }
7014
7015 if ((HDD_ANTENNA_MODE_2X2 == mode) &&
7016 (!hdd_is_supported_chain_mask_2x2(hdd_ctx))) {
7017 hdd_err("System does not support 2x2 mode");
7018 ret = -EPERM;
7019 goto exit;
7020 }
7021
7022 if ((HDD_ANTENNA_MODE_1X1 == mode) &&
7023 hdd_is_supported_chain_mask_1x1(hdd_ctx)) {
7024 hdd_err("System only supports 1x1 mode");
7025 ret = 0;
7026 goto exit;
7027 }
7028
7029 switch (mode) {
7030 case HDD_ANTENNA_MODE_1X1:
7031 params.num_rx_chains = 1;
7032 params.num_tx_chains = 1;
7033 break;
7034 case HDD_ANTENNA_MODE_2X2:
7035 params.num_rx_chains = 2;
7036 params.num_tx_chains = 2;
7037 break;
7038 default:
7039 hdd_err("unsupported antenna mode");
7040 ret = -EINVAL;
7041 goto exit;
7042 }
7043
7044 params.set_antenna_mode_resp =
7045 (void *)wlan_hdd_soc_set_antenna_mode_cb;
7046 hdd_info("Set antenna mode rx chains: %d tx chains: %d",
7047 params.num_rx_chains,
7048 params.num_tx_chains);
7049
7050
7051 INIT_COMPLETION(hdd_ctx->set_antenna_mode_cmpl);
7052 status = sme_soc_set_antenna_mode(hdd_ctx->hHal, &params);
7053 if (QDF_STATUS_SUCCESS != status) {
7054 hdd_err("set antenna mode failed status : %d", status);
7055 ret = -EFAULT;
7056 goto exit;
7057 }
7058
7059 ret = wait_for_completion_timeout(
7060 &hdd_ctx->set_antenna_mode_cmpl,
7061 msecs_to_jiffies(WLAN_WAIT_TIME_ANTENNA_MODE_REQ));
7062 if (!ret) {
7063 ret = -EFAULT;
7064 hdd_err("send set antenna mode timed out");
7065 goto exit;
7066 }
7067
7068 /* Update SME SMPS config */
7069 if (HDD_ANTENNA_MODE_1X1 == mode) {
7070 smps_enable = true;
7071 smps_mode = HDD_SMPS_MODE_STATIC;
7072 } else {
7073 smps_enable = false;
7074 smps_mode = HDD_SMPS_MODE_DISABLED;
7075 }
7076
7077 hdd_info("Update SME SMPS enable: %d mode: %d",
7078 smps_enable, smps_mode);
7079 status = sme_update_mimo_power_save(
7080 hdd_ctx->hHal, smps_enable, smps_mode, false);
7081 if (QDF_STATUS_SUCCESS != status) {
7082 hdd_err("Update SMPS config failed enable: %d mode: %d status: %d",
7083 smps_enable, smps_mode, status);
7084 ret = -EFAULT;
7085 goto exit;
7086 }
7087
7088 hdd_info("Successfully switched to mode: %d x %d", mode, mode);
7089 ret = 0;
7090 hdd_ctx->current_antenna_mode = mode;
7091
7092exit:
7093 hdd_info("Set antenna status: %d current mode: %d",
7094 ret, hdd_ctx->current_antenna_mode);
7095 return ret;
7096
7097}
7098
7099/**
7100 * drv_cmd_get_antenna_mode() - GET ANTENNA MODE driver command
7101 * handler
7102 * @adapter: Pointer to hdd adapter
7103 * @hdd_ctx: Pointer to hdd context
7104 * @command: Pointer to input command
7105 * @command_len: length of the command
7106 * @priv_data: private data coming with the driver command
7107 *
7108 * Return: 0 for success non-zero for failure
7109 */
7110static inline int drv_cmd_get_antenna_mode(hdd_adapter_t *adapter,
7111 hdd_context_t *hdd_ctx,
7112 uint8_t *command,
7113 uint8_t command_len,
7114 hdd_priv_data_t *priv_data)
7115{
7116 uint32_t antenna_mode = 0;
7117 char extra[32];
7118 uint8_t len = 0;
7119
7120 antenna_mode = hdd_ctx->current_antenna_mode;
7121 len = scnprintf(extra, sizeof(extra), "%s %d", command,
7122 antenna_mode);
7123 len = QDF_MIN(priv_data->total_len, len + 1);
7124 if (copy_to_user(priv_data->buf, &extra, len)) {
7125 hdd_err("Failed to copy data to user buffer");
7126 return -EFAULT;
7127 }
7128
7129 hdd_info("Get antenna mode: %d", antenna_mode);
7130
7131 return 0;
7132}
7133
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007134/*
7135 * dummy (no-op) hdd driver command handler
7136 */
7137static int drv_cmd_dummy(hdd_adapter_t *adapter,
7138 hdd_context_t *hdd_ctx,
7139 uint8_t *command,
7140 uint8_t command_len,
7141 hdd_priv_data_t *priv_data)
7142{
7143 hdd_info("%s: Ignoring driver command \"%s\"",
7144 adapter->dev->name, command);
7145 return 0;
7146}
7147
7148/*
7149 * handler for any unsupported wlan hdd driver command
7150 */
7151static int drv_cmd_invalid(hdd_adapter_t *adapter,
7152 hdd_context_t *hdd_ctx,
7153 uint8_t *command,
7154 uint8_t command_len,
7155 hdd_priv_data_t *priv_data)
7156{
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05307157 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007158 TRACE_CODE_HDD_UNSUPPORTED_IOCTL,
7159 adapter->sessionId, 0));
7160
7161 hdd_warn("%s: Unsupported driver command \"%s\"",
7162 adapter->dev->name, command);
7163
7164 return -ENOTSUPP;
7165}
7166
7167/**
7168 * drv_cmd_set_fcc_channel() - handle fcc constraint request
7169 * @adapter: HDD adapter
7170 * @hdd_ctx: HDD context
7171 * @command: command ptr, SET_FCC_CHANNEL 0/1 is the command
7172 * @command_len: command len
7173 * @priv_data: private data
7174 *
7175 * Return: status
7176 */
7177static int drv_cmd_set_fcc_channel(hdd_adapter_t *adapter,
7178 hdd_context_t *hdd_ctx,
7179 uint8_t *command,
7180 uint8_t command_len,
7181 hdd_priv_data_t *priv_data)
7182{
7183 uint8_t *value;
7184 uint8_t fcc_constraint;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05307185 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007186 int ret = 0;
7187
7188 /*
7189 * this command would be called by user-space when it detects WLAN
7190 * ON after airplane mode is set. When APM is set, WLAN turns off.
7191 * But it can be turned back on. Otherwise; when APM is turned back
7192 * off, WLAN would turn back on. So at that point the command is
7193 * expected to come down. 0 means disable, 1 means enable. The
7194 * constraint is removed when parameter 1 is set or different
7195 * country code is set
7196 */
7197
7198 value = command + command_len + 1;
7199
7200 ret = kstrtou8(value, 10, &fcc_constraint);
7201 if ((ret < 0) || (fcc_constraint > 1)) {
7202 /*
7203 * If the input value is greater than max value of datatype,
7204 * then also it is a failure
7205 */
7206 hdd_err("value out of range");
7207 return -EINVAL;
7208 }
7209
7210 status = sme_disable_non_fcc_channel(hdd_ctx->hHal, !fcc_constraint);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05307211 if (status != QDF_STATUS_SUCCESS) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007212 hdd_err("sme disable fn. returned err");
7213 ret = -EPERM;
7214 }
7215
7216 return ret;
7217}
7218
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307219/**
7220 * hdd_parse_set_channel_switch_command() - Parse and validate CHANNEL_SWITCH
7221 * command
7222 * @value: Pointer to the command
7223 * @chan_number: Pointer to the channel number
7224 * @chan_bw: Pointer to the channel bandwidth
7225 *
7226 * Parses and provides the channel number and channel width from the input
7227 * command which is expected to be of the format: CHANNEL_SWITCH <CH> <BW>
7228 * <CH> is channel number to move (where 1 = channel 1, 149 = channel 149, ...)
7229 * <BW> is bandwidth to move (where 20 = BW 20, 40 = BW 40, 80 = BW 80)
7230 *
7231 * Return: 0 for success, non-zero for failure
7232 */
7233static int hdd_parse_set_channel_switch_command(uint8_t *value,
7234 uint32_t *chan_number,
7235 uint32_t *chan_bw)
7236{
7237 const uint8_t *in_ptr = value;
7238 int ret;
7239
7240 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
7241
7242 /* no argument after the command */
7243 if (NULL == in_ptr) {
7244 hdd_err("No argument after the command");
7245 return -EINVAL;
7246 }
7247
7248 /* no space after the command */
7249 if (SPACE_ASCII_VALUE != *in_ptr) {
7250 hdd_err("No space after the command ");
7251 return -EINVAL;
7252 }
7253
7254 /* remove empty spaces and move the next argument */
7255 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
7256 in_ptr++;
7257
7258 /* no argument followed by spaces */
7259 if ('\0' == *in_ptr) {
7260 hdd_err("No argument followed by spaces");
7261 return -EINVAL;
7262 }
7263
7264 /* get the two arguments: channel number and bandwidth */
7265 ret = sscanf(in_ptr, "%u %u", chan_number, chan_bw);
7266 if (ret != 2) {
7267 hdd_err("Arguments retrieval from cmd string failed");
7268 return -EINVAL;
7269 }
7270
7271 return 0;
7272}
7273
7274/**
7275 * drv_cmd_set_channel_switch() - Switch SAP/P2P-GO operating channel
7276 * @adapter: HDD adapter
7277 * @hdd_ctx: HDD context
7278 * @command: Pointer to the input command CHANNEL_SWITCH
7279 * @command_len: Command len
7280 * @priv_data: Private data
7281 *
7282 * Handles private IOCTL CHANNEL_SWITCH command to switch the operating channel
7283 * of SAP/P2P-GO
7284 *
7285 * Return: 0 for success, non-zero for failure
7286 */
7287static int drv_cmd_set_channel_switch(hdd_adapter_t *adapter,
7288 hdd_context_t *hdd_ctx,
7289 uint8_t *command,
7290 uint8_t command_len,
7291 hdd_priv_data_t *priv_data)
7292{
7293 struct net_device *dev = adapter->dev;
7294 int status;
7295 uint32_t chan_number = 0, chan_bw = 0;
7296 uint8_t *value = command;
Kiran Kumar Lokere13644672016-02-29 15:40:10 -08007297 enum phy_ch_width width;
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307298
Krunal Sonibe766b02016-03-10 13:00:44 -08007299 if ((adapter->device_mode != QDF_P2P_GO_MODE) &&
7300 (adapter->device_mode != QDF_SAP_MODE)) {
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307301 hdd_err("IOCTL CHANNEL_SWITCH not supported for mode %d",
7302 adapter->device_mode);
7303 return -EINVAL;
7304 }
7305
7306 status = hdd_parse_set_channel_switch_command(value,
7307 &chan_number, &chan_bw);
7308 if (status) {
7309 hdd_err("Invalid CHANNEL_SWITCH command");
7310 return status;
7311 }
7312
7313 if ((chan_bw != 20) && (chan_bw != 40) && (chan_bw != 80)) {
7314 hdd_err("BW %d is not allowed for CHANNEL_SWITCH", chan_bw);
7315 return -EINVAL;
7316 }
7317
7318 if (chan_bw == 80)
7319 width = CH_WIDTH_80MHZ;
7320 else if (chan_bw == 40)
7321 width = CH_WIDTH_40MHZ;
7322 else
7323 width = CH_WIDTH_20MHZ;
7324
7325 hdd_info("CH:%d BW:%d", chan_number, chan_bw);
7326
7327 status = hdd_softap_set_channel_change(dev, chan_number, width);
7328 if (status) {
7329 hdd_err("Set channel change fail");
7330 return status;
7331 }
7332
7333 return 0;
7334}
7335
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007336/*
7337 * The following table contains all supported WLAN HDD
7338 * IOCTL driver commands and the handler for each of them.
7339 */
7340static const hdd_drv_cmd_t hdd_drv_cmds[] = {
7341 {"P2P_DEV_ADDR", drv_cmd_p2p_dev_addr},
7342 {"P2P_SET_NOA", drv_cmd_p2p_set_noa},
7343 {"P2P_SET_PS", drv_cmd_p2p_set_ps},
7344 {"SETBAND", drv_cmd_set_band},
7345 {"SETWMMPS", drv_cmd_set_wmmps},
7346 {"COUNTRY", drv_cmd_country},
7347 {"SETSUSPENDMODE", drv_cmd_dummy},
7348 {"SET_AP_WPS_P2P_IE", drv_cmd_dummy},
7349 {"BTCOEXSCAN", drv_cmd_dummy},
7350 {"RXFILTER", drv_cmd_dummy},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007351 {"SETROAMTRIGGER", drv_cmd_set_roam_trigger},
7352 {"GETROAMTRIGGER", drv_cmd_get_roam_trigger},
7353 {"SETROAMSCANPERIOD", drv_cmd_set_roam_scan_period},
7354 {"GETROAMSCANPERIOD", drv_cmd_get_roam_scan_period},
7355 {"SETROAMSCANREFRESHPERIOD", drv_cmd_set_roam_scan_refresh_period},
7356 {"GETROAMSCANREFRESHPERIOD", drv_cmd_get_roam_scan_refresh_period},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007357 {"SETROAMMODE", drv_cmd_set_roam_mode},
7358 {"GETROAMMODE", drv_cmd_get_roam_mode},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007359 {"SETROAMDELTA", drv_cmd_set_roam_delta},
7360 {"GETROAMDELTA", drv_cmd_get_roam_delta},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007361 {"GETBAND", drv_cmd_get_band},
7362 {"SETROAMSCANCHANNELS", drv_cmd_set_roam_scan_channels},
7363 {"GETROAMSCANCHANNELS", drv_cmd_get_roam_scan_channels},
7364 {"GETCCXMODE", drv_cmd_get_ccx_mode},
7365 {"GETOKCMODE", drv_cmd_get_okc_mode},
7366 {"GETFASTROAM", drv_cmd_get_fast_roam},
7367 {"GETFASTTRANSITION", drv_cmd_get_fast_transition},
7368 {"SETROAMSCANCHANNELMINTIME", drv_cmd_set_roam_scan_channel_min_time},
7369 {"SENDACTIONFRAME", drv_cmd_send_action_frame},
7370 {"GETROAMSCANCHANNELMINTIME", drv_cmd_get_roam_scan_channel_min_time},
7371 {"SETSCANCHANNELTIME", drv_cmd_set_scan_channel_time},
7372 {"GETSCANCHANNELTIME", drv_cmd_get_scan_channel_time},
7373 {"SETSCANHOMETIME", drv_cmd_set_scan_home_time},
7374 {"GETSCANHOMETIME", drv_cmd_get_scan_home_time},
7375 {"SETROAMINTRABAND", drv_cmd_set_roam_intra_band},
7376 {"GETROAMINTRABAND", drv_cmd_get_roam_intra_band},
7377 {"SETSCANNPROBES", drv_cmd_set_scan_n_probes},
7378 {"GETSCANNPROBES", drv_cmd_get_scan_n_probes},
7379 {"SETSCANHOMEAWAYTIME", drv_cmd_set_scan_home_away_time},
7380 {"GETSCANHOMEAWAYTIME", drv_cmd_get_scan_home_away_time},
7381 {"REASSOC", drv_cmd_reassoc},
7382 {"SETWESMODE", drv_cmd_set_wes_mode},
7383 {"GETWESMODE", drv_cmd_get_wes_mode},
7384 {"SETOPPORTUNISTICRSSIDIFF", drv_cmd_set_opportunistic_rssi_diff},
7385 {"GETOPPORTUNISTICRSSIDIFF", drv_cmd_get_opportunistic_rssi_diff},
7386 {"SETROAMRESCANRSSIDIFF", drv_cmd_set_roam_rescan_rssi_diff},
7387 {"GETROAMRESCANRSSIDIFF", drv_cmd_get_roam_rescan_rssi_diff},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007388 {"SETFASTROAM", drv_cmd_set_fast_roam},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007389 {"SETFASTTRANSITION", drv_cmd_set_fast_transition},
7390 {"FASTREASSOC", drv_cmd_fast_reassoc},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007391 {"SETROAMSCANCONTROL", drv_cmd_set_roam_scan_control},
7392#ifdef FEATURE_WLAN_OKC
7393 {"SETOKCMODE", drv_cmd_set_okc_mode},
7394#endif /* FEATURE_WLAN_OKC */
7395 {"GETROAMSCANCONTROL", drv_cmd_get_roam_scan_control},
7396 {"BTCOEXMODE", drv_cmd_bt_coex_mode},
7397 {"SCAN-ACTIVE", drv_cmd_scan_active},
7398 {"SCAN-PASSIVE", drv_cmd_scan_passive},
7399 {"GETDWELLTIME", drv_cmd_get_dwell_time},
7400 {"SETDWELLTIME", drv_cmd_set_dwell_time},
7401 {"MIRACAST", drv_cmd_miracast},
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08007402 {"SETIBSSBEACONOUIDATA", drv_cmd_set_ibss_beacon_oui_data},
7403 {"SETRMCENABLE", drv_cmd_set_rmc_enable},
7404 {"SETRMCACTIONPERIOD", drv_cmd_set_rmc_action_period},
7405 {"GETIBSSPEERINFOALL", drv_cmd_get_ibss_peer_info_all},
7406 {"GETIBSSPEERINFO", drv_cmd_get_ibss_peer_info},
7407 {"SETRMCTXRATE", drv_cmd_set_rmc_tx_rate},
7408 {"SETIBSSTXFAILEVENT", drv_cmd_set_ibss_tx_fail_event},
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08007409#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007410 {"SETCCXROAMSCANCHANNELS", drv_cmd_set_ccx_roam_scan_channels},
7411 {"GETTSMSTATS", drv_cmd_get_tsm_stats},
7412 {"SETCCKMIE", drv_cmd_set_cckm_ie},
7413 {"CCXBEACONREQ", drv_cmd_ccx_beacon_req},
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08007414#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007415 {"SETMCRATE", drv_cmd_set_mc_rate},
7416 {"MAXTXPOWER", drv_cmd_max_tx_power},
7417 {"SETDFSSCANMODE", drv_cmd_set_dfs_scan_mode},
7418 {"GETDFSSCANMODE", drv_cmd_get_dfs_scan_mode},
7419 {"GETLINKSTATUS", drv_cmd_get_link_status},
7420#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
7421 {"ENABLEEXTWOW", drv_cmd_enable_ext_wow},
7422 {"SETAPP1PARAMS", drv_cmd_set_app1_params},
7423 {"SETAPP2PARAMS", drv_cmd_set_app2_params},
7424#endif
7425#ifdef FEATURE_WLAN_TDLS
7426 {"TDLSSECONDARYCHANNELOFFSET", drv_cmd_tdls_secondary_channel_offset},
7427 {"TDLSOFFCHANNELMODE", drv_cmd_tdls_off_channel_mode},
7428 {"TDLSOFFCHANNEL", drv_cmd_tdls_off_channel},
7429 {"TDLSSCAN", drv_cmd_tdls_scan},
7430#endif
7431 {"RSSI", drv_cmd_get_rssi},
7432 {"LINKSPEED", drv_cmd_get_linkspeed},
7433#ifdef FEATURE_NAPI
7434 {"NAPI", drv_cmd_napi},
7435#endif /* FEATURE_NAPI */
7436 {"RXFILTER-REMOVE", drv_cmd_rx_filter_remove},
7437 {"RXFILTER-ADD", drv_cmd_rx_filter_add},
7438 {"SET_FCC_CHANNEL", drv_cmd_set_fcc_channel},
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307439 {"CHANNEL_SWITCH", drv_cmd_set_channel_switch},
Archana Ramachandran393f3792015-11-13 17:13:21 -08007440 {"SETANTENNAMODE", drv_cmd_set_antenna_mode},
7441 {"GETANTENNAMODE", drv_cmd_get_antenna_mode},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007442};
7443
7444/**
7445 * hdd_drv_cmd_process() - chooses and runs the proper
7446 * handler based on the input command
7447 * @adapter: Pointer to the hdd adapter
7448 * @cmd: Pointer to the driver command
7449 * @priv_data: Pointer to the data associated with the command
7450 *
7451 * This function parses the input hdd driver command and runs
7452 * the proper handler
7453 *
7454 * Return: 0 for success non-zero for failure
7455 */
7456static int hdd_drv_cmd_process(hdd_adapter_t *adapter,
7457 uint8_t *cmd,
7458 hdd_priv_data_t *priv_data)
7459{
7460 hdd_context_t *hdd_ctx;
7461 int i;
7462 const int cmd_num_total = ARRAY_SIZE(hdd_drv_cmds);
7463 uint8_t *cmd_i = NULL;
7464 hdd_drv_cmd_handler_t handler = NULL;
7465 int len = 0;
7466
7467 if (!adapter || !cmd || !priv_data) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05307468 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007469 "%s: at least 1 param is NULL", __func__);
7470 return -EINVAL;
7471 }
7472
7473 hdd_ctx = (hdd_context_t *)adapter->pHddCtx;
7474
7475 for (i = 0; i < cmd_num_total; i++) {
7476
7477 cmd_i = (uint8_t *)hdd_drv_cmds[i].cmd;
7478 handler = hdd_drv_cmds[i].handler;
7479 len = strlen(cmd_i);
7480
7481 if (!handler) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05307482 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007483 "%s: no. %d handler is NULL", __func__, i);
7484 return -EINVAL;
7485 }
7486
7487 if (strncasecmp(cmd, cmd_i, len) == 0)
7488 return handler(adapter, hdd_ctx,
7489 cmd, len, priv_data);
7490 }
7491
7492 return drv_cmd_invalid(adapter, hdd_ctx, cmd, len, priv_data);
7493}
7494
7495/**
7496 * hdd_driver_command() - top level wlan hdd driver command handler
7497 * @adapter: Pointer to the hdd adapter
7498 * @priv_data: Pointer to the raw command data
7499 *
7500 * This function is the top level wlan hdd driver command handler. It
7501 * handles the command with the help of hdd_drv_cmd_process()
7502 *
7503 * Return: 0 for success non-zero for failure
7504 */
7505static int hdd_driver_command(hdd_adapter_t *adapter,
7506 hdd_priv_data_t *priv_data)
7507{
7508 uint8_t *command = NULL;
7509 int ret = 0;
7510
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307511 ENTER();
7512
Anurag Chouhan6d760662016-02-20 16:05:43 +05307513 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007514 hddLog(LOGE, FL("Command not allowed in FTM mode"));
7515 return -EINVAL;
7516 }
7517
7518 /*
7519 * Note that valid pointers are provided by caller
7520 */
7521
7522 /* copy to local struct to avoid numerous changes to legacy code */
7523 if (priv_data->total_len <= 0 ||
7524 priv_data->total_len > WLAN_PRIV_DATA_MAX_LEN) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05307525 hddLog(QDF_TRACE_LEVEL_WARN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007526 "%s:invalid priv_data.total_len(%d)!!!", __func__,
7527 priv_data->total_len);
7528 ret = -EINVAL;
7529 goto exit;
7530 }
7531
7532 /* Allocate +1 for '\0' */
7533 command = kmalloc(priv_data->total_len + 1, GFP_KERNEL);
7534 if (!command) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05307535 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007536 "%s: failed to allocate memory", __func__);
7537 ret = -ENOMEM;
7538 goto exit;
7539 }
7540
7541 if (copy_from_user(command, priv_data->buf, priv_data->total_len)) {
7542 ret = -EFAULT;
7543 goto exit;
7544 }
7545
7546 /* Make sure the command is NUL-terminated */
7547 command[priv_data->total_len] = '\0';
7548
7549 hdd_info("%s: %s", adapter->dev->name, command);
7550 ret = hdd_drv_cmd_process(adapter, command, priv_data);
7551
7552exit:
7553 if (command)
7554 kfree(command);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307555 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007556 return ret;
7557}
7558
7559#ifdef CONFIG_COMPAT
7560static int hdd_driver_compat_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
7561{
7562 struct {
7563 compat_uptr_t buf;
7564 int used_len;
7565 int total_len;
7566 } compat_priv_data;
7567 hdd_priv_data_t priv_data;
7568 int ret = 0;
7569
7570 /*
7571 * Note that adapter and ifr have already been verified by caller,
7572 * and HDD context has also been validated
7573 */
7574 if (copy_from_user(&compat_priv_data, ifr->ifr_data,
7575 sizeof(compat_priv_data))) {
7576 ret = -EFAULT;
7577 goto exit;
7578 }
7579 priv_data.buf = compat_ptr(compat_priv_data.buf);
7580 priv_data.used_len = compat_priv_data.used_len;
7581 priv_data.total_len = compat_priv_data.total_len;
7582 ret = hdd_driver_command(adapter, &priv_data);
7583exit:
7584 return ret;
7585}
7586#else /* CONFIG_COMPAT */
7587static int hdd_driver_compat_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
7588{
7589 /* will never be invoked */
7590 return 0;
7591}
7592#endif /* CONFIG_COMPAT */
7593
7594static int hdd_driver_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
7595{
7596 hdd_priv_data_t priv_data;
7597 int ret = 0;
7598
7599 /*
7600 * Note that adapter and ifr have already been verified by caller,
7601 * and HDD context has also been validated
7602 */
7603 if (copy_from_user(&priv_data, ifr->ifr_data, sizeof(priv_data)))
7604 ret = -EFAULT;
7605 else
7606 ret = hdd_driver_command(adapter, &priv_data);
7607
7608 return ret;
7609}
7610
7611/**
7612 * __hdd_ioctl() - ioctl handler for wlan network interfaces
7613 * @dev: device upon which the ioctl was received
7614 * @ifr: ioctl request information
7615 * @cmd: ioctl command
7616 *
7617 * This function does initial processing of wlan device ioctls.
7618 * Currently two flavors of ioctls are supported. The primary ioctl
7619 * that is supported is the (SIOCDEVPRIVATE + 1) ioctl which is used
7620 * for Android "DRIVER" commands. The other ioctl that is
7621 * conditionally supported is the SIOCIOCTLTX99 ioctl which is used
7622 * for FTM on some platforms. This function simply verifies that the
7623 * driver is in a sane state, and that the ioctl is one of the
7624 * supported flavors, in which case flavor-specific handlers are
7625 * dispatched.
7626 *
7627 * Return: 0 on success, non-zero on error
7628 */
7629static int __hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7630{
7631 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
7632 hdd_context_t *hdd_ctx;
7633 int ret;
7634
Jeff Johnson3c3994a2016-02-11 08:12:30 -08007635 ENTER_DEV(dev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307636
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007637 if (dev != adapter->dev) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05307638 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_FATAL,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007639 "%s: HDD adapter/dev inconsistency", __func__);
7640 ret = -ENODEV;
7641 goto exit;
7642 }
7643
7644 if ((!ifr) || (!ifr->ifr_data)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05307645 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007646 "%s: invalid data", __func__);
7647 ret = -EINVAL;
7648 goto exit;
7649 }
7650#if defined(QCA_WIFI_FTM) && defined(LINUX_QCMBR)
Anurag Chouhan6d760662016-02-20 16:05:43 +05307651 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007652 if (SIOCIOCTLTX99 == cmd) {
7653 ret = wlan_hdd_qcmbr_unified_ioctl(adapter, ifr);
7654 goto exit;
7655 }
7656 }
7657#endif
7658
7659 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
7660 ret = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307661 if (ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007662 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007663
7664 switch (cmd) {
7665 case (SIOCDEVPRIVATE + 1):
7666 if (is_compat_task())
7667 ret = hdd_driver_compat_ioctl(adapter, ifr);
7668 else
7669 ret = hdd_driver_ioctl(adapter, ifr);
7670 break;
7671 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05307672 hddLog(QDF_TRACE_LEVEL_ERROR, "%s: unknown ioctl %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007673 __func__, cmd);
7674 ret = -EINVAL;
7675 break;
7676 }
7677exit:
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307678 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007679 return ret;
7680}
7681
7682/**
7683 * hdd_ioctl() - ioctl handler (wrapper) for wlan network interfaces
7684 * @dev: device upon which the ioctl was received
7685 * @ifr: ioctl request information
7686 * @cmd: ioctl command
7687 *
7688 * This function acts as an SSR-protecting wrapper to __hdd_ioctl()
7689 * which is where the ioctls are really handled.
7690 *
7691 * Return: 0 on success, non-zero on error
7692 */
7693int hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7694{
7695 int ret;
7696
7697 cds_ssr_protect(__func__);
7698 ret = __hdd_ioctl(dev, ifr, cmd);
7699 cds_ssr_unprotect(__func__);
7700 return ret;
7701}