blob: 9723486740e3c7e0c18bbdb4c04accfb61079123 [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/**
426 * hdd_cfg80211_get_ibss_peer_info_cb() - Callback function for IBSS
427 * Peer Info request
428 * @pUserData: Adapter private data
429 * @pPeerInfoRsp: Peer info response
430 *
431 * This is an asynchronous callback function from SME when the peer info
432 * is received
433 *
434 * Return: 0 for success non-zero for failure
435 */
436static void
437hdd_cfg80211_get_ibss_peer_info_cb(void *pUserData, void *pPeerInfoRsp)
438{
439 hdd_adapter_t *adapter = (hdd_adapter_t *) pUserData;
440 hdd_ibss_peer_info_t *pPeerInfo = (hdd_ibss_peer_info_t *)pPeerInfoRsp;
441 hdd_station_ctx_t *pStaCtx;
442 uint8_t i;
443
444 /* Sanity check */
445 if ((NULL == adapter) ||
446 (WLAN_HDD_ADAPTER_MAGIC != adapter->magic)) {
447 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_FATAL,
448 "invalid adapter or adapter has invalid magic");
449 return;
450 }
451
452 pStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
453 if (NULL != pPeerInfo && QDF_STATUS_SUCCESS == pPeerInfo->status) {
454 pStaCtx->ibss_peer_info.status = pPeerInfo->status;
455 pStaCtx->ibss_peer_info.numIBSSPeers = pPeerInfo->numIBSSPeers;
456
457 /* Paranoia check */
458 if (pPeerInfo->numIBSSPeers < MAX_IBSS_PEERS) {
459 for (i = 0; i < pPeerInfo->numIBSSPeers; i++) {
460 memcpy(&pStaCtx->ibss_peer_info.ibssPeerList[i],
461 &pPeerInfo->ibssPeerList[i],
462 sizeof(hdd_ibss_peer_info_params_t));
463 }
464 hddLog(LOG1, FL("Peer Info copied in HDD"));
465 } else {
466 hddLog(LOG1,
467 FL("Number of peers %d returned is more than limit %d"),
468 pPeerInfo->numIBSSPeers, MAX_IBSS_PEERS);
469 }
470 } else {
471 hddLog(LOG1, FL("peerInfo returned is NULL"));
472 }
473
474 complete(&adapter->ibss_peer_info_comp);
475}
476
477/**
478 * hdd_cfg80211_get_ibss_peer_info_all() - get ibss peers' info
479 * @adapter: Adapter context
480 *
481 * Request function to get IBSS peer info from lower layers
482 *
483 * Return: 0 for success non-zero for failure
484 */
485static
486QDF_STATUS hdd_cfg80211_get_ibss_peer_info_all(hdd_adapter_t *adapter)
487{
488 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
489 QDF_STATUS retStatus = QDF_STATUS_E_FAILURE;
490 unsigned long rc;
491
492 INIT_COMPLETION(adapter->ibss_peer_info_comp);
493
494 retStatus = sme_request_ibss_peer_info(hHal, adapter,
495 hdd_cfg80211_get_ibss_peer_info_cb,
496 true, 0xFF);
497
498 if (QDF_STATUS_SUCCESS == retStatus) {
499 rc = wait_for_completion_timeout
500 (&adapter->ibss_peer_info_comp,
501 msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT));
502
503 /* status will be 0 if timed out */
504 if (!rc) {
505 hddLog(QDF_TRACE_LEVEL_WARN,
506 "%s: Warning: IBSS_PEER_INFO_TIMEOUT",
507 __func__);
508 retStatus = QDF_STATUS_E_FAILURE;
509 return retStatus;
510 }
511 } else {
512 hddLog(QDF_TRACE_LEVEL_WARN,
513 "%s: Warning: sme_request_ibss_peer_info Request failed",
514 __func__);
515 }
516
517 return retStatus;
518}
519
520/**
521 * hdd_cfg80211_get_ibss_peer_info() - get ibss peer info
522 * @adapter: Adapter context
523 * @staIdx: Sta index for which the peer info is requested
524 *
525 * Request function to get IBSS peer info from lower layers
526 *
527 * Return: 0 for success non-zero for failure
528 */
529static QDF_STATUS
530hdd_cfg80211_get_ibss_peer_info(hdd_adapter_t *adapter, uint8_t staIdx)
531{
532 unsigned long rc;
533 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
534 QDF_STATUS retStatus = QDF_STATUS_E_FAILURE;
535
536 INIT_COMPLETION(adapter->ibss_peer_info_comp);
537
538 retStatus = sme_request_ibss_peer_info(hHal, adapter,
539 hdd_cfg80211_get_ibss_peer_info_cb,
540 false, staIdx);
541
542 if (QDF_STATUS_SUCCESS == retStatus) {
543 rc = wait_for_completion_timeout(
544 &adapter->ibss_peer_info_comp,
545 msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT));
546
547 /* status = 0 on timeout */
548 if (!rc) {
549 hddLog(QDF_TRACE_LEVEL_WARN,
550 "%s: Warning: IBSS_PEER_INFO_TIMEOUT",
551 __func__);
552 retStatus = QDF_STATUS_E_FAILURE;
553 return retStatus;
554 }
555 } else {
556 hddLog(QDF_TRACE_LEVEL_WARN,
557 "%s: Warning: sme_request_ibss_peer_info Request failed",
558 __func__);
559 }
560
561 return retStatus;
562}
563
564/* Function header is left blank intentionally */
565QDF_STATUS
566hdd_parse_get_ibss_peer_info(uint8_t *pValue, struct qdf_mac_addr *pPeerMacAddr)
567{
568 uint8_t *inPtr = pValue;
569 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
570
571 if (NULL == inPtr) {
572 return QDF_STATUS_E_FAILURE;;
573 }
574
575 else if (SPACE_ASCII_VALUE != *inPtr) {
576 return QDF_STATUS_E_FAILURE;;
577 }
578
579 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
580 inPtr++;
581
582 if ('\0' == *inPtr) {
583 return QDF_STATUS_E_FAILURE;;
584 }
585
586 if (inPtr[2] != ':' || inPtr[5] != ':' || inPtr[8] != ':' ||
587 inPtr[11] != ':' || inPtr[14] != ':') {
588 return QDF_STATUS_E_FAILURE;;
589 }
590 sscanf(inPtr, "%2x:%2x:%2x:%2x:%2x:%2x",
591 (unsigned int *)&pPeerMacAddr->bytes[0],
592 (unsigned int *)&pPeerMacAddr->bytes[1],
593 (unsigned int *)&pPeerMacAddr->bytes[2],
594 (unsigned int *)&pPeerMacAddr->bytes[3],
595 (unsigned int *)&pPeerMacAddr->bytes[4],
596 (unsigned int *)&pPeerMacAddr->bytes[5]);
597
598 return QDF_STATUS_SUCCESS;
599}
600
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800601static void hdd_get_band_helper(hdd_context_t *hdd_ctx, int *pBand)
602{
603 eCsrBand band = -1;
604 sme_get_freq_band((tHalHandle) (hdd_ctx->hHal), &band);
605 switch (band) {
606 case eCSR_BAND_ALL:
607 *pBand = WLAN_HDD_UI_BAND_AUTO;
608 break;
609
610 case eCSR_BAND_24:
611 *pBand = WLAN_HDD_UI_BAND_2_4_GHZ;
612 break;
613
614 case eCSR_BAND_5G:
615 *pBand = WLAN_HDD_UI_BAND_5_GHZ;
616 break;
617
618 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530619 hddLog(QDF_TRACE_LEVEL_WARN, "%s: Invalid Band %d", __func__,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800620 band);
621 *pBand = -1;
622 break;
623 }
624}
625
626/**
627 * _hdd_parse_bssid_and_chan() - helper function to parse bssid and channel
628 * @data: input data
629 * @target_ap_bssid: pointer to bssid (output parameter)
630 * @channel: pointer to channel (output parameter)
631 *
632 * Return: 0 if parsing is successful; -EINVAL otherwise
633 */
634static int _hdd_parse_bssid_and_chan(const uint8_t **data,
635 uint8_t *bssid,
636 uint8_t *channel)
637{
638 const uint8_t *in_ptr;
639 int v = 0;
640 int temp_int;
641 uint8_t temp_buf[32];
642
643 /* 12 hexa decimal digits, 5 ':' and '\0' */
644 uint8_t mac_addr[18];
645
646 if (!data || !*data)
647 return -EINVAL;
648
649 in_ptr = *data;
650
651 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
652 /* no argument after the command */
653 if (NULL == in_ptr)
654 goto error;
655 /* no space after the command */
656 else if (SPACE_ASCII_VALUE != *in_ptr)
657 goto error;
658
659 /* remove empty spaces */
660 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
661 in_ptr++;
662
663 /* no argument followed by spaces */
664 if ('\0' == *in_ptr)
665 goto error;
666
667 v = sscanf(in_ptr, "%17s", mac_addr);
668 if (!((1 == v) && hdd_is_valid_mac_address(mac_addr))) {
669 hddLog(LOGE,
670 FL(
671 "Invalid MAC address or All hex inputs are not read (%d)"
672 ),
673 v);
674 goto error;
675 }
676
677 bssid[0] = hex_to_bin(mac_addr[0]) << 4 |
678 hex_to_bin(mac_addr[1]);
679 bssid[1] = hex_to_bin(mac_addr[3]) << 4 |
680 hex_to_bin(mac_addr[4]);
681 bssid[2] = hex_to_bin(mac_addr[6]) << 4 |
682 hex_to_bin(mac_addr[7]);
683 bssid[3] = hex_to_bin(mac_addr[9]) << 4 |
684 hex_to_bin(mac_addr[10]);
685 bssid[4] = hex_to_bin(mac_addr[12]) << 4 |
686 hex_to_bin(mac_addr[13]);
687 bssid[5] = hex_to_bin(mac_addr[15]) << 4 |
688 hex_to_bin(mac_addr[16]);
689
690 /* point to the next argument */
691 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
692 /* no argument after the command */
693 if (NULL == in_ptr)
694 goto error;
695
696 /* remove empty spaces */
697 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
698 in_ptr++;
699
700 /* no argument followed by spaces */
701 if ('\0' == *in_ptr)
702 goto error;
703
704 /* get the next argument ie the channel number */
705 v = sscanf(in_ptr, "%31s ", temp_buf);
706 if (1 != v)
707 goto error;
708
709 v = kstrtos32(temp_buf, 10, &temp_int);
710 if ((v < 0) || (temp_int < 0) ||
711 (temp_int > WNI_CFG_CURRENT_CHANNEL_STAMAX))
712 return -EINVAL;
713
714 *channel = temp_int;
715 *data = in_ptr;
716 return 0;
717error:
718 *data = in_ptr;
719 return -EINVAL;
720}
721
722/**
723 * hdd_parse_send_action_frame_data() - HDD Parse send action frame data
724 * @pValue: Pointer to input data
725 * @pTargetApBssid: Pointer to target Ap bssid
726 * @pChannel: Pointer to the Target AP channel
727 * @pDwellTime: Pointer to the time to stay off-channel
728 * after transmitting action frame
729 * @pBuf: Pointer to data
730 * @pBufLen: Pointer to data length
731 *
732 * This function parses the send action frame data passed in the format
733 * SENDACTIONFRAME<space><bssid><space><channel><space><dwelltime><space><data>
734 *
735 * Return: 0 for success non-zero for failure
736 */
737static int
738hdd_parse_send_action_frame_v1_data(const uint8_t *pValue,
739 uint8_t *pTargetApBssid,
740 uint8_t *pChannel, uint8_t *pDwellTime,
741 uint8_t **pBuf, uint8_t *pBufLen)
742{
743 const uint8_t *inPtr = pValue;
744 const uint8_t *dataEnd;
745 int tempInt;
746 int j = 0;
747 int i = 0;
748 int v = 0;
749 uint8_t tempBuf[32];
750 uint8_t tempByte = 0;
751
752 if (_hdd_parse_bssid_and_chan(&inPtr, pTargetApBssid, pChannel))
753 return -EINVAL;
754
755 /* point to the next argument */
756 inPtr = strnchr(inPtr, strlen(inPtr), SPACE_ASCII_VALUE);
757 /* no argument after the command */
758 if (NULL == inPtr)
759 return -EINVAL;
760 /* removing empty spaces */
761 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
762 inPtr++;
763
764 /* no argument followed by spaces */
765 if ('\0' == *inPtr) {
766 return -EINVAL;
767 }
768
769 /* getting the next argument ie the dwell time */
770 v = sscanf(inPtr, "%31s ", tempBuf);
771 if (1 != v)
772 return -EINVAL;
773
774 v = kstrtos32(tempBuf, 10, &tempInt);
775 if (v < 0 || tempInt < 0)
776 return -EINVAL;
777
778 *pDwellTime = tempInt;
779
780 /* point to the next argument */
781 inPtr = strnchr(inPtr, strlen(inPtr), SPACE_ASCII_VALUE);
782 /* no argument after the command */
783 if (NULL == inPtr)
784 return -EINVAL;
785 /* removing empty spaces */
786 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
787 inPtr++;
788
789 /* no argument followed by spaces */
790 if ('\0' == *inPtr) {
791 return -EINVAL;
792 }
793
794 /* find the length of data */
795 dataEnd = inPtr;
796 while (('\0' != *dataEnd)) {
797 dataEnd++;
798 }
799 *pBufLen = dataEnd - inPtr;
800 if (*pBufLen <= 0)
801 return -EINVAL;
802
803 /*
804 * Allocate the number of bytes based on the number of input characters
805 * whether it is even or odd.
806 * if the number of input characters are even, then we need N/2 byte.
807 * if the number of input characters are odd, then we need do (N+1)/2
808 * to compensate rounding off.
809 * For example, if N = 18, then (18 + 1)/2 = 9 bytes are enough.
810 * If N = 19, then we need 10 bytes, hence (19 + 1)/2 = 10 bytes
811 */
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530812 *pBuf = qdf_mem_malloc((*pBufLen + 1) / 2);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800813 if (NULL == *pBuf) {
Anurag Chouhanf04e84f2016-03-03 10:12:12 +0530814 hddLog(LOGE, FL("qdf_mem_malloc failed"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800815 return -ENOMEM;
816 }
817
818 /* the buffer received from the upper layer is character buffer,
819 * we need to prepare the buffer taking 2 characters in to a U8 hex
820 * decimal number for example 7f0000f0...form a buffer to contain 7f
821 * in 0th location, 00 in 1st and f0 in 3rd location
822 */
823 for (i = 0, j = 0; j < *pBufLen; j += 2) {
824 if (j + 1 == *pBufLen) {
825 tempByte = hex_to_bin(inPtr[j]);
826 } else {
827 tempByte =
828 (hex_to_bin(inPtr[j]) << 4) |
829 (hex_to_bin(inPtr[j + 1]));
830 }
831 (*pBuf)[i++] = tempByte;
832 }
833 *pBufLen = i;
834 return 0;
835}
836
837/**
838 * hdd_parse_reassoc_command_data() - HDD Parse reassoc command data
839 * @pValue: Pointer to input data (its a NULL terminated string)
840 * @pTargetApBssid: Pointer to target Ap bssid
841 * @pChannel: Pointer to the Target AP channel
842 *
843 * This function parses the reasoc command data passed in the format
844 * REASSOC<space><bssid><space><channel>
845 *
846 * Return: 0 for success non-zero for failure
847 */
848static int hdd_parse_reassoc_command_v1_data(const uint8_t *pValue,
849 uint8_t *pTargetApBssid,
850 uint8_t *pChannel)
851{
852 const uint8_t *inPtr = pValue;
853
854 if (_hdd_parse_bssid_and_chan(&inPtr, pTargetApBssid, pChannel))
855 return -EINVAL;
856
857 return 0;
858}
859
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800860/**
861 * hdd_reassoc() - perform a userspace-directed reassoc
862 * @adapter: Adapter upon which the command was received
863 * @bssid: BSSID with which to reassociate
864 * @channel: channel upon which to reassociate
865 *
866 * This function performs a userspace-directed reassoc operation
867 *
868 * Return: 0 for success non-zero for failure
869 */
870static int
871hdd_reassoc(hdd_adapter_t *adapter, const uint8_t *bssid,
872 const uint8_t channel)
873{
874 hdd_station_ctx_t *pHddStaCtx;
875 int ret = 0;
876
Krunal Sonibe766b02016-03-10 13:00:44 -0800877 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800878 hdd_warn("Unsupported in mode %s(%d)",
879 hdd_device_mode_to_string(adapter->device_mode),
880 adapter->device_mode);
881 return -EINVAL;
882 }
883
884 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
885
886 /* if not associated, no need to proceed with reassoc */
887 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530888 hddLog(QDF_TRACE_LEVEL_INFO, "%s: Not associated", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800889 ret = -EINVAL;
890 goto exit;
891 }
892
893 /*
894 * if the target bssid is same as currently associated AP,
895 * then no need to proceed with reassoc
896 */
897 if (!memcmp(bssid, pHddStaCtx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530898 QDF_MAC_ADDR_SIZE)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800899 hddLog(LOG1,
900 FL("Reassoc BSSID is same as currently associated AP bssid"));
901 ret = -EINVAL;
902 goto exit;
903 }
904
905 /* Check channel number is a valid channel number */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530906 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800907 wlan_hdd_validate_operation_channel(adapter, channel)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530908 hddLog(QDF_TRACE_LEVEL_ERROR, "%s: Invalid Channel %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800909 __func__, channel);
910 ret = -EINVAL;
911 goto exit;
912 }
913
914 /* Proceed with reassoc */
915 {
916 tCsrHandoffRequest handoffInfo;
917 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
918
919 handoffInfo.channel = channel;
920 handoffInfo.src = REASSOC;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530921 qdf_mem_copy(handoffInfo.bssid.bytes, bssid, QDF_MAC_ADDR_SIZE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800922 sme_handoff_request(hdd_ctx->hHal, adapter->sessionId,
923 &handoffInfo);
924 }
925exit:
926 return ret;
927}
928
929/**
930 * hdd_parse_reassoc_v1() - parse version 1 of the REASSOC command
931 * @adapter: Adapter upon which the command was received
932 * @command: ASCII text command that was received
933 *
934 * This function parses the v1 REASSOC command with the format
935 *
936 * REASSOC xx:xx:xx:xx:xx:xx CH
937 *
938 * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the
939 * BSSID and CH is the ASCII representation of the channel. For
940 * example
941 *
942 * REASSOC 00:0a:0b:11:22:33 48
943 *
944 * Return: 0 for success non-zero for failure
945 */
946static int hdd_parse_reassoc_v1(hdd_adapter_t *adapter, const char *command)
947{
948 uint8_t channel = 0;
949 tSirMacAddr bssid;
950 int ret;
951
952 ret = hdd_parse_reassoc_command_v1_data(command, bssid, &channel);
953 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530954 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800955 "%s: Failed to parse reassoc command data", __func__);
956 } else {
957 ret = hdd_reassoc(adapter, bssid, channel);
958 }
959 return ret;
960}
961
962/**
963 * hdd_parse_reassoc_v2() - parse version 2 of the REASSOC command
964 * @adapter: Adapter upon which the command was received
965 * @command: Command that was received, ASCII command
966 * followed by binary data
967 *
968 * This function parses the v2 REASSOC command with the format
969 *
970 * REASSOC <android_wifi_reassoc_params>
971 *
972 * Return: 0 for success non-zero for failure
973 */
974static int hdd_parse_reassoc_v2(hdd_adapter_t *adapter, const char *command)
975{
976 struct android_wifi_reassoc_params params;
977 tSirMacAddr bssid;
978 int ret;
979
980 /* The params are located after "REASSOC " */
981 memcpy(&params, command + 8, sizeof(params));
982
983 if (!mac_pton(params.bssid, (u8 *) &bssid)) {
984 hddLog(LOGE, "%s: MAC address parsing failed", __func__);
985 ret = -EINVAL;
986 } else {
987 ret = hdd_reassoc(adapter, bssid, params.channel);
988 }
989 return ret;
990}
991
992/**
993 * hdd_parse_reassoc() - parse the REASSOC command
994 * @adapter: Adapter upon which the command was received
995 * @command: Command that was received
996 *
997 * There are two different versions of the REASSOC command. Version 1
998 * of the command contains a parameter list that is ASCII characters
999 * whereas version 2 contains a combination of ASCII and binary
1000 * payload. Determine if a version 1 or a version 2 command is being
1001 * parsed by examining the parameters, and then dispatch the parser
1002 * that is appropriate for the command.
1003 *
1004 * Return: 0 for success non-zero for failure
1005 */
1006static int hdd_parse_reassoc(hdd_adapter_t *adapter, const char *command)
1007{
1008 int ret;
1009
1010 /* both versions start with "REASSOC "
1011 * v1 has a bssid and channel # as an ASCII string
1012 * REASSOC xx:xx:xx:xx:xx:xx CH
1013 * v2 has a C struct
1014 * REASSOC <binary c struct>
1015 *
1016 * The first field in the v2 struct is also the bssid in ASCII.
1017 * But in the case of a v2 message the BSSID is NUL-terminated.
1018 * Hence we can peek at that offset to see if this is V1 or V2
1019 * REASSOC xx:xx:xx:xx:xx:xx*
1020 * 1111111111222222
1021 * 01234567890123456789012345
1022 */
1023 if (command[25]) {
1024 ret = hdd_parse_reassoc_v1(adapter, command);
1025 } else {
1026 ret = hdd_parse_reassoc_v2(adapter, command);
1027 }
1028
1029 return ret;
1030}
1031
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001032/**
1033 * hdd_sendactionframe() - send a userspace-supplied action frame
1034 * @adapter: Adapter upon which the command was received
1035 * @bssid: BSSID target of the action frame
1036 * @channel: Channel upon which to send the frame
1037 * @dwell_time: Amount of time to dwell when the frame is sent
1038 * @payload_len:Length of the payload
1039 * @payload: Payload of the frame
1040 *
1041 * This function sends a userspace-supplied action frame
1042 *
1043 * Return: 0 for success non-zero for failure
1044 */
1045static int
1046hdd_sendactionframe(hdd_adapter_t *adapter, const uint8_t *bssid,
1047 const uint8_t channel, const uint8_t dwell_time,
1048 const uint8_t payload_len, const uint8_t *payload)
1049{
1050 struct ieee80211_channel chan;
1051 uint8_t frame_len;
1052 uint8_t *frame;
1053 struct ieee80211_hdr_3addr *hdr;
1054 u64 cookie;
1055 hdd_station_ctx_t *pHddStaCtx;
1056 hdd_context_t *hdd_ctx;
1057 int ret = 0;
1058 tpSirMacVendorSpecificFrameHdr pVendorSpecific =
1059 (tpSirMacVendorSpecificFrameHdr) payload;
1060#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
1061 struct cfg80211_mgmt_tx_params params;
1062#endif
1063
Krunal Sonibe766b02016-03-10 13:00:44 -08001064 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001065 hdd_warn("Unsupported in mode %s(%d)",
1066 hdd_device_mode_to_string(adapter->device_mode),
1067 adapter->device_mode);
1068 return -EINVAL;
1069 }
1070
1071 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
1072 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1073
1074 /* if not associated, no need to send action frame */
1075 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301076 hddLog(QDF_TRACE_LEVEL_INFO, "%s: Not associated", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001077 ret = -EINVAL;
1078 goto exit;
1079 }
1080
1081 /*
1082 * if the target bssid is different from currently associated AP,
1083 * then no need to send action frame
1084 */
1085 if (memcmp(bssid, pHddStaCtx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05301086 QDF_MAC_ADDR_SIZE)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001087 hddLog(LOG1, FL("STA is not associated to this AP"));
1088 ret = -EINVAL;
1089 goto exit;
1090 }
1091
1092 chan.center_freq = sme_chn_to_freq(channel);
1093 /* Check if it is specific action frame */
1094 if (pVendorSpecific->category ==
1095 SIR_MAC_ACTION_VENDOR_SPECIFIC_CATEGORY) {
1096 static const uint8_t Oui[] = { 0x00, 0x00, 0xf0 };
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301097 if (!qdf_mem_cmp(pVendorSpecific->Oui, (void *)Oui, 3)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001098 /*
1099 * if the channel number is different from operating
1100 * channel then no need to send action frame
1101 */
1102 if (channel != 0) {
1103 if (channel !=
1104 pHddStaCtx->conn_info.operationChannel) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301105 hddLog(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001106 "%s: channel(%d) is different from operating channel(%d)",
1107 __func__, channel,
1108 pHddStaCtx->conn_info.
1109 operationChannel);
1110 ret = -EINVAL;
1111 goto exit;
1112 }
1113 /*
1114 * If channel number is specified and same
1115 * as home channel, ensure that action frame
1116 * is sent immediately by cancelling
1117 * roaming scans. Otherwise large dwell times
1118 * may cause long delays in sending action
1119 * frames.
1120 */
1121 sme_abort_roam_scan(hdd_ctx->hHal,
1122 adapter->sessionId);
1123 } else {
1124 /*
1125 * 0 is accepted as current home channel,
1126 * delayed transmission of action frame is ok.
1127 */
1128 chan.center_freq =
1129 sme_chn_to_freq(pHddStaCtx->conn_info.
1130 operationChannel);
1131 }
1132 }
1133 }
1134 if (chan.center_freq == 0) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301135 hddLog(QDF_TRACE_LEVEL_ERROR, "%s:invalid channel number %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001136 __func__, channel);
1137 ret = -EINVAL;
1138 goto exit;
1139 }
1140
1141 frame_len = payload_len + 24;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301142 frame = qdf_mem_malloc(frame_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001143 if (!frame) {
1144 hddLog(LOGE, FL("memory allocation failed"));
1145 ret = -ENOMEM;
1146 goto exit;
1147 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301148 qdf_mem_zero(frame, frame_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001149
1150 hdr = (struct ieee80211_hdr_3addr *)frame;
1151 hdr->frame_control =
1152 cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301153 qdf_mem_copy(hdr->addr1, bssid, QDF_MAC_ADDR_SIZE);
1154 qdf_mem_copy(hdr->addr2, adapter->macAddressCurrent.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05301155 QDF_MAC_ADDR_SIZE);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301156 qdf_mem_copy(hdr->addr3, bssid, QDF_MAC_ADDR_SIZE);
1157 qdf_mem_copy(hdr + 1, payload, payload_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001158
1159#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
1160 params.chan = &chan;
1161 params.offchan = 0;
1162 params.wait = dwell_time;
1163 params.buf = frame;
1164 params.len = frame_len;
1165 params.no_cck = 1;
1166 params.dont_wait_for_ack = 1;
1167 ret = wlan_hdd_mgmt_tx(NULL, &adapter->wdev, &params, &cookie);
1168#else
1169 ret = wlan_hdd_mgmt_tx(NULL,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001170 &(adapter->wdev),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001171 &chan, 0,
Amar Singhal01098f72015-10-08 11:55:32 -07001172
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001173 dwell_time, frame, frame_len, 1, 1, &cookie);
1174#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
1175
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301176 qdf_mem_free(frame);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001177exit:
1178 return ret;
1179}
1180
1181/**
1182 * hdd_parse_sendactionframe_v1() - parse version 1 of the
1183 * SENDACTIONFRAME command
1184 * @adapter: Adapter upon which the command was received
1185 * @command: ASCII text command that was received
1186 *
1187 * This function parses the v1 SENDACTIONFRAME command with the format
1188 *
1189 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DW xxxxxx
1190 *
1191 * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the
1192 * BSSID, CH is the ASCII representation of the channel, DW is the
1193 * ASCII representation of the dwell time, and xxxxxx is the Hex-ASCII
1194 * payload. For example
1195 *
1196 * SENDACTIONFRAME 00:0a:0b:11:22:33 48 40 aabbccddee
1197 *
1198 * Return: 0 for success non-zero for failure
1199 */
1200static int
1201hdd_parse_sendactionframe_v1(hdd_adapter_t *adapter, const char *command)
1202{
1203 uint8_t channel = 0;
1204 uint8_t dwell_time = 0;
1205 uint8_t payload_len = 0;
1206 uint8_t *payload = NULL;
1207 tSirMacAddr bssid;
1208 int ret;
1209
1210 ret = hdd_parse_send_action_frame_v1_data(command, bssid, &channel,
1211 &dwell_time, &payload,
1212 &payload_len);
1213 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301214 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001215 "%s: Failed to parse send action frame data", __func__);
1216 } else {
1217 ret = hdd_sendactionframe(adapter, bssid, channel,
1218 dwell_time, payload_len, payload);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301219 qdf_mem_free(payload);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001220 }
1221
1222 return ret;
1223}
1224
1225/**
1226 * hdd_parse_sendactionframe_v2() - parse version 2 of the
1227 * SENDACTIONFRAME command
1228 * @adapter: Adapter upon which the command was received
1229 * @command: Command that was received, ASCII command
1230 * followed by binary data
1231 *
1232 * This function parses the v2 SENDACTIONFRAME command with the format
1233 *
1234 * SENDACTIONFRAME <android_wifi_af_params>
1235 *
1236 * Return: 0 for success non-zero for failure
1237 */
1238static int
1239hdd_parse_sendactionframe_v2(hdd_adapter_t *adapter, const char *command)
1240{
1241 struct android_wifi_af_params *params;
1242 tSirMacAddr bssid;
1243 int ret;
1244
1245 /* params are large so keep off the stack */
1246 params = kmalloc(sizeof(*params), GFP_KERNEL);
1247 if (!params)
1248 return -ENOMEM;
1249
1250 /* The params are located after "SENDACTIONFRAME " */
1251 memcpy(params, command + 16, sizeof(*params));
1252
1253 if (!mac_pton(params->bssid, (u8 *) &bssid)) {
1254 hddLog(LOGE, "%s: MAC address parsing failed", __func__);
1255 ret = -EINVAL;
1256 } else {
1257 ret = hdd_sendactionframe(adapter, bssid, params->channel,
1258 params->dwell_time, params->len,
1259 params->data);
1260 }
1261 kfree(params);
1262 return ret;
1263}
1264
1265/**
1266 * hdd_parse_sendactionframe() - parse the SENDACTIONFRAME command
1267 * @adapter: Adapter upon which the command was received
1268 * @command: Command that was received
1269 *
1270 * There are two different versions of the SENDACTIONFRAME command.
1271 * Version 1 of the command contains a parameter list that is ASCII
1272 * characters whereas version 2 contains a combination of ASCII and
1273 * binary payload. Determine if a version 1 or a version 2 command is
1274 * being parsed by examining the parameters, and then dispatch the
1275 * parser that is appropriate for the version of the command.
1276 *
1277 * Return: 0 for success non-zero for failure
1278 */
1279static int
1280hdd_parse_sendactionframe(hdd_adapter_t *adapter, const char *command)
1281{
1282 int ret;
1283
1284 /*
1285 * both versions start with "SENDACTIONFRAME "
1286 * v1 has a bssid and other parameters as an ASCII string
1287 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DWELL LEN FRAME
1288 * v2 has a C struct
1289 * SENDACTIONFRAME <binary c struct>
1290 *
1291 * The first field in the v2 struct is also the bssid in ASCII.
1292 * But in the case of a v2 message the BSSID is NUL-terminated.
1293 * Hence we can peek at that offset to see if this is V1 or V2
1294 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx*
1295 * 111111111122222222223333
1296 * 0123456789012345678901234567890123
1297 */
1298 if (command[33]) {
1299 ret = hdd_parse_sendactionframe_v1(adapter, command);
1300 } else {
1301 ret = hdd_parse_sendactionframe_v2(adapter, command);
1302 }
1303
1304 return ret;
1305}
1306
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001307/**
1308 * hdd_parse_channellist() - HDD Parse channel list
1309 * @pValue: Pointer to input channel list
1310 * @ChannelList: Pointer to local output array to record
1311 * channel list
1312 * @pNumChannels: Pointer to number of roam scan channels
1313 *
1314 * This function parses the channel list passed in the format
1315 * SETROAMSCANCHANNELS<space><Number of channels><space>Channel 1<space>Channel 2<space>Channel N
1316 * if the Number of channels (N) does not match with the actual number
1317 * of channels passed then take the minimum of N and count of
1318 * (Ch1, Ch2, ...Ch M). For example, if SETROAMSCANCHANNELS 3 36 40 44 48,
1319 * only 36, 40 and 44 shall be taken. If SETROAMSCANCHANNELS 5 36 40 44 48,
1320 * ignore 5 and take 36, 40, 44 and 48. This function does not take care of
1321 * removing duplicate channels from the list
1322 *
1323 * Return: 0 for success non-zero for failure
1324 */
1325static int
1326hdd_parse_channellist(const uint8_t *pValue, uint8_t *pChannelList,
1327 uint8_t *pNumChannels)
1328{
1329 const uint8_t *inPtr = pValue;
1330 int tempInt;
1331 int j = 0;
1332 int v = 0;
1333 char buf[32];
1334
1335 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
1336 /* no argument after the command */
1337 if (NULL == inPtr) {
1338 return -EINVAL;
1339 }
1340
1341 /* no space after the command */
1342 else if (SPACE_ASCII_VALUE != *inPtr) {
1343 return -EINVAL;
1344 }
1345
1346 /* remove empty spaces */
1347 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
1348 inPtr++;
1349
1350 /* no argument followed by spaces */
1351 if ('\0' == *inPtr) {
1352 return -EINVAL;
1353 }
1354
1355 /* get the first argument ie the number of channels */
1356 v = sscanf(inPtr, "%31s ", buf);
1357 if (1 != v)
1358 return -EINVAL;
1359
1360 v = kstrtos32(buf, 10, &tempInt);
1361 if ((v < 0) ||
1362 (tempInt <= 0) || (tempInt > WNI_CFG_VALID_CHANNEL_LIST_LEN)) {
1363 return -EINVAL;
1364 }
1365
1366 *pNumChannels = tempInt;
1367
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301368 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001369 "Number of channels are: %d", *pNumChannels);
1370
1371 for (j = 0; j < (*pNumChannels); j++) {
1372 /*
1373 * inPtr pointing to the beginning of first space after number
1374 * of channels
1375 */
1376 inPtr = strpbrk(inPtr, " ");
1377 /* no channel list after the number of channels argument */
1378 if (NULL == inPtr) {
1379 if (0 != j) {
1380 *pNumChannels = j;
1381 return 0;
1382 } else {
1383 return -EINVAL;
1384 }
1385 }
1386
1387 /* remove empty space */
1388 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
1389 inPtr++;
1390
1391 /*
1392 * no channel list after the number of channels
1393 * argument and spaces
1394 */
1395 if ('\0' == *inPtr) {
1396 if (0 != j) {
1397 *pNumChannels = j;
1398 return 0;
1399 } else {
1400 return -EINVAL;
1401 }
1402 }
1403
1404 v = sscanf(inPtr, "%31s ", buf);
1405 if (1 != v)
1406 return -EINVAL;
1407
1408 v = kstrtos32(buf, 10, &tempInt);
1409 if ((v < 0) ||
1410 (tempInt <= 0) ||
1411 (tempInt > WNI_CFG_CURRENT_CHANNEL_STAMAX)) {
1412 return -EINVAL;
1413 }
1414 pChannelList[j] = tempInt;
1415
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301416 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001417 "Channel %d added to preferred channel list",
1418 pChannelList[j]);
1419 }
1420
1421 return 0;
1422}
1423
1424/**
1425 * hdd_parse_set_roam_scan_channels_v1() - parse version 1 of the
1426 * SETROAMSCANCHANNELS command
1427 * @adapter: Adapter upon which the command was received
1428 * @command: ASCII text command that was received
1429 *
1430 * This function parses the v1 SETROAMSCANCHANNELS command with the format
1431 *
1432 * SETROAMSCANCHANNELS N C1 C2 ... Cn
1433 *
1434 * Where "N" is the ASCII representation of the number of channels and
1435 * C1 thru Cn is the ASCII representation of the channels. For example
1436 *
1437 * SETROAMSCANCHANNELS 4 36 40 44 48
1438 *
1439 * Return: 0 for success non-zero for failure
1440 */
1441static int
1442hdd_parse_set_roam_scan_channels_v1(hdd_adapter_t *adapter,
1443 const char *command)
1444{
1445 uint8_t channel_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
1446 uint8_t num_chan = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301447 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001448 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1449 int ret;
1450
1451 ret = hdd_parse_channellist(command, channel_list, &num_chan);
1452 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301453 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001454 "%s: Failed to parse channel list information",
1455 __func__);
1456 goto exit;
1457 }
1458
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301459 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001460 TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL,
1461 adapter->sessionId, num_chan));
1462
1463 if (num_chan > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301464 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001465 "%s: number of channels (%d) supported exceeded max (%d)",
1466 __func__, num_chan, WNI_CFG_VALID_CHANNEL_LIST_LEN);
1467 ret = -EINVAL;
1468 goto exit;
1469 }
1470
1471 status =
1472 sme_change_roam_scan_channel_list(hdd_ctx->hHal,
1473 adapter->sessionId,
1474 channel_list, num_chan);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301475 if (QDF_STATUS_SUCCESS != status) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301476 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001477 "%s: Failed to update channel list information",
1478 __func__);
1479 ret = -EINVAL;
1480 goto exit;
1481 }
1482exit:
1483 return ret;
1484}
1485
1486/**
1487 * hdd_parse_set_roam_scan_channels_v2() - parse version 2 of the
1488 * SETROAMSCANCHANNELS command
1489 * @adapter: Adapter upon which the command was received
1490 * @command: Command that was received, ASCII command
1491 * followed by binary data
1492 *
1493 * This function parses the v2 SETROAMSCANCHANNELS command with the format
1494 *
1495 * SETROAMSCANCHANNELS [N][C1][C2][Cn]
1496 *
1497 * The command begins with SETROAMSCANCHANNELS followed by a space, but
1498 * what follows the space is an array of u08 parameters. For example
1499 *
1500 * SETROAMSCANCHANNELS [0x04 0x24 0x28 0x2c 0x30]
1501 *
1502 * Return: 0 for success non-zero for failure
1503 */
1504static int
1505hdd_parse_set_roam_scan_channels_v2(hdd_adapter_t *adapter,
1506 const char *command)
1507{
1508 const uint8_t *value;
1509 uint8_t channel_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
1510 uint8_t channel;
1511 uint8_t num_chan;
1512 int i;
1513 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301514 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001515 int ret = 0;
1516
1517 /* array of values begins after "SETROAMSCANCHANNELS " */
1518 value = command + 20;
1519
1520 num_chan = *value++;
1521 if (num_chan > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301522 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001523 "%s: number of channels (%d) supported exceeded max (%d)",
1524 __func__, num_chan, WNI_CFG_VALID_CHANNEL_LIST_LEN);
1525 ret = -EINVAL;
1526 goto exit;
1527 }
1528
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301529 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001530 TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL,
1531 adapter->sessionId, num_chan));
1532
1533 for (i = 0; i < num_chan; i++) {
1534 channel = *value++;
1535 if (channel > WNI_CFG_CURRENT_CHANNEL_STAMAX) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301536 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001537 "%s: index %d invalid channel %d", __func__,
1538 i, channel);
1539 ret = -EINVAL;
1540 goto exit;
1541 }
1542 channel_list[i] = channel;
1543 }
1544 status =
1545 sme_change_roam_scan_channel_list(hdd_ctx->hHal,
1546 adapter->sessionId,
1547 channel_list, num_chan);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301548 if (QDF_STATUS_SUCCESS != status) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301549 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001550 "%s: Failed to update channel list information",
1551 __func__);
1552 ret = -EINVAL;
1553 goto exit;
1554 }
1555exit:
1556 return ret;
1557}
1558
1559/**
1560 * hdd_parse_set_roam_scan_channels() - parse the
1561 * SETROAMSCANCHANNELS command
1562 * @adapter: Adapter upon which the command was received
1563 * @command: Command that was received
1564 *
1565 * There are two different versions of the SETROAMSCANCHANNELS command.
1566 * Version 1 of the command contains a parameter list that is ASCII
1567 * characters whereas version 2 contains a binary payload. Determine
1568 * if a version 1 or a version 2 command is being parsed by examining
1569 * the parameters, and then dispatch the parser that is appropriate for
1570 * the command.
1571 *
1572 * Return: 0 for success non-zero for failure
1573 */
1574static int
1575hdd_parse_set_roam_scan_channels(hdd_adapter_t *adapter, const char *command)
1576{
1577 const char *cursor;
1578 char ch;
1579 bool v1;
1580 int ret;
1581
1582 /* start after "SETROAMSCANCHANNELS " */
1583 cursor = command + 20;
1584
1585 /* assume we have a version 1 command until proven otherwise */
1586 v1 = true;
1587
1588 /* v1 params will only contain ASCII digits and space */
1589 while ((ch = *cursor++) && v1) {
1590 if (!(isdigit(ch) || isspace(ch))) {
1591 v1 = false;
1592 }
1593 }
1594 if (v1) {
1595 ret = hdd_parse_set_roam_scan_channels_v1(adapter, command);
1596 } else {
1597 ret = hdd_parse_set_roam_scan_channels_v2(adapter, command);
1598 }
1599
1600 return ret;
1601}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001602
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08001603#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001604/**
1605 * hdd_parse_plm_cmd() - HDD Parse Plm command
1606 * @pValue: Pointer to input data
1607 * @pPlmRequest:Pointer to output struct tpSirPlmReq
1608 *
1609 * This function parses the plm command passed in the format
1610 * CCXPLMREQ<space><enable><space><dialog_token><space>
1611 * <meas_token><space><num_of_bursts><space><burst_int><space>
1612 * <measu duration><space><burst_len><space><desired_tx_pwr>
1613 * <space><multcast_addr><space><number_of_channels>
1614 * <space><channel_numbers>
1615 *
1616 * Return: 0 for success non-zero for failure
1617 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301618QDF_STATUS hdd_parse_plm_cmd(uint8_t *pValue, tSirPlmReq *pPlmRequest)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001619{
1620 uint8_t *cmdPtr = NULL;
1621 int count, content = 0, ret = 0;
1622 char buf[32];
1623
1624 /* move to argument list */
1625 cmdPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
1626 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301627 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001628
1629 /* no space after the command */
1630 if (SPACE_ASCII_VALUE != *cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301631 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001632
1633 /* remove empty spaces */
1634 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1635 cmdPtr++;
1636
1637 /* START/STOP PLM req */
1638 ret = sscanf(cmdPtr, "%31s ", buf);
1639 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301640 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001641
1642 ret = kstrtos32(buf, 10, &content);
1643 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301644 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001645
1646 pPlmRequest->enable = content;
1647 cmdPtr = strpbrk(cmdPtr, " ");
1648
1649 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301650 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001651
1652 /* remove empty spaces */
1653 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1654 cmdPtr++;
1655
1656 /* Dialog token of radio meas req containing meas reqIE */
1657 ret = sscanf(cmdPtr, "%31s ", buf);
1658 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301659 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001660
1661 ret = kstrtos32(buf, 10, &content);
1662 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301663 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001664
1665 pPlmRequest->diag_token = content;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301666 hddLog(QDF_TRACE_LEVEL_DEBUG, "diag token %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001667 pPlmRequest->diag_token);
1668 cmdPtr = strpbrk(cmdPtr, " ");
1669
1670 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301671 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001672
1673 /* remove empty spaces */
1674 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1675 cmdPtr++;
1676
1677 /* measurement token of meas req IE */
1678 ret = sscanf(cmdPtr, "%31s ", buf);
1679 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301680 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001681
1682 ret = kstrtos32(buf, 10, &content);
1683 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301684 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001685
1686 pPlmRequest->meas_token = content;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301687 hddLog(QDF_TRACE_LEVEL_DEBUG, "meas token %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001688 pPlmRequest->meas_token);
1689
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301690 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001691 "PLM req %s", pPlmRequest->enable ? "START" : "STOP");
1692 if (pPlmRequest->enable) {
1693
1694 cmdPtr = strpbrk(cmdPtr, " ");
1695
1696 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301697 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001698
1699 /* remove empty spaces */
1700 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1701 cmdPtr++;
1702
1703 /* total number of bursts after which STA stops sending */
1704 ret = sscanf(cmdPtr, "%31s ", buf);
1705 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301706 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001707
1708 ret = kstrtos32(buf, 10, &content);
1709 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301710 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001711
1712 if (content < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301713 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001714
1715 pPlmRequest->numBursts = content;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301716 hddLog(QDF_TRACE_LEVEL_DEBUG, "num burst %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001717 pPlmRequest->numBursts);
1718 cmdPtr = strpbrk(cmdPtr, " ");
1719
1720 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301721 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001722
1723 /* remove empty spaces */
1724 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1725 cmdPtr++;
1726
1727 /* burst interval in seconds */
1728 ret = sscanf(cmdPtr, "%31s ", buf);
1729 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301730 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001731
1732 ret = kstrtos32(buf, 10, &content);
1733 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301734 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001735
1736 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301737 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001738
1739 pPlmRequest->burstInt = content;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301740 hddLog(QDF_TRACE_LEVEL_DEBUG, "burst Int %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001741 pPlmRequest->burstInt);
1742 cmdPtr = strpbrk(cmdPtr, " ");
1743
1744 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301745 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001746
1747 /* remove empty spaces */
1748 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1749 cmdPtr++;
1750
1751 /* Meas dur in TU's,STA goes off-ch and transmit PLM bursts */
1752 ret = sscanf(cmdPtr, "%31s ", buf);
1753 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301754 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001755
1756 ret = kstrtos32(buf, 10, &content);
1757 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301758 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001759
1760 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301761 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001762
1763 pPlmRequest->measDuration = content;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301764 hddLog(QDF_TRACE_LEVEL_DEBUG, "measDur %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001765 pPlmRequest->measDuration);
1766 cmdPtr = strpbrk(cmdPtr, " ");
1767
1768 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301769 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001770
1771 /* remove empty spaces */
1772 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1773 cmdPtr++;
1774
1775 /* burst length of PLM bursts */
1776 ret = sscanf(cmdPtr, "%31s ", buf);
1777 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301778 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001779
1780 ret = kstrtos32(buf, 10, &content);
1781 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301782 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001783
1784 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301785 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001786
1787 pPlmRequest->burstLen = content;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301788 hddLog(QDF_TRACE_LEVEL_DEBUG, "burstLen %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001789 pPlmRequest->burstLen);
1790 cmdPtr = strpbrk(cmdPtr, " ");
1791
1792 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301793 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001794
1795 /* remove empty spaces */
1796 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1797 cmdPtr++;
1798
1799 /* desired tx power for transmission of PLM bursts */
1800 ret = sscanf(cmdPtr, "%31s ", buf);
1801 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301802 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001803
1804 ret = kstrtos32(buf, 10, &content);
1805 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301806 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001807
1808 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301809 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001810
1811 pPlmRequest->desiredTxPwr = content;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301812 hddLog(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001813 "desiredTxPwr %d", pPlmRequest->desiredTxPwr);
1814
Anurag Chouhan6d760662016-02-20 16:05:43 +05301815 for (count = 0; count < QDF_MAC_ADDR_SIZE; count++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001816 cmdPtr = strpbrk(cmdPtr, " ");
1817
1818 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301819 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001820
1821 /* remove empty spaces */
1822 while ((SPACE_ASCII_VALUE == *cmdPtr)
1823 && ('\0' != *cmdPtr))
1824 cmdPtr++;
1825
1826 ret = sscanf(cmdPtr, "%31s ", buf);
1827 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301828 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001829
1830 ret = kstrtos32(buf, 16, &content);
1831 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301832 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001833
Srinivas Girigowda5146dee2015-11-18 21:46:48 -08001834 pPlmRequest->mac_addr.bytes[count] = content;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001835 }
1836
Srinivas Girigowda5146dee2015-11-18 21:46:48 -08001837 hdd_debug("MC addr " MAC_ADDRESS_STR,
1838 MAC_ADDR_ARRAY(pPlmRequest->mac_addr.bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001839
1840 cmdPtr = strpbrk(cmdPtr, " ");
1841
1842 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301843 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001844
1845 /* remove empty spaces */
1846 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1847 cmdPtr++;
1848
1849 /* number of channels */
1850 ret = sscanf(cmdPtr, "%31s ", buf);
1851 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301852 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001853
1854 ret = kstrtos32(buf, 10, &content);
1855 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301856 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001857
1858 if (content < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301859 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001860
1861 pPlmRequest->plmNumCh = content;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301862 hddLog(QDF_TRACE_LEVEL_DEBUG, "numch %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001863 pPlmRequest->plmNumCh);
1864
1865 /* Channel numbers */
1866 for (count = 0; count < pPlmRequest->plmNumCh; count++) {
1867 cmdPtr = strpbrk(cmdPtr, " ");
1868
1869 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301870 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001871
1872 /* remove empty spaces */
1873 while ((SPACE_ASCII_VALUE == *cmdPtr)
1874 && ('\0' != *cmdPtr))
1875 cmdPtr++;
1876
1877 ret = sscanf(cmdPtr, "%31s ", buf);
1878 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301879 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001880
1881 ret = kstrtos32(buf, 10, &content);
1882 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301883 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001884
1885 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301886 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001887
1888 pPlmRequest->plmChList[count] = content;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301889 hddLog(QDF_TRACE_LEVEL_DEBUG, " ch- %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001890 pPlmRequest->plmChList[count]);
1891 }
1892 }
1893 /* If PLM START */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301894 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001895}
1896#endif
1897
1898#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
1899static void wlan_hdd_ready_to_extwow(void *callbackContext, bool is_success)
1900{
1901 hdd_context_t *hdd_ctx = (hdd_context_t *) callbackContext;
1902 int rc;
1903
1904 rc = wlan_hdd_validate_context(hdd_ctx);
1905 if (0 != rc) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301906 hddLog(QDF_TRACE_LEVEL_ERROR, FL("HDD context is not valid"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001907 return;
1908 }
1909 hdd_ctx->ext_wow_should_suspend = is_success;
1910 complete(&hdd_ctx->ready_to_extwow);
1911}
1912
1913static int hdd_enable_ext_wow(hdd_adapter_t *adapter,
1914 tpSirExtWoWParams arg_params)
1915{
1916 tSirExtWoWParams params;
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301917 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001918 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1919 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
1920 int rc;
1921
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301922 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001923
1924 INIT_COMPLETION(hdd_ctx->ready_to_extwow);
1925
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301926 qdf_ret_status = sme_configure_ext_wow(hHal, &params,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001927 &wlan_hdd_ready_to_extwow,
1928 hdd_ctx);
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301929 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301930 hddLog(QDF_TRACE_LEVEL_ERROR,
Krishna Kumaar Natarajand9131902015-10-19 11:52:47 -07001931 FL("sme_configure_ext_wow returned failure %d"),
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301932 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001933 return -EPERM;
1934 }
1935
1936 rc = wait_for_completion_timeout(&hdd_ctx->ready_to_extwow,
1937 msecs_to_jiffies(WLAN_WAIT_TIME_READY_TO_EXTWOW));
1938 if (!rc) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301939 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001940 "%s: Failed to get ready to extwow", __func__);
1941 return -EPERM;
1942 }
1943
1944 if (hdd_ctx->ext_wow_should_suspend) {
1945 if (hdd_ctx->config->extWowGotoSuspend) {
1946 pm_message_t state;
1947
1948 state.event = PM_EVENT_SUSPEND;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301949 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001950 "%s: Received ready to ExtWoW. Going to suspend",
1951 __func__);
1952
1953 rc = wlan_hdd_cfg80211_suspend_wlan(hdd_ctx->wiphy, NULL);
1954 if (rc < 0) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301955 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001956 "%s: wlan_hdd_cfg80211_suspend_wlan failed, error = %d",
1957 __func__, rc);
1958 return rc;
1959 }
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301960 qdf_ret_status = wlan_hdd_bus_suspend(state);
1961 if (qdf_ret_status != QDF_STATUS_SUCCESS) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301962 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001963 "%s: wlan_hdd_suspend failed, status = %d",
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301964 __func__, qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001965 wlan_hdd_cfg80211_resume_wlan(hdd_ctx->wiphy);
1966 return -EPERM;
1967 }
1968 }
1969 } else {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301970 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001971 "%s: Received ready to ExtWoW failure", __func__);
1972 return -EPERM;
1973 }
1974
1975 return 0;
1976}
1977
1978static int hdd_enable_ext_wow_parser(hdd_adapter_t *adapter, int vdev_id,
1979 int value)
1980{
1981 tSirExtWoWParams params;
1982 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1983 int rc;
1984
1985 rc = wlan_hdd_validate_context(hdd_ctx);
1986 if (0 != rc) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301987 hddLog(QDF_TRACE_LEVEL_ERROR, FL("HDD context is not valid"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001988 return -EINVAL;
1989 }
1990
1991 if (value < EXT_WOW_TYPE_APP_TYPE1 ||
1992 value > EXT_WOW_TYPE_APP_TYPE1_2) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301993 hddLog(QDF_TRACE_LEVEL_ERROR, FL("Invalid type"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001994 return -EINVAL;
1995 }
1996
1997 if (value == EXT_WOW_TYPE_APP_TYPE1 &&
1998 hdd_ctx->is_extwow_app_type1_param_set)
1999 params.type = value;
2000 else if (value == EXT_WOW_TYPE_APP_TYPE2 &&
2001 hdd_ctx->is_extwow_app_type2_param_set)
2002 params.type = value;
2003 else if (value == EXT_WOW_TYPE_APP_TYPE1_2 &&
2004 hdd_ctx->is_extwow_app_type1_param_set &&
2005 hdd_ctx->is_extwow_app_type2_param_set)
2006 params.type = value;
2007 else {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302008 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002009 FL("Set app params before enable it value %d"), value);
2010 return -EINVAL;
2011 }
2012
2013 params.vdev_id = vdev_id;
2014 params.wakeup_pin_num = hdd_ctx->config->extWowApp1WakeupPinNumber |
2015 (hdd_ctx->config->extWowApp2WakeupPinNumber
2016 << 8);
2017
2018 return hdd_enable_ext_wow(adapter, &params);
2019}
2020
2021static int hdd_set_app_type1_params(tHalHandle hHal,
2022 tpSirAppType1Params arg_params)
2023{
2024 tSirAppType1Params params;
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05302025 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002026
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302027 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002028
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05302029 qdf_ret_status = sme_configure_app_type1_params(hHal, &params);
2030 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302031 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002032 FL("sme_configure_app_type1_params returned failure %d"),
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05302033 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002034 return -EPERM;
2035 }
2036
2037 return 0;
2038}
2039
2040static int hdd_set_app_type1_parser(hdd_adapter_t *adapter,
2041 char *arg, int len)
2042{
2043 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2044 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
2045 char id[20], password[20];
2046 tSirAppType1Params params;
Srinivas Girigowda04209912015-11-24 12:11:13 -08002047 int rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002048
2049 rc = wlan_hdd_validate_context(hdd_ctx);
2050 if (0 != rc) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302051 hddLog(QDF_TRACE_LEVEL_ERROR, FL("HDD context is not valid"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002052 return -EINVAL;
2053 }
2054
2055 if (2 != sscanf(arg, "%8s %16s", id, password)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302056 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002057 FL("Invalid Number of arguments"));
2058 return -EINVAL;
2059 }
2060
2061 memset(&params, 0, sizeof(tSirAppType1Params));
2062 params.vdev_id = adapter->sessionId;
Anurag Chouhanc5548422016-02-24 18:33:27 +05302063 qdf_copy_macaddr(&params.wakee_mac_addr, &adapter->macAddressCurrent);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002064
2065 params.id_length = strlen(id);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302066 qdf_mem_copy(params.identification_id, id, params.id_length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002067 params.pass_length = strlen(password);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302068 qdf_mem_copy(params.password, password, params.pass_length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002069
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302070 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002071 "%s: %d %pM %.8s %u %.16s %u",
Srinivas Girigowda04209912015-11-24 12:11:13 -08002072 __func__, params.vdev_id, params.wakee_mac_addr.bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002073 params.identification_id, params.id_length,
2074 params.password, params.pass_length);
2075
2076 return hdd_set_app_type1_params(hHal, &params);
2077}
2078
2079static int hdd_set_app_type2_params(tHalHandle hHal,
2080 tpSirAppType2Params arg_params)
2081{
2082 tSirAppType2Params params;
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05302083 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002084
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302085 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002086
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05302087 qdf_ret_status = sme_configure_app_type2_params(hHal, &params);
2088 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302089 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002090 FL("sme_configure_app_type2_params returned failure %d"),
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05302091 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002092 return -EPERM;
2093 }
2094
2095 return 0;
2096}
2097
2098static int hdd_set_app_type2_parser(hdd_adapter_t *adapter,
2099 char *arg, int len)
2100{
2101 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2102 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
2103 char mac_addr[20], rc4_key[20];
Anurag Chouhan6d760662016-02-20 16:05:43 +05302104 unsigned int gateway_mac[QDF_MAC_ADDR_SIZE];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002105 tSirAppType2Params params;
2106 int ret;
2107
2108 ret = wlan_hdd_validate_context(hdd_ctx);
2109 if (0 != ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302110 hddLog(QDF_TRACE_LEVEL_ERROR, FL("HDD context is not valid"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002111 return -EINVAL;
2112 }
2113
2114 memset(&params, 0, sizeof(tSirAppType2Params));
2115
Bhargav Shahf4fd97d2015-07-08 10:21:37 +05302116 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 -08002117 mac_addr, rc4_key, (unsigned int *)&params.ip_id,
2118 (unsigned int *)&params.ip_device_ip,
2119 (unsigned int *)&params.ip_server_ip,
2120 (unsigned int *)&params.tcp_seq,
2121 (unsigned int *)&params.tcp_ack_seq,
Bhargav Shahf4fd97d2015-07-08 10:21:37 +05302122 (uint16_t *)&params.tcp_src_port,
2123 (uint16_t *)&params.tcp_dst_port,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002124 (unsigned int *)&params.keepalive_init,
2125 (unsigned int *)&params.keepalive_min,
2126 (unsigned int *)&params.keepalive_max,
2127 (unsigned int *)&params.keepalive_inc,
2128 (unsigned int *)&params.tcp_tx_timeout_val,
2129 (unsigned int *)&params.tcp_rx_timeout_val);
2130
2131 if (ret != 15 && ret != 7) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302132 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002133 "Invalid Number of arguments");
2134 return -EINVAL;
2135 }
2136
2137 if (6 !=
2138 sscanf(mac_addr, "%02x:%02x:%02x:%02x:%02x:%02x", &gateway_mac[0],
2139 &gateway_mac[1], &gateway_mac[2], &gateway_mac[3],
2140 &gateway_mac[4], &gateway_mac[5])) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302141 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002142 "Invalid MacAddress Input %s", mac_addr);
2143 return -EINVAL;
2144 }
2145
2146 if (params.tcp_src_port > WLAN_HDD_MAX_TCP_PORT ||
2147 params.tcp_dst_port > WLAN_HDD_MAX_TCP_PORT) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302148 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002149 "Invalid TCP Port Number");
2150 return -EINVAL;
2151 }
2152
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302153 qdf_mem_copy(&params.gateway_mac.bytes, (uint8_t *) &gateway_mac,
Anurag Chouhan6d760662016-02-20 16:05:43 +05302154 QDF_MAC_ADDR_SIZE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002155
2156 params.rc4_key_len = strlen(rc4_key);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302157 qdf_mem_copy(params.rc4_key, rc4_key, params.rc4_key_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002158
2159 params.vdev_id = adapter->sessionId;
2160 params.tcp_src_port = (params.tcp_src_port != 0) ?
2161 params.tcp_src_port : hdd_ctx->config->extWowApp2TcpSrcPort;
2162 params.tcp_dst_port = (params.tcp_dst_port != 0) ?
2163 params.tcp_dst_port : hdd_ctx->config->extWowApp2TcpDstPort;
2164 params.keepalive_init = (params.keepalive_init != 0) ?
2165 params.keepalive_init : hdd_ctx->config->
2166 extWowApp2KAInitPingInterval;
2167 params.keepalive_min =
2168 (params.keepalive_min != 0) ?
2169 params.keepalive_min :
2170 hdd_ctx->config->extWowApp2KAMinPingInterval;
2171 params.keepalive_max =
2172 (params.keepalive_max != 0) ?
2173 params.keepalive_max :
2174 hdd_ctx->config->extWowApp2KAMaxPingInterval;
2175 params.keepalive_inc =
2176 (params.keepalive_inc != 0) ?
2177 params.keepalive_inc :
2178 hdd_ctx->config->extWowApp2KAIncPingInterval;
2179 params.tcp_tx_timeout_val =
2180 (params.tcp_tx_timeout_val != 0) ?
2181 params.tcp_tx_timeout_val :
2182 hdd_ctx->config->extWowApp2TcpTxTimeout;
2183 params.tcp_rx_timeout_val =
2184 (params.tcp_rx_timeout_val != 0) ?
2185 params.tcp_rx_timeout_val :
2186 hdd_ctx->config->extWowApp2TcpRxTimeout;
2187
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302188 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002189 "%s: %pM %.16s %u %u %u %u %u %u %u %u %u %u %u %u %u",
2190 __func__, gateway_mac, rc4_key, params.ip_id,
2191 params.ip_device_ip, params.ip_server_ip, params.tcp_seq,
2192 params.tcp_ack_seq, params.tcp_src_port, params.tcp_dst_port,
2193 params.keepalive_init, params.keepalive_min,
2194 params.keepalive_max, params.keepalive_inc,
2195 params.tcp_tx_timeout_val, params.tcp_rx_timeout_val);
2196
2197 return hdd_set_app_type2_params(hHal, &params);
2198}
2199#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
2200
2201/**
2202 * hdd_parse_setmaxtxpower_command() - HDD Parse MAXTXPOWER command
2203 * @pValue: Pointer to MAXTXPOWER command
2204 * @pDbm: Pointer to tx power
2205 *
2206 * This function parses the MAXTXPOWER command passed in the format
2207 * MAXTXPOWER<space>X(Tx power in dbm)
2208 *
2209 * For example input commands:
2210 * 1) MAXTXPOWER -8 -> This is translated into set max TX power to -8 dbm
2211 * 2) MAXTXPOWER -23 -> This is translated into set max TX power to -23 dbm
2212 *
2213 * Return: 0 for success non-zero for failure
2214 */
2215static int hdd_parse_setmaxtxpower_command(uint8_t *pValue, int *pTxPower)
2216{
2217 uint8_t *inPtr = pValue;
2218 int tempInt;
2219 int v = 0;
2220 *pTxPower = 0;
2221
2222 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2223 /* no argument after the command */
2224 if (NULL == inPtr) {
2225 return -EINVAL;
2226 }
2227
2228 /* no space after the command */
2229 else if (SPACE_ASCII_VALUE != *inPtr) {
2230 return -EINVAL;
2231 }
2232
2233 /* remove empty spaces */
2234 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2235 inPtr++;
2236
2237 /* no argument followed by spaces */
2238 if ('\0' == *inPtr) {
2239 return 0;
2240 }
2241
2242 v = kstrtos32(inPtr, 10, &tempInt);
2243
2244 /* Range checking for passed parameter */
2245 if ((tempInt < HDD_MIN_TX_POWER) || (tempInt > HDD_MAX_TX_POWER)) {
2246 return -EINVAL;
2247 }
2248
2249 *pTxPower = tempInt;
2250
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302251 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002252 "SETMAXTXPOWER: %d", *pTxPower);
2253
2254 return 0;
2255} /* End of hdd_parse_setmaxtxpower_command */
2256
2257static int hdd_get_dwell_time(struct hdd_config *pCfg, uint8_t *command,
2258 char *extra, uint8_t n, uint8_t *len)
2259{
2260 int ret = 0;
2261
2262 if (!pCfg || !command || !extra || !len) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302263 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002264 "%s: argument passed for GETDWELLTIME is incorrect",
2265 __func__);
2266 ret = -EINVAL;
2267 return ret;
2268 }
2269
2270 if (strncmp(command, "GETDWELLTIME ACTIVE MAX", 23) == 0) {
2271 *len = scnprintf(extra, n, "GETDWELLTIME ACTIVE MAX %u\n",
2272 (int)pCfg->nActiveMaxChnTime);
2273 return ret;
2274 } else if (strncmp(command, "GETDWELLTIME ACTIVE MIN", 23) == 0) {
2275 *len = scnprintf(extra, n, "GETDWELLTIME ACTIVE MIN %u\n",
2276 (int)pCfg->nActiveMinChnTime);
2277 return ret;
2278 } else if (strncmp(command, "GETDWELLTIME PASSIVE MAX", 24) == 0) {
2279 *len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MAX %u\n",
2280 (int)pCfg->nPassiveMaxChnTime);
2281 return ret;
2282 } else if (strncmp(command, "GETDWELLTIME PASSIVE MIN", 24) == 0) {
2283 *len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MIN %u\n",
2284 (int)pCfg->nPassiveMinChnTime);
2285 return ret;
2286 } else if (strncmp(command, "GETDWELLTIME", 12) == 0) {
2287 *len = scnprintf(extra, n, "GETDWELLTIME %u \n",
2288 (int)pCfg->nActiveMaxChnTime);
2289 return ret;
2290 } else {
2291 ret = -EINVAL;
2292 }
2293
2294 return ret;
2295}
2296
2297static int hdd_set_dwell_time(hdd_adapter_t *adapter, uint8_t *command)
2298{
2299 tHalHandle hHal;
2300 struct hdd_config *pCfg;
2301 uint8_t *value = command;
2302 tSmeConfigParams smeConfig;
2303 int val = 0, temp = 0;
2304
2305 pCfg = (WLAN_HDD_GET_CTX(adapter))->config;
2306 hHal = WLAN_HDD_GET_HAL_CTX(adapter);
2307 if (!pCfg || !hHal) {
2308 hddLog(LOGE,
2309 FL("argument passed for SETDWELLTIME is incorrect"));
2310 return -EINVAL;
2311 }
2312
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302313 qdf_mem_zero(&smeConfig, sizeof(smeConfig));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002314 sme_get_config_param(hHal, &smeConfig);
2315
2316 if (strncmp(command, "SETDWELLTIME ACTIVE MAX", 23) == 0) {
2317 value = value + 24;
2318 temp = kstrtou32(value, 10, &val);
2319 if (temp != 0 || val < CFG_ACTIVE_MAX_CHANNEL_TIME_MIN ||
2320 val > CFG_ACTIVE_MAX_CHANNEL_TIME_MAX) {
2321 hddLog(LOGE,
2322 FL("argument passed for SETDWELLTIME ACTIVE MAX is incorrect"));
2323 return -EFAULT;
2324 }
2325 pCfg->nActiveMaxChnTime = val;
2326 smeConfig.csrConfig.nActiveMaxChnTime = val;
2327 sme_update_config(hHal, &smeConfig);
2328 } else if (strncmp(command, "SETDWELLTIME ACTIVE MIN", 23) == 0) {
2329 value = value + 24;
2330 temp = kstrtou32(value, 10, &val);
2331 if (temp != 0 || val < CFG_ACTIVE_MIN_CHANNEL_TIME_MIN ||
2332 val > CFG_ACTIVE_MIN_CHANNEL_TIME_MAX) {
2333 hddLog(LOGE,
2334 FL("argument passed for SETDWELLTIME ACTIVE MIN is incorrect"));
2335 return -EFAULT;
2336 }
2337 pCfg->nActiveMinChnTime = val;
2338 smeConfig.csrConfig.nActiveMinChnTime = val;
2339 sme_update_config(hHal, &smeConfig);
2340 } else if (strncmp(command, "SETDWELLTIME PASSIVE MAX", 24) == 0) {
2341 value = value + 25;
2342 temp = kstrtou32(value, 10, &val);
2343 if (temp != 0 || val < CFG_PASSIVE_MAX_CHANNEL_TIME_MIN ||
2344 val > CFG_PASSIVE_MAX_CHANNEL_TIME_MAX) {
2345 hddLog(LOGE,
2346 FL("argument passed for SETDWELLTIME PASSIVE MAX is incorrect"));
2347 return -EFAULT;
2348 }
2349 pCfg->nPassiveMaxChnTime = val;
2350 smeConfig.csrConfig.nPassiveMaxChnTime = val;
2351 sme_update_config(hHal, &smeConfig);
2352 } else if (strncmp(command, "SETDWELLTIME PASSIVE MIN", 24) == 0) {
2353 value = value + 25;
2354 temp = kstrtou32(value, 10, &val);
2355 if (temp != 0 || val < CFG_PASSIVE_MIN_CHANNEL_TIME_MIN ||
2356 val > CFG_PASSIVE_MIN_CHANNEL_TIME_MAX) {
2357 hddLog(LOGE,
2358 FL("argument passed for SETDWELLTIME PASSIVE MIN is incorrect"));
2359 return -EFAULT;
2360 }
2361 pCfg->nPassiveMinChnTime = val;
2362 smeConfig.csrConfig.nPassiveMinChnTime = val;
2363 sme_update_config(hHal, &smeConfig);
2364 } else if (strncmp(command, "SETDWELLTIME", 12) == 0) {
2365 value = value + 13;
2366 temp = kstrtou32(value, 10, &val);
2367 if (temp != 0 || val < CFG_ACTIVE_MAX_CHANNEL_TIME_MIN ||
2368 val > CFG_ACTIVE_MAX_CHANNEL_TIME_MAX) {
2369 hddLog(LOGE,
2370 FL("argument passed for SETDWELLTIME is incorrect"));
2371 return -EFAULT;
2372 }
2373 pCfg->nActiveMaxChnTime = val;
2374 smeConfig.csrConfig.nActiveMaxChnTime = val;
2375 sme_update_config(hHal, &smeConfig);
2376 } else {
2377 return -EINVAL;
2378 }
2379
2380 return 0;
2381}
2382
2383static void hdd_get_link_status_cb(uint8_t status, void *context)
2384{
2385 struct statsContext *pLinkContext;
2386 hdd_adapter_t *adapter;
2387
2388 if (NULL == context) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302389 hddLog(QDF_TRACE_LEVEL_ERROR, "%s: Bad context [%p]",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002390 __func__, context);
2391 return;
2392 }
2393
2394 pLinkContext = context;
2395 adapter = pLinkContext->pAdapter;
2396
2397 spin_lock(&hdd_context_lock);
2398
2399 if ((NULL == adapter) ||
2400 (LINK_STATUS_MAGIC != pLinkContext->magic)) {
2401 /*
2402 * the caller presumably timed out so there is
2403 * nothing we can do
2404 */
2405 spin_unlock(&hdd_context_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302406 hddLog(QDF_TRACE_LEVEL_WARN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002407 "%s: Invalid context, adapter [%p] magic [%08x]",
2408 __func__, adapter, pLinkContext->magic);
2409 return;
2410 }
2411
2412 /* context is valid so caller is still waiting */
2413
2414 /* paranoia: invalidate the magic */
2415 pLinkContext->magic = 0;
2416
2417 /* copy over the status */
2418 adapter->linkStatus = status;
2419
2420 /* notify the caller */
2421 complete(&pLinkContext->completion);
2422
2423 /* serialization is complete */
2424 spin_unlock(&hdd_context_lock);
2425}
2426
2427/**
2428 * wlan_hdd_get_link_status() - get link status
2429 * @pAdapter: pointer to the adapter
2430 *
2431 * This function sends a request to query the link status and waits
2432 * on a timer to invoke the callback. if the callback is invoked then
2433 * latest link status shall be returned or otherwise cached value
2434 * will be returned.
2435 *
2436 * Return: On success, link status shall be returned.
2437 * On error or not associated, link status 0 will be returned.
2438 */
2439static int wlan_hdd_get_link_status(hdd_adapter_t *adapter)
2440{
2441
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002442 hdd_station_ctx_t *pHddStaCtx =
2443 WLAN_HDD_GET_STATION_CTX_PTR(adapter);
2444 struct statsContext context;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302445 QDF_STATUS hstatus;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002446 unsigned long rc;
2447
Prashanth Bhatta9e143052015-12-04 11:56:47 -08002448 if (cds_is_driver_recovering()) {
2449 hdd_warn("Recovery in Progress. State: 0x%x Ignore!!!",
2450 cds_get_driver_state());
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002451 return 0;
2452 }
2453
Krunal Sonibe766b02016-03-10 13:00:44 -08002454 if ((QDF_STA_MODE != adapter->device_mode) &&
2455 (QDF_P2P_CLIENT_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002456 hdd_warn("Unsupported in mode %s(%d)",
2457 hdd_device_mode_to_string(adapter->device_mode),
2458 adapter->device_mode);
2459 return 0;
2460 }
2461
2462 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
2463 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
2464 /* If not associated, then expected link status return
2465 * value is 0
2466 */
2467 hddLog(LOG1, FL("Not associated!"));
2468 return 0;
2469 }
2470
2471 init_completion(&context.completion);
2472 context.pAdapter = adapter;
2473 context.magic = LINK_STATUS_MAGIC;
2474 hstatus = sme_get_link_status(WLAN_HDD_GET_HAL_CTX(adapter),
2475 hdd_get_link_status_cb,
2476 &context, adapter->sessionId);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302477 if (QDF_STATUS_SUCCESS != hstatus) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302478 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002479 "%s: Unable to retrieve link status", __func__);
2480 /* return a cached value */
2481 } else {
2482 /* request is sent -- wait for the response */
2483 rc = wait_for_completion_timeout(&context.completion,
2484 msecs_to_jiffies(WLAN_WAIT_TIME_LINK_STATUS));
2485 if (!rc)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302486 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002487 FL("SME timed out while retrieving link status"));
2488 }
2489
2490 spin_lock(&hdd_context_lock);
2491 context.magic = 0;
2492 spin_unlock(&hdd_context_lock);
2493
2494 /* either callback updated adapter stats or it has cached data */
2495 return adapter->linkStatus;
2496}
2497
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002498static void hdd_tx_fail_ind_callback(uint8_t *MacAddr, uint8_t seqNo)
2499{
2500 int payload_len;
2501 struct sk_buff *skb;
2502 struct nlmsghdr *nlh;
2503 uint8_t *data;
2504
2505 payload_len = ETH_ALEN;
2506
2507 if (0 == cesium_pid) {
2508 hddLog(QDF_TRACE_LEVEL_ERROR,
2509 "%s: cesium process not registered", __func__);
2510 return;
2511 }
2512
2513 skb = nlmsg_new(payload_len, GFP_ATOMIC);
2514 if (skb == NULL) {
2515 hddLog(LOGE,
2516 FL("nlmsg_new() failed for msg size[%d]"),
2517 NLMSG_SPACE(payload_len));
2518 return;
2519 }
2520
2521 nlh = nlmsg_put(skb, cesium_pid, seqNo, 0, payload_len, NLM_F_REQUEST);
2522
2523 if (NULL == nlh) {
2524 hddLog(QDF_TRACE_LEVEL_ERROR,
2525 "%s: nlmsg_put() failed for msg size[%d]",
2526 __func__, NLMSG_SPACE(payload_len));
2527
2528 kfree_skb(skb);
2529 return;
2530 }
2531
2532 data = nlmsg_data(nlh);
2533 memcpy(data, MacAddr, ETH_ALEN);
2534
2535 if (nlmsg_unicast(cesium_nl_srv_sock, skb, cesium_pid) < 0) {
2536 hddLog(QDF_TRACE_LEVEL_ERROR,
2537 "%s: nlmsg_unicast() failed for msg size[%d]",
2538 __func__, NLMSG_SPACE(payload_len));
2539 }
2540
2541 return;
2542}
2543
2544
2545/**
2546 * hdd_ParseuserParams - return a pointer to the next argument
2547 * @pValue: Input argument string
2548 * @ppArg: Output pointer to the next argument
2549 *
2550 * This function parses argument stream and finds the pointer
2551 * to the next argument
2552 *
2553 * Return: 0 if the next argument found; -EINVAL otherwise
2554 */
2555static int hdd_parse_user_params(uint8_t *pValue, uint8_t **ppArg)
2556{
2557 uint8_t *pVal;
2558
2559 pVal = strnchr(pValue, strlen(pValue), ' ');
2560
2561 if (NULL == pVal) {
2562 /* no argument remains */
2563 return -EINVAL;
2564 } else if (SPACE_ASCII_VALUE != *pVal) {
2565 /* no space after the current argument */
2566 return -EINVAL;
2567 }
2568
2569 pVal++;
2570
2571 /* remove empty spaces */
2572 while ((SPACE_ASCII_VALUE == *pVal) && ('\0' != *pVal)) {
2573 pVal++;
2574 }
2575
2576 /* no argument followed by spaces */
2577 if ('\0' == *pVal) {
2578 return -EINVAL;
2579 }
2580
2581 *ppArg = pVal;
2582
2583 return 0;
2584}
2585
2586/**
2587 * hdd_parse_ibsstx_fail_event_params - Parse params
2588 * for SETIBSSTXFAILEVENT
2589 * @pValue: Input ibss tx fail event argument
2590 * @tx_fail_count: (Output parameter) Tx fail counter
2591 * @pid: (Output parameter) PID
2592 *
2593 * Return: 0 if the parsing succeeds; -EINVAL otherwise
2594 */
2595static int hdd_parse_ibsstx_fail_event_params(uint8_t *pValue,
2596 uint8_t *tx_fail_count,
2597 uint16_t *pid)
2598{
2599 uint8_t *param = NULL;
2600 int ret;
2601
2602 ret = hdd_parse_user_params(pValue, &param);
2603
2604 if (0 == ret && NULL != param) {
2605 if (1 != sscanf(param, "%hhu", tx_fail_count)) {
2606 ret = -EINVAL;
2607 goto done;
2608 }
2609 } else {
2610 goto done;
2611 }
2612
2613 if (0 == *tx_fail_count) {
2614 *pid = 0;
2615 goto done;
2616 }
2617
2618 pValue = param;
2619 pValue++;
2620
2621 ret = hdd_parse_user_params(pValue, &param);
2622
2623 if (0 == ret) {
2624 if (1 != sscanf(param, "%hu", pid)) {
2625 ret = -EINVAL;
2626 goto done;
2627 }
2628 } else {
2629 goto done;
2630 }
2631
2632done:
2633 return ret;
2634}
2635
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08002636#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002637/**
2638 * hdd_parse_ese_beacon_req() - Parse ese beacon request
2639 * @pValue: Pointer to data
2640 * @pEseBcnReq: Output pointer to store parsed ie information
2641 *
2642 * This function parses the ese beacon request passed in the format
2643 * CCXBEACONREQ<space><Number of fields><space><Measurement token>
2644 * <space>Channel 1<space>Scan Mode <space>Meas Duration<space>Channel N
2645 * <space>Scan Mode N<space>Meas Duration N
2646 *
2647 * If the Number of bcn req fields (N) does not match with the
2648 * actual number of fields passed then take N.
2649 * <Meas Token><Channel><Scan Mode> and <Meas Duration> are treated
2650 * as one pair. For example, CCXBEACONREQ 2 1 1 1 30 2 44 0 40.
2651 * This function does not take care of removing duplicate channels from the
2652 * list
2653 *
2654 * Return: 0 for success non-zero for failure
2655 */
2656static int hdd_parse_ese_beacon_req(uint8_t *pValue,
2657 tCsrEseBeaconReq *pEseBcnReq)
2658{
2659 uint8_t *inPtr = pValue;
2660 int tempInt = 0;
2661 int j = 0, i = 0, v = 0;
2662 char buf[32];
2663
2664 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2665 /* no argument after the command */
2666 if (NULL == inPtr) {
2667 return -EINVAL;
2668 }
2669 /* no space after the command */
2670 else if (SPACE_ASCII_VALUE != *inPtr) {
2671 return -EINVAL;
2672 }
2673
2674 /* remove empty spaces */
2675 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2676 inPtr++;
2677
2678 /* no argument followed by spaces */
2679 if ('\0' == *inPtr)
2680 return -EINVAL;
2681
2682 /* get the first argument ie measurement token */
2683 v = sscanf(inPtr, "%31s ", buf);
2684 if (1 != v)
2685 return -EINVAL;
2686
2687 v = kstrtos32(buf, 10, &tempInt);
2688 if (v < 0)
2689 return -EINVAL;
2690
2691 pEseBcnReq->numBcnReqIe = tempInt;
2692
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302693 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002694 "Number of Bcn Req Ie fields(%d)", pEseBcnReq->numBcnReqIe);
2695
2696 for (j = 0; j < (pEseBcnReq->numBcnReqIe); j++) {
2697 for (i = 0; i < 4; i++) {
2698 /*
2699 * inPtr pointing to the beginning of 1st space
2700 * after number of ie fields
2701 */
2702 inPtr = strpbrk(inPtr, " ");
2703 /* no ie data after the number of ie fields argument */
2704 if (NULL == inPtr)
2705 return -EINVAL;
2706
2707 /* remove empty space */
2708 while ((SPACE_ASCII_VALUE == *inPtr)
2709 && ('\0' != *inPtr))
2710 inPtr++;
2711
2712 /*
2713 * no ie data after the number of ie fields
2714 * argument and spaces
2715 */
2716 if ('\0' == *inPtr)
2717 return -EINVAL;
2718
2719 v = sscanf(inPtr, "%31s ", buf);
2720 if (1 != v)
2721 return -EINVAL;
2722
2723 v = kstrtos32(buf, 10, &tempInt);
2724 if (v < 0)
2725 return -EINVAL;
2726
2727 switch (i) {
2728 case 0: /* Measurement token */
2729 if (tempInt <= 0) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302730 QDF_TRACE(QDF_MODULE_ID_HDD,
2731 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002732 "Invalid Measurement Token(%d)",
2733 tempInt);
2734 return -EINVAL;
2735 }
2736 pEseBcnReq->bcnReq[j].measurementToken =
2737 tempInt;
2738 break;
2739
2740 case 1: /* Channel number */
2741 if ((tempInt <= 0) ||
2742 (tempInt >
2743 WNI_CFG_CURRENT_CHANNEL_STAMAX)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302744 QDF_TRACE(QDF_MODULE_ID_HDD,
2745 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002746 "Invalid Channel Number(%d)",
2747 tempInt);
2748 return -EINVAL;
2749 }
2750 pEseBcnReq->bcnReq[j].channel = tempInt;
2751 break;
2752
2753 case 2: /* Scan mode */
2754 if ((tempInt < eSIR_PASSIVE_SCAN)
2755 || (tempInt > eSIR_BEACON_TABLE)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302756 QDF_TRACE(QDF_MODULE_ID_HDD,
2757 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002758 "Invalid Scan Mode(%d) Expected{0|1|2}",
2759 tempInt);
2760 return -EINVAL;
2761 }
2762 pEseBcnReq->bcnReq[j].scanMode = tempInt;
2763 break;
2764
2765 case 3: /* Measurement duration */
2766 if (((tempInt <= 0)
2767 && (pEseBcnReq->bcnReq[j].scanMode !=
2768 eSIR_BEACON_TABLE)) ||
2769 ((tempInt < 0) &&
2770 (pEseBcnReq->bcnReq[j].scanMode ==
2771 eSIR_BEACON_TABLE))) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302772 QDF_TRACE(QDF_MODULE_ID_HDD,
2773 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002774 "Invalid Measurement Duration(%d)",
2775 tempInt);
2776 return -EINVAL;
2777 }
2778 pEseBcnReq->bcnReq[j].measurementDuration =
2779 tempInt;
2780 break;
2781 }
2782 }
2783 }
2784
2785 for (j = 0; j < pEseBcnReq->numBcnReqIe; j++) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302786 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002787 "Index(%d) Measurement Token(%u) Channel(%u) Scan Mode(%u) Measurement Duration(%u)",
2788 j,
2789 pEseBcnReq->bcnReq[j].measurementToken,
2790 pEseBcnReq->bcnReq[j].channel,
2791 pEseBcnReq->bcnReq[j].scanMode,
2792 pEseBcnReq->bcnReq[j].measurementDuration);
2793 }
2794
2795 return 0;
2796}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002797
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002798/**
2799 * hdd_parse_get_cckm_ie() - HDD Parse and fetch the CCKM IE
2800 * @pValue: Pointer to input data
2801 * @pCckmIe: Pointer to output cckm Ie
2802 * @pCckmIeLen: Pointer to output cckm ie length
2803 *
2804 * This function parses the SETCCKM IE command
2805 * SETCCKMIE<space><ie data>
2806 *
2807 * Return: 0 for success non-zero for failure
2808 */
2809static int hdd_parse_get_cckm_ie(uint8_t *pValue, uint8_t **pCckmIe,
2810 uint8_t *pCckmIeLen)
2811{
2812 uint8_t *inPtr = pValue;
2813 uint8_t *dataEnd;
2814 int j = 0;
2815 int i = 0;
2816 uint8_t tempByte = 0;
2817 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2818 /* no argument after the command */
2819 if (NULL == inPtr) {
2820 return -EINVAL;
2821 }
2822 /* no space after the command */
2823 else if (SPACE_ASCII_VALUE != *inPtr) {
2824 return -EINVAL;
2825 }
2826 /* remove empty spaces */
2827 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2828 inPtr++;
2829 /* no argument followed by spaces */
2830 if ('\0' == *inPtr) {
2831 return -EINVAL;
2832 }
2833 /* find the length of data */
2834 dataEnd = inPtr;
2835 while (('\0' != *dataEnd)) {
2836 dataEnd++;
2837 ++(*pCckmIeLen);
2838 }
2839 if (*pCckmIeLen <= 0)
2840 return -EINVAL;
2841 /*
2842 * Allocate the number of bytes based on the number of input characters
2843 * whether it is even or odd.
2844 * if the number of input characters are even, then we need N / 2 byte.
2845 * if the number of input characters are odd, then we need do
2846 * (N + 1) / 2 to compensate rounding off.
2847 * For example, if N = 18, then (18 + 1) / 2 = 9 bytes are enough.
2848 * If N = 19, then we need 10 bytes, hence (19 + 1) / 2 = 10 bytes
2849 */
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302850 *pCckmIe = qdf_mem_malloc((*pCckmIeLen + 1) / 2);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002851 if (NULL == *pCckmIe) {
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05302852 hddLog(LOGE, FL("qdf_mem_malloc failed"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002853 return -ENOMEM;
2854 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302855 qdf_mem_zero(*pCckmIe, (*pCckmIeLen + 1) / 2);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002856 /*
2857 * the buffer received from the upper layer is character buffer,
2858 * we need to prepare the buffer taking 2 characters in to a U8 hex
2859 * decimal number for example 7f0000f0...form a buffer to contain
2860 * 7f in 0th location, 00 in 1st and f0 in 3rd location
2861 */
2862 for (i = 0, j = 0; j < *pCckmIeLen; j += 2) {
2863 tempByte = (hex_to_bin(inPtr[j]) << 4) |
2864 (hex_to_bin(inPtr[j + 1]));
2865 (*pCckmIe)[i++] = tempByte;
2866 }
2867 *pCckmIeLen = i;
2868 return 0;
2869}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08002870#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002871
2872int wlan_hdd_set_mc_rate(hdd_adapter_t *pAdapter, int targetRate)
2873{
2874 tSirRateUpdateInd rateUpdate = {0};
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302875 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002876 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
2877 struct hdd_config *pConfig = NULL;
2878
2879 if (pHddCtx == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302880 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002881 "%s: HDD context is null", __func__);
2882 return -EINVAL;
2883 }
Krunal Sonibe766b02016-03-10 13:00:44 -08002884 if ((QDF_IBSS_MODE != pAdapter->device_mode) &&
2885 (QDF_SAP_MODE != pAdapter->device_mode) &&
2886 (QDF_STA_MODE != pAdapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002887 hddLog(LOGE,
2888 FL("Received SETMCRATE cmd in invalid mode %s(%d)"),
2889 hdd_device_mode_to_string(pAdapter->device_mode),
2890 pAdapter->device_mode);
2891 hddLog(LOGE,
2892 FL("SETMCRATE cmd is allowed only in STA, IBSS or SOFTAP mode"));
2893 return -EINVAL;
2894 }
2895 pConfig = pHddCtx->config;
2896 rateUpdate.nss = (pConfig->enable2x2 == 0) ? 0 : 1;
2897 rateUpdate.dev_mode = pAdapter->device_mode;
2898 rateUpdate.mcastDataRate24GHz = targetRate;
2899 rateUpdate.mcastDataRate24GHzTxFlag = 1;
2900 rateUpdate.mcastDataRate5GHz = targetRate;
2901 rateUpdate.bcastDataRate = -1;
Anurag Chouhanc5548422016-02-24 18:33:27 +05302902 qdf_copy_macaddr(&rateUpdate.bssid, &pAdapter->macAddressCurrent);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002903 hddLog(LOG1,
2904 FL("MC Target rate %d, mac = %pM, dev_mode %s(%d)"),
Srinivas Girigowdaafede182015-11-18 22:36:12 -08002905 rateUpdate.mcastDataRate24GHz, rateUpdate.bssid.bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002906 hdd_device_mode_to_string(pAdapter->device_mode),
2907 pAdapter->device_mode);
2908 status = sme_send_rate_update_ind(pHddCtx->hHal, &rateUpdate);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302909 if (QDF_STATUS_SUCCESS != status) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302910 hddLog(QDF_TRACE_LEVEL_ERROR, "%s: SETMCRATE failed",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002911 __func__);
2912 return -EFAULT;
2913 }
2914 return 0;
2915}
2916
2917static int drv_cmd_p2p_dev_addr(hdd_adapter_t *adapter,
2918 hdd_context_t *hdd_ctx,
2919 uint8_t *command,
2920 uint8_t command_len,
2921 hdd_priv_data_t *priv_data)
2922{
2923 int ret = 0;
2924
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302925 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002926 TRACE_CODE_HDD_P2P_DEV_ADDR_IOCTL,
2927 adapter->sessionId,
2928 (unsigned)(*(hdd_ctx->p2pDeviceAddress.bytes + 2)
2929 << 24 | *(hdd_ctx->p2pDeviceAddress.bytes
2930 + 3) << 16 | *(hdd_ctx->
2931 p2pDeviceAddress.bytes + 4) << 8 |
2932 *(hdd_ctx->p2pDeviceAddress.bytes +
2933 5))));
2934
2935 if (copy_to_user(priv_data->buf, hdd_ctx->p2pDeviceAddress.bytes,
2936 sizeof(tSirMacAddr))) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302937 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002938 "%s: failed to copy data to user buffer",
2939 __func__);
2940 ret = -EFAULT;
2941 }
2942
2943 return ret;
2944}
2945
2946/**
2947 * drv_cmd_p2p_set_noa() - Handler for P2P_SET_NOA driver command
2948 * @adapter: Adapter on which the command was received
2949 * @hdd_ctx: HDD global context
2950 * @command: Entire driver command received from userspace
2951 * @command_len: Length of @command
2952 * @priv_data: Pointer to ioctl private data structure
2953 *
2954 * This is a trivial command hander function which simply forwards the
2955 * command to the actual command processor within the P2P module.
2956 *
2957 * Return: 0 on success, non-zero on failure
2958 */
2959static int drv_cmd_p2p_set_noa(hdd_adapter_t *adapter,
2960 hdd_context_t *hdd_ctx,
2961 uint8_t *command,
2962 uint8_t command_len,
2963 hdd_priv_data_t *priv_data)
2964{
2965 return hdd_set_p2p_noa(adapter->dev, command);
2966}
2967
2968/**
2969 * drv_cmd_p2p_set_ps() - Handler for P2P_SET_PS driver command
2970 * @adapter: Adapter on which the command was received
2971 * @hdd_ctx: HDD global context
2972 * @command: Entire driver command received from userspace
2973 * @command_len: Length of @command
2974 * @priv_data: Pointer to ioctl private data structure
2975 *
2976 * This is a trivial command hander function which simply forwards the
2977 * command to the actual command processor within the P2P module.
2978 *
2979 * Return: 0 on success, non-zero on failure
2980 */
2981static int drv_cmd_p2p_set_ps(hdd_adapter_t *adapter,
2982 hdd_context_t *hdd_ctx,
2983 uint8_t *command,
2984 uint8_t command_len,
2985 hdd_priv_data_t *priv_data)
2986{
2987 return hdd_set_p2p_opps(adapter->dev, command);
2988}
2989
2990static int drv_cmd_set_band(hdd_adapter_t *adapter,
2991 hdd_context_t *hdd_ctx,
2992 uint8_t *command,
2993 uint8_t command_len,
2994 hdd_priv_data_t *priv_data)
2995{
2996 int ret = 0;
2997
2998 uint8_t *ptr = command;
2999
3000 /* Change band request received */
3001
3002 /*
3003 * First 8 bytes will have "SETBAND " and
3004 * 9 byte will have band setting value
3005 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303006 hddLog(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003007 "%s: SetBandCommand Info comm %s UL %d, TL %d",
3008 __func__, command, priv_data->used_len,
3009 priv_data->total_len);
3010
3011 /* Change band request received */
3012 ret = hdd_set_band_helper(adapter->dev, ptr);
3013
3014 return ret;
3015}
3016
3017static int drv_cmd_set_wmmps(hdd_adapter_t *adapter,
3018 hdd_context_t *hdd_ctx,
3019 uint8_t *command,
3020 uint8_t command_len,
3021 hdd_priv_data_t *priv_data)
3022{
3023 return hdd_wmmps_helper(adapter, command);
3024}
3025
3026static int drv_cmd_country(hdd_adapter_t *adapter,
3027 hdd_context_t *hdd_ctx,
3028 uint8_t *command,
3029 uint8_t command_len,
3030 hdd_priv_data_t *priv_data)
3031{
3032 int ret = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303033 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003034 unsigned long rc;
3035 char *country_code;
3036
3037 country_code = command + 8;
3038
3039 INIT_COMPLETION(adapter->change_country_code);
3040
3041 status = sme_change_country_code(hdd_ctx->hHal,
3042 wlan_hdd_change_country_code_callback,
3043 country_code,
3044 adapter,
3045 hdd_ctx->pcds_context,
3046 eSIR_TRUE,
3047 eSIR_TRUE);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303048 if (status == QDF_STATUS_SUCCESS) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003049 rc = wait_for_completion_timeout(
3050 &adapter->change_country_code,
3051 msecs_to_jiffies(WLAN_WAIT_TIME_COUNTRY));
3052 if (!rc)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303053 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003054 "%s: SME while setting country code timed out",
3055 __func__);
3056 } else {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303057 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003058 "%s: SME Change Country code fail, status=%d",
3059 __func__, status);
3060 ret = -EINVAL;
3061 }
3062
3063 return ret;
3064}
3065
3066static int drv_cmd_set_roam_trigger(hdd_adapter_t *adapter,
3067 hdd_context_t *hdd_ctx,
3068 uint8_t *command,
3069 uint8_t command_len,
3070 hdd_priv_data_t *priv_data)
3071{
3072 int ret = 0;
3073 uint8_t *value = command;
3074 int8_t rssi = 0;
3075 uint8_t lookUpThreshold = CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_DEFAULT;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303076 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003077
3078 /* Move pointer to ahead of SETROAMTRIGGER<delimiter> */
3079 value = value + command_len + 1;
3080
3081 /* Convert the value from ascii to integer */
3082 ret = kstrtos8(value, 10, &rssi);
3083 if (ret < 0) {
3084 /*
3085 * If the input value is greater than max value of datatype,
3086 * then also kstrtou8 fails
3087 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303088 QDF_TRACE(QDF_MODULE_ID_HDD,
3089 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003090 "%s: kstrtou8 failed Input value may be out of range[%d - %d]",
3091 __func__,
3092 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN,
3093 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX);
3094 ret = -EINVAL;
3095 goto exit;
3096 }
3097
3098 lookUpThreshold = abs(rssi);
3099
3100 if ((lookUpThreshold < CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN)
3101 || (lookUpThreshold > CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303102 QDF_TRACE(QDF_MODULE_ID_HDD,
3103 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003104 "Neighbor lookup threshold value %d is out of range (Min: %d Max: %d)",
3105 lookUpThreshold,
3106 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN,
3107 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX);
3108 ret = -EINVAL;
3109 goto exit;
3110 }
3111
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303112 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003113 TRACE_CODE_HDD_SETROAMTRIGGER_IOCTL,
3114 adapter->sessionId, lookUpThreshold));
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303115 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003116 "%s: Received Command to Set Roam trigger (Neighbor lookup threshold) = %d",
3117 __func__,
3118 lookUpThreshold);
3119
3120 hdd_ctx->config->nNeighborLookupRssiThreshold = lookUpThreshold;
3121 status = sme_set_neighbor_lookup_rssi_threshold(hdd_ctx->hHal,
3122 adapter->sessionId,
3123 lookUpThreshold);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303124 if (QDF_STATUS_SUCCESS != status) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303125 QDF_TRACE(QDF_MODULE_ID_HDD,
3126 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003127 "%s: Failed to set roam trigger, try again",
3128 __func__);
3129 ret = -EPERM;
3130 goto exit;
3131 }
3132
3133exit:
3134 return ret;
3135}
3136
3137static int drv_cmd_get_roam_trigger(hdd_adapter_t *adapter,
3138 hdd_context_t *hdd_ctx,
3139 uint8_t *command,
3140 uint8_t command_len,
3141 hdd_priv_data_t *priv_data)
3142{
3143 int ret = 0;
3144 uint8_t lookUpThreshold =
3145 sme_get_neighbor_lookup_rssi_threshold(hdd_ctx->hHal);
3146 int rssi = (-1) * lookUpThreshold;
3147 char extra[32];
3148 uint8_t len = 0;
3149
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303150 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003151 TRACE_CODE_HDD_GETROAMTRIGGER_IOCTL,
3152 adapter->sessionId, lookUpThreshold));
3153
3154 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303155 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003156 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303157 QDF_TRACE(QDF_MODULE_ID_HDD,
3158 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003159 "%s: failed to copy data to user buffer",
3160 __func__);
3161 ret = -EFAULT;
3162 }
3163
3164 return ret;
3165}
3166
3167static int drv_cmd_set_roam_scan_period(hdd_adapter_t *adapter,
3168 hdd_context_t *hdd_ctx,
3169 uint8_t *command,
3170 uint8_t command_len,
3171 hdd_priv_data_t *priv_data)
3172{
3173 int ret = 0;
3174 uint8_t *value = command;
3175 uint8_t roamScanPeriod = 0;
3176 uint16_t neighborEmptyScanRefreshPeriod =
3177 CFG_EMPTY_SCAN_REFRESH_PERIOD_DEFAULT;
3178
3179 /* input refresh period is in terms of seconds */
3180
3181 /* Move pointer to ahead of SETROAMSCANPERIOD<delimiter> */
3182 value = value + command_len + 1;
3183
3184 /* Convert the value from ascii to integer */
3185 ret = kstrtou8(value, 10, &roamScanPeriod);
3186 if (ret < 0) {
3187 /*
3188 * If the input value is greater than max value of datatype,
3189 * then also kstrtou8 fails
3190 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303191 QDF_TRACE(QDF_MODULE_ID_HDD,
3192 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003193 "%s: kstrtou8 failed Input value may be out of range[%d - %d]",
3194 __func__,
3195 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000),
3196 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000));
3197 ret = -EINVAL;
3198 goto exit;
3199 }
3200
3201 if ((roamScanPeriod < (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000))
3202 || (roamScanPeriod > (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000))) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303203 QDF_TRACE(QDF_MODULE_ID_HDD,
3204 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003205 "Roam scan period value %d is out of range (Min: %d Max: %d)",
3206 roamScanPeriod,
3207 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000),
3208 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000));
3209 ret = -EINVAL;
3210 goto exit;
3211 }
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303212 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003213 TRACE_CODE_HDD_SETROAMSCANPERIOD_IOCTL,
3214 adapter->sessionId, roamScanPeriod));
3215 neighborEmptyScanRefreshPeriod = roamScanPeriod * 1000;
3216
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303217 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003218 "%s: Received Command to Set roam scan period (Empty Scan refresh period) = %d",
3219 __func__,
3220 roamScanPeriod);
3221
3222 hdd_ctx->config->nEmptyScanRefreshPeriod =
3223 neighborEmptyScanRefreshPeriod;
3224 sme_update_empty_scan_refresh_period(hdd_ctx->hHal,
3225 adapter->sessionId,
3226 neighborEmptyScanRefreshPeriod);
3227
3228exit:
3229 return ret;
3230}
3231
3232static int drv_cmd_get_roam_scan_period(hdd_adapter_t *adapter,
3233 hdd_context_t *hdd_ctx,
3234 uint8_t *command,
3235 uint8_t command_len,
3236 hdd_priv_data_t *priv_data)
3237{
3238 int ret = 0;
3239 uint16_t nEmptyScanRefreshPeriod =
3240 sme_get_empty_scan_refresh_period(hdd_ctx->hHal);
3241 char extra[32];
3242 uint8_t len = 0;
3243
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303244 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003245 TRACE_CODE_HDD_GETROAMSCANPERIOD_IOCTL,
3246 adapter->sessionId,
3247 nEmptyScanRefreshPeriod));
3248 len = scnprintf(extra, sizeof(extra), "%s %d",
3249 "GETROAMSCANPERIOD",
3250 (nEmptyScanRefreshPeriod / 1000));
3251 /* Returned value is in units of seconds */
Anurag Chouhan6d760662016-02-20 16:05:43 +05303252 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003253 if (copy_to_user(priv_data->buf, &extra, len)) {
3254 hddLog(LOGE,
3255 FL("failed to copy data to user buffer"));
3256 ret = -EFAULT;
3257 }
3258
3259 return ret;
3260}
3261
3262static int drv_cmd_set_roam_scan_refresh_period(hdd_adapter_t *adapter,
3263 hdd_context_t *hdd_ctx,
3264 uint8_t *command,
3265 uint8_t command_len,
3266 hdd_priv_data_t *priv_data)
3267{
3268 int ret = 0;
3269 uint8_t *value = command;
3270 uint8_t roamScanRefreshPeriod = 0;
3271 uint16_t neighborScanRefreshPeriod =
3272 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_DEFAULT;
3273
3274 /* input refresh period is in terms of seconds */
3275 /* Move pointer to ahead of SETROAMSCANREFRESHPERIOD<delimiter> */
3276 value = value + command_len + 1;
3277
3278 /* Convert the value from ascii to integer */
3279 ret = kstrtou8(value, 10, &roamScanRefreshPeriod);
3280 if (ret < 0) {
3281 /*
3282 * If the input value is greater than max value of datatype,
3283 * then also kstrtou8 fails
3284 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303285 QDF_TRACE(QDF_MODULE_ID_HDD,
3286 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003287 "%s: kstrtou8 failed Input value may be out of range[%d - %d]",
3288 __func__,
3289 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN / 1000,
3290 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX / 1000);
3291 ret = -EINVAL;
3292 goto exit;
3293 }
3294
3295 if ((roamScanRefreshPeriod <
3296 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN / 1000))
3297 || (roamScanRefreshPeriod >
3298 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX / 1000))) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303299 QDF_TRACE(QDF_MODULE_ID_HDD,
3300 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003301 "Neighbor scan results refresh period value %d is out of range (Min: %d Max: %d)",
3302 roamScanRefreshPeriod,
3303 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN
3304 / 1000),
3305 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX
3306 / 1000));
3307 ret = -EINVAL;
3308 goto exit;
3309 }
3310 neighborScanRefreshPeriod = roamScanRefreshPeriod * 1000;
3311
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303312 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003313 "%s: Received Command to Set roam scan refresh period (Scan refresh period) = %d",
3314 __func__,
3315 roamScanRefreshPeriod);
3316
3317 hdd_ctx->config->nNeighborResultsRefreshPeriod =
3318 neighborScanRefreshPeriod;
3319 sme_set_neighbor_scan_refresh_period(hdd_ctx->hHal,
3320 adapter->sessionId,
3321 neighborScanRefreshPeriod);
3322
3323exit:
3324 return ret;
3325}
3326
3327static int drv_cmd_get_roam_scan_refresh_period(hdd_adapter_t *adapter,
3328 hdd_context_t *hdd_ctx,
3329 uint8_t *command,
3330 uint8_t command_len,
3331 hdd_priv_data_t *priv_data)
3332{
3333 int ret = 0;
3334 uint16_t value =
3335 sme_get_neighbor_scan_refresh_period(hdd_ctx->hHal);
3336 char extra[32];
3337 uint8_t len = 0;
3338
3339 len = scnprintf(extra, sizeof(extra), "%s %d",
3340 "GETROAMSCANREFRESHPERIOD",
3341 (value / 1000));
3342 /* Returned value is in units of seconds */
Anurag Chouhan6d760662016-02-20 16:05:43 +05303343 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003344 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303345 QDF_TRACE(QDF_MODULE_ID_HDD,
3346 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003347 "%s: failed to copy data to user buffer",
3348 __func__);
3349 ret = -EFAULT;
3350 }
3351
3352 return ret;
3353}
3354
3355static int drv_cmd_set_roam_mode(hdd_adapter_t *adapter,
3356 hdd_context_t *hdd_ctx,
3357 uint8_t *command,
3358 uint8_t command_len,
3359 hdd_priv_data_t *priv_data)
3360{
3361 int ret = 0;
3362 uint8_t *value = command;
3363 uint8_t roamMode = CFG_LFR_FEATURE_ENABLED_DEFAULT;
3364
3365 /* Move pointer to ahead of SETROAMMODE<delimiter> */
3366 value = value + SIZE_OF_SETROAMMODE + 1;
3367
3368 /* Convert the value from ascii to integer */
3369 ret = kstrtou8(value, SIZE_OF_SETROAMMODE, &roamMode);
3370 if (ret < 0) {
3371 /*
3372 * If the input value is greater than max value of datatype,
3373 * then also kstrtou8 fails
3374 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303375 QDF_TRACE(QDF_MODULE_ID_HDD,
3376 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003377 "%s: kstrtou8 failed range [%d - %d]",
3378 __func__, CFG_LFR_FEATURE_ENABLED_MIN,
3379 CFG_LFR_FEATURE_ENABLED_MAX);
3380 ret = -EINVAL;
3381 goto exit;
3382 }
3383 if ((roamMode < CFG_LFR_FEATURE_ENABLED_MIN) ||
3384 (roamMode > CFG_LFR_FEATURE_ENABLED_MAX)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303385 QDF_TRACE(QDF_MODULE_ID_HDD,
3386 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003387 "Roam Mode value %d is out of range (Min: %d Max: %d)",
3388 roamMode,
3389 CFG_LFR_FEATURE_ENABLED_MIN,
3390 CFG_LFR_FEATURE_ENABLED_MAX);
3391 ret = -EINVAL;
3392 goto exit;
3393 }
3394
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303395 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003396 "%s: Received Command to Set Roam Mode = %d",
3397 __func__, roamMode);
3398 /*
3399 * Note that
3400 * SETROAMMODE 0 is to enable LFR while
3401 * SETROAMMODE 1 is to disable LFR, but
3402 * notify_is_fast_roam_ini_feature_enabled 0/1 is to
3403 * enable/disable. So, we have to invert the value
3404 * to call sme_update_is_fast_roam_ini_feature_enabled.
3405 */
3406 if (CFG_LFR_FEATURE_ENABLED_MIN == roamMode)
3407 roamMode = CFG_LFR_FEATURE_ENABLED_MAX; /* Roam enable */
3408 else
3409 roamMode = CFG_LFR_FEATURE_ENABLED_MIN; /* Roam disable */
3410
3411 hdd_ctx->config->isFastRoamIniFeatureEnabled = roamMode;
3412 if (roamMode) {
3413 hdd_ctx->config->isRoamOffloadScanEnabled = roamMode;
3414 sme_update_roam_scan_offload_enabled(
3415 (tHalHandle)(hdd_ctx->hHal),
3416 hdd_ctx->config->isRoamOffloadScanEnabled);
3417 sme_update_is_fast_roam_ini_feature_enabled(
3418 hdd_ctx->hHal,
3419 adapter->sessionId,
3420 roamMode);
3421 } else {
3422 sme_update_is_fast_roam_ini_feature_enabled(
3423 hdd_ctx->hHal,
3424 adapter->sessionId,
3425 roamMode);
3426 hdd_ctx->config->isRoamOffloadScanEnabled = roamMode;
3427 sme_update_roam_scan_offload_enabled(
3428 (tHalHandle)(hdd_ctx->hHal),
3429 hdd_ctx->config->isRoamOffloadScanEnabled);
3430 }
3431
3432
3433exit:
3434 return ret;
3435}
3436
3437static int drv_cmd_get_roam_mode(hdd_adapter_t *adapter,
3438 hdd_context_t *hdd_ctx,
3439 uint8_t *command,
3440 uint8_t command_len,
3441 hdd_priv_data_t *priv_data)
3442{
3443 int ret = 0;
3444 bool roamMode = sme_get_is_lfr_feature_enabled(hdd_ctx->hHal);
3445 char extra[32];
3446 uint8_t len = 0;
3447
3448 /*
3449 * roamMode value shall be inverted because the sementics is different.
3450 */
3451 if (CFG_LFR_FEATURE_ENABLED_MIN == roamMode)
3452 roamMode = CFG_LFR_FEATURE_ENABLED_MAX;
3453 else
3454 roamMode = CFG_LFR_FEATURE_ENABLED_MIN;
3455
3456 len = scnprintf(extra, sizeof(extra), "%s %d", command, roamMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303457 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003458 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303459 QDF_TRACE(QDF_MODULE_ID_HDD,
3460 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003461 "%s: failed to copy data to user buffer",
3462 __func__);
3463 ret = -EFAULT;
3464 }
3465
3466 return ret;
3467}
3468
3469static int drv_cmd_set_roam_delta(hdd_adapter_t *adapter,
3470 hdd_context_t *hdd_ctx,
3471 uint8_t *command,
3472 uint8_t command_len,
3473 hdd_priv_data_t *priv_data)
3474{
3475 int ret = 0;
3476 uint8_t *value = command;
3477 uint8_t roamRssiDiff = CFG_ROAM_RSSI_DIFF_DEFAULT;
3478
3479 /* Move pointer to ahead of SETROAMDELTA<delimiter> */
3480 value = value + command_len + 1;
3481
3482 /* Convert the value from ascii to integer */
3483 ret = kstrtou8(value, 10, &roamRssiDiff);
3484 if (ret < 0) {
3485 /*
3486 * If the input value is greater than max value of datatype,
3487 * then also kstrtou8 fails
3488 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303489 QDF_TRACE(QDF_MODULE_ID_HDD,
3490 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003491 "%s: kstrtou8 failed range [%d - %d]",
3492 __func__, CFG_ROAM_RSSI_DIFF_MIN,
3493 CFG_ROAM_RSSI_DIFF_MAX);
3494 ret = -EINVAL;
3495 goto exit;
3496 }
3497
3498 if ((roamRssiDiff < CFG_ROAM_RSSI_DIFF_MIN) ||
3499 (roamRssiDiff > CFG_ROAM_RSSI_DIFF_MAX)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303500 QDF_TRACE(QDF_MODULE_ID_HDD,
3501 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003502 "Roam rssi diff value %d is out of range (Min: %d Max: %d)",
3503 roamRssiDiff,
3504 CFG_ROAM_RSSI_DIFF_MIN,
3505 CFG_ROAM_RSSI_DIFF_MAX);
3506 ret = -EINVAL;
3507 goto exit;
3508 }
3509
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303510 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003511 "%s: Received Command to Set roam rssi diff = %d",
3512 __func__, roamRssiDiff);
3513
3514 hdd_ctx->config->RoamRssiDiff = roamRssiDiff;
3515 sme_update_roam_rssi_diff(hdd_ctx->hHal,
3516 adapter->sessionId,
3517 roamRssiDiff);
3518
3519exit:
3520 return ret;
3521}
3522
3523static int drv_cmd_get_roam_delta(hdd_adapter_t *adapter,
3524 hdd_context_t *hdd_ctx,
3525 uint8_t *command,
3526 uint8_t command_len,
3527 hdd_priv_data_t *priv_data)
3528{
3529 int ret = 0;
3530 uint8_t roamRssiDiff =
3531 sme_get_roam_rssi_diff(hdd_ctx->hHal);
3532 char extra[32];
3533 uint8_t len = 0;
3534
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303535 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003536 TRACE_CODE_HDD_GETROAMDELTA_IOCTL,
3537 adapter->sessionId, roamRssiDiff));
3538
3539 len = scnprintf(extra, sizeof(extra), "%s %d",
3540 command, roamRssiDiff);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303541 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003542
3543 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303544 QDF_TRACE(QDF_MODULE_ID_HDD,
3545 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003546 "%s: failed to copy data to user buffer",
3547 __func__);
3548 ret = -EFAULT;
3549 }
3550
3551 return ret;
3552}
3553
3554static int drv_cmd_get_band(hdd_adapter_t *adapter,
3555 hdd_context_t *hdd_ctx,
3556 uint8_t *command,
3557 uint8_t command_len,
3558 hdd_priv_data_t *priv_data)
3559{
3560 int ret = 0;
3561 int band = -1;
3562 char extra[32];
3563 uint8_t len = 0;
3564
3565 hdd_get_band_helper(hdd_ctx, &band);
3566
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303567 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003568 TRACE_CODE_HDD_GETBAND_IOCTL,
3569 adapter->sessionId, band));
3570
3571 len = scnprintf(extra, sizeof(extra), "%s %d", command, band);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303572 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003573
3574 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303575 QDF_TRACE(QDF_MODULE_ID_HDD,
3576 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003577 "%s: failed to copy data to user buffer",
3578 __func__);
3579 ret = -EFAULT;
3580 }
3581
3582 return ret;
3583}
3584
3585static int drv_cmd_set_roam_scan_channels(hdd_adapter_t *adapter,
3586 hdd_context_t *hdd_ctx,
3587 uint8_t *command,
3588 uint8_t command_len,
3589 hdd_priv_data_t *priv_data)
3590{
3591 return hdd_parse_set_roam_scan_channels(adapter, command);
3592}
3593
3594static int drv_cmd_get_roam_scan_channels(hdd_adapter_t *adapter,
3595 hdd_context_t *hdd_ctx,
3596 uint8_t *command,
3597 uint8_t command_len,
3598 hdd_priv_data_t *priv_data)
3599{
3600 int ret = 0;
3601 uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
3602 uint8_t numChannels = 0;
3603 uint8_t j = 0;
3604 char extra[128] = { 0 };
3605 int len;
3606
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303607 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003608 sme_get_roam_scan_channel_list(hdd_ctx->hHal,
3609 ChannelList,
3610 &numChannels,
3611 adapter->sessionId)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303612 QDF_TRACE(QDF_MODULE_ID_HDD,
3613 QDF_TRACE_LEVEL_FATAL,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003614 "%s: failed to get roam scan channel list",
3615 __func__);
3616 ret = -EFAULT;
3617 goto exit;
3618 }
3619
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303620 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003621 TRACE_CODE_HDD_GETROAMSCANCHANNELS_IOCTL,
3622 adapter->sessionId, numChannels));
3623 /*
3624 * output channel list is of the format
3625 * [Number of roam scan channels][Channel1][Channel2]...
3626 * copy the number of channels in the 0th index
3627 */
3628 len = scnprintf(extra, sizeof(extra), "%s %d", command,
3629 numChannels);
3630 for (j = 0; (j < numChannels); j++)
3631 len += scnprintf(extra + len, sizeof(extra) - len,
3632 " %d", ChannelList[j]);
3633
Anurag Chouhan6d760662016-02-20 16:05:43 +05303634 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003635 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303636 QDF_TRACE(QDF_MODULE_ID_HDD,
3637 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003638 "%s: failed to copy data to user buffer",
3639 __func__);
3640 ret = -EFAULT;
3641 goto exit;
3642 }
3643
3644exit:
3645 return ret;
3646}
3647
3648static int drv_cmd_get_ccx_mode(hdd_adapter_t *adapter,
3649 hdd_context_t *hdd_ctx,
3650 uint8_t *command,
3651 uint8_t command_len,
3652 hdd_priv_data_t *priv_data)
3653{
3654 int ret = 0;
3655 bool eseMode = sme_get_is_ese_feature_enabled(hdd_ctx->hHal);
3656 char extra[32];
3657 uint8_t len = 0;
3658
3659 /*
3660 * Check if the features OKC/ESE/11R are supported simultaneously,
3661 * then this operation is not permitted (return FAILURE)
3662 */
3663 if (eseMode &&
3664 hdd_is_okc_mode_enabled(hdd_ctx) &&
3665 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303666 QDF_TRACE(QDF_MODULE_ID_HDD,
3667 QDF_TRACE_LEVEL_WARN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003668 "%s: OKC/ESE/11R are supported simultaneously hence this operation is not permitted!",
3669 __func__);
3670 ret = -EPERM;
3671 goto exit;
3672 }
3673
3674 len = scnprintf(extra, sizeof(extra), "%s %d",
3675 "GETCCXMODE", eseMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303676 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003677 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303678 QDF_TRACE(QDF_MODULE_ID_HDD,
3679 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003680 "%s: failed to copy data to user buffer",
3681 __func__);
3682 ret = -EFAULT;
3683 goto exit;
3684 }
3685
3686exit:
3687 return ret;
3688}
3689
3690static int drv_cmd_get_okc_mode(hdd_adapter_t *adapter,
3691 hdd_context_t *hdd_ctx,
3692 uint8_t *command,
3693 uint8_t command_len,
3694 hdd_priv_data_t *priv_data)
3695{
3696 int ret = 0;
3697 bool okcMode = hdd_is_okc_mode_enabled(hdd_ctx);
3698 char extra[32];
3699 uint8_t len = 0;
3700
3701 /*
3702 * Check if the features OKC/ESE/11R are supported simultaneously,
3703 * then this operation is not permitted (return FAILURE)
3704 */
3705 if (okcMode &&
3706 sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
3707 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303708 QDF_TRACE(QDF_MODULE_ID_HDD,
3709 QDF_TRACE_LEVEL_WARN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003710 "%s: OKC/ESE/11R are supported simultaneously hence this operation is not permitted!",
3711 __func__);
3712 ret = -EPERM;
3713 goto exit;
3714 }
3715
3716 len = scnprintf(extra, sizeof(extra), "%s %d",
3717 "GETOKCMODE", okcMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303718 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003719
3720 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303721 QDF_TRACE(QDF_MODULE_ID_HDD,
3722 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003723 "%s: failed to copy data to user buffer",
3724 __func__);
3725 ret = -EFAULT;
3726 goto exit;
3727 }
3728
3729exit:
3730 return ret;
3731}
3732
3733static int drv_cmd_get_fast_roam(hdd_adapter_t *adapter,
3734 hdd_context_t *hdd_ctx,
3735 uint8_t *command,
3736 uint8_t command_len,
3737 hdd_priv_data_t *priv_data)
3738{
3739 int ret = 0;
3740 bool lfrMode = sme_get_is_lfr_feature_enabled(hdd_ctx->hHal);
3741 char extra[32];
3742 uint8_t len = 0;
3743
3744 len = scnprintf(extra, sizeof(extra), "%s %d",
3745 "GETFASTROAM", lfrMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303746 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003747
3748 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303749 QDF_TRACE(QDF_MODULE_ID_HDD,
3750 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003751 "%s: failed to copy data to user buffer",
3752 __func__);
3753 ret = -EFAULT;
3754 }
3755
3756 return ret;
3757}
3758
3759static int drv_cmd_get_fast_transition(hdd_adapter_t *adapter,
3760 hdd_context_t *hdd_ctx,
3761 uint8_t *command,
3762 uint8_t command_len,
3763 hdd_priv_data_t *priv_data)
3764{
3765 int ret = 0;
3766 bool ft = sme_get_is_ft_feature_enabled(hdd_ctx->hHal);
3767 char extra[32];
3768 uint8_t len = 0;
3769
3770 len = scnprintf(extra, sizeof(extra), "%s %d",
3771 "GETFASTTRANSITION", ft);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303772 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003773
3774 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303775 QDF_TRACE(QDF_MODULE_ID_HDD,
3776 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003777 "%s: failed to copy data to user buffer",
3778 __func__);
3779 ret = -EFAULT;
3780 }
3781
3782 return ret;
3783}
3784
3785static int drv_cmd_set_roam_scan_channel_min_time(hdd_adapter_t *adapter,
3786 hdd_context_t *hdd_ctx,
3787 uint8_t *command,
3788 uint8_t command_len,
3789 hdd_priv_data_t *priv_data)
3790{
3791 int ret = 0;
3792 uint8_t *value = command;
3793 uint8_t minTime = CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_DEFAULT;
3794
3795 /* Move pointer to ahead of SETROAMSCANCHANNELMINTIME<delimiter> */
3796 value = value + command_len + 1;
3797
3798 /* Convert the value from ascii to integer */
3799 ret = kstrtou8(value, 10, &minTime);
3800 if (ret < 0) {
3801 /*
3802 * If the input value is greater than max value of datatype,
3803 * then also kstrtou8 fails
3804 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303805 QDF_TRACE(QDF_MODULE_ID_HDD,
3806 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003807 "%s: kstrtou8 failed range [%d - %d]",
3808 __func__,
3809 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN,
3810 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX);
3811 ret = -EINVAL;
3812 goto exit;
3813 }
3814
3815 if ((minTime < CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN) ||
3816 (minTime > CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303817 QDF_TRACE(QDF_MODULE_ID_HDD,
3818 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003819 "scan min channel time value %d is out of range (Min: %d Max: %d)",
3820 minTime,
3821 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN,
3822 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX);
3823 ret = -EINVAL;
3824 goto exit;
3825 }
3826
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303827 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003828 TRACE_CODE_HDD_SETROAMSCANCHANNELMINTIME_IOCTL,
3829 adapter->sessionId, minTime));
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303830 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003831 "%s: Received Command to change channel min time = %d",
3832 __func__, minTime);
3833
3834 hdd_ctx->config->nNeighborScanMinChanTime = minTime;
3835 sme_set_neighbor_scan_min_chan_time(hdd_ctx->hHal,
3836 minTime,
3837 adapter->sessionId);
3838
3839exit:
3840 return ret;
3841}
3842
3843static int drv_cmd_send_action_frame(hdd_adapter_t *adapter,
3844 hdd_context_t *hdd_ctx,
3845 uint8_t *command,
3846 uint8_t command_len,
3847 hdd_priv_data_t *priv_data)
3848{
3849 return hdd_parse_sendactionframe(adapter, command);
3850}
3851
3852static int drv_cmd_get_roam_scan_channel_min_time(hdd_adapter_t *adapter,
3853 hdd_context_t *hdd_ctx,
3854 uint8_t *command,
3855 uint8_t command_len,
3856 hdd_priv_data_t *priv_data)
3857{
3858 int ret = 0;
3859 uint16_t val = sme_get_neighbor_scan_min_chan_time(hdd_ctx->hHal,
3860 adapter->sessionId);
3861 char extra[32];
3862 uint8_t len = 0;
3863
3864 /* value is interms of msec */
3865 len = scnprintf(extra, sizeof(extra), "%s %d",
3866 "GETROAMSCANCHANNELMINTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303867 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003868
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303869 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003870 TRACE_CODE_HDD_GETROAMSCANCHANNELMINTIME_IOCTL,
3871 adapter->sessionId, val));
3872
3873 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303874 QDF_TRACE(QDF_MODULE_ID_HDD,
3875 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003876 "%s: failed to copy data to user buffer",
3877 __func__);
3878 ret = -EFAULT;
3879 }
3880
3881 return ret;
3882}
3883
3884static int drv_cmd_set_scan_channel_time(hdd_adapter_t *adapter,
3885 hdd_context_t *hdd_ctx,
3886 uint8_t *command,
3887 uint8_t command_len,
3888 hdd_priv_data_t *priv_data)
3889{
3890 int ret = 0;
3891 uint8_t *value = command;
3892 uint16_t maxTime = CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_DEFAULT;
3893
3894 /* Move pointer to ahead of SETSCANCHANNELTIME<delimiter> */
3895 value = value + command_len + 1;
3896
3897 /* Convert the value from ascii to integer */
3898 ret = kstrtou16(value, 10, &maxTime);
3899 if (ret < 0) {
3900 /*
3901 * If the input value is greater than max value of datatype,
3902 * then also kstrtou8 fails
3903 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303904 QDF_TRACE(QDF_MODULE_ID_HDD,
3905 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003906 "%s: kstrtou16 failed range [%d - %d]",
3907 __func__,
3908 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN,
3909 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX);
3910 ret = -EINVAL;
3911 goto exit;
3912 }
3913
3914 if ((maxTime < CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN) ||
3915 (maxTime > CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303916 QDF_TRACE(QDF_MODULE_ID_HDD,
3917 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003918 "lfr mode value %d is out of range (Min: %d Max: %d)",
3919 maxTime,
3920 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN,
3921 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX);
3922 ret = -EINVAL;
3923 goto exit;
3924 }
3925
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303926 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003927 "%s: Received Command to change channel max time = %d",
3928 __func__, maxTime);
3929
3930 hdd_ctx->config->nNeighborScanMaxChanTime = maxTime;
3931 sme_set_neighbor_scan_max_chan_time(hdd_ctx->hHal,
3932 adapter->sessionId,
3933 maxTime);
3934
3935exit:
3936 return ret;
3937}
3938
3939static int drv_cmd_get_scan_channel_time(hdd_adapter_t *adapter,
3940 hdd_context_t *hdd_ctx,
3941 uint8_t *command,
3942 uint8_t command_len,
3943 hdd_priv_data_t *priv_data)
3944{
3945 int ret = 0;
3946 uint16_t val = sme_get_neighbor_scan_max_chan_time(hdd_ctx->hHal,
3947 adapter->sessionId);
3948 char extra[32];
3949 uint8_t len = 0;
3950
3951 /* value is interms of msec */
3952 len = scnprintf(extra, sizeof(extra), "%s %d",
3953 "GETSCANCHANNELTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303954 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003955
3956 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303957 QDF_TRACE(QDF_MODULE_ID_HDD,
3958 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003959 "%s: failed to copy data to user buffer",
3960 __func__);
3961 ret = -EFAULT;
3962 }
3963
3964 return ret;
3965}
3966
3967static int drv_cmd_set_scan_home_time(hdd_adapter_t *adapter,
3968 hdd_context_t *hdd_ctx,
3969 uint8_t *command,
3970 uint8_t command_len,
3971 hdd_priv_data_t *priv_data)
3972{
3973 int ret = 0;
3974 uint8_t *value = command;
3975 uint16_t val = CFG_NEIGHBOR_SCAN_TIMER_PERIOD_DEFAULT;
3976
3977 /* Move pointer to ahead of SETSCANHOMETIME<delimiter> */
3978 value = value + command_len + 1;
3979
3980 /* Convert the value from ascii to integer */
3981 ret = kstrtou16(value, 10, &val);
3982 if (ret < 0) {
3983 /*
3984 * If the input value is greater than max value of datatype,
3985 * then also kstrtou8 fails
3986 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303987 QDF_TRACE(QDF_MODULE_ID_HDD,
3988 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003989 "%s: kstrtou16 failed range [%d - %d]",
3990 __func__,
3991 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN,
3992 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX);
3993 ret = -EINVAL;
3994 goto exit;
3995 }
3996
3997 if ((val < CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN) ||
3998 (val > CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303999 QDF_TRACE(QDF_MODULE_ID_HDD,
4000 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004001 "scan home time value %d is out of range (Min: %d Max: %d)",
4002 val,
4003 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN,
4004 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX);
4005 ret = -EINVAL;
4006 goto exit;
4007 }
4008
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304009 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004010 "%s: Received Command to change scan home time = %d",
4011 __func__, val);
4012
4013 hdd_ctx->config->nNeighborScanPeriod = val;
4014 sme_set_neighbor_scan_period(hdd_ctx->hHal,
4015 adapter->sessionId, val);
4016
4017exit:
4018 return ret;
4019}
4020
4021static int drv_cmd_get_scan_home_time(hdd_adapter_t *adapter,
4022 hdd_context_t *hdd_ctx,
4023 uint8_t *command,
4024 uint8_t command_len,
4025 hdd_priv_data_t *priv_data)
4026{
4027 int ret = 0;
4028 uint16_t val = sme_get_neighbor_scan_period(hdd_ctx->hHal,
4029 adapter->
4030 sessionId);
4031 char extra[32];
4032 uint8_t len = 0;
4033
4034 /* value is interms of msec */
4035 len = scnprintf(extra, sizeof(extra), "%s %d",
4036 "GETSCANHOMETIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304037 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004038
4039 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304040 QDF_TRACE(QDF_MODULE_ID_HDD,
4041 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004042 "%s: failed to copy data to user buffer",
4043 __func__);
4044 ret = -EFAULT;
4045 }
4046
4047 return ret;
4048}
4049
4050static int drv_cmd_set_roam_intra_band(hdd_adapter_t *adapter,
4051 hdd_context_t *hdd_ctx,
4052 uint8_t *command,
4053 uint8_t command_len,
4054 hdd_priv_data_t *priv_data)
4055{
4056 int ret = 0;
4057 uint8_t *value = command;
4058 uint8_t val = CFG_ROAM_INTRA_BAND_DEFAULT;
4059
4060 /* Move pointer to ahead of SETROAMINTRABAND<delimiter> */
4061 value = value + command_len + 1;
4062
4063 /* Convert the value from ascii to integer */
4064 ret = kstrtou8(value, 10, &val);
4065 if (ret < 0) {
4066 /*
4067 * If the input value is greater than max value of datatype,
4068 * then also kstrtou8 fails
4069 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304070 QDF_TRACE(QDF_MODULE_ID_HDD,
4071 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004072 "%s: kstrtou8 failed range [%d - %d]",
4073 __func__, CFG_ROAM_INTRA_BAND_MIN,
4074 CFG_ROAM_INTRA_BAND_MAX);
4075 ret = -EINVAL;
4076 goto exit;
4077 }
4078
4079 if ((val < CFG_ROAM_INTRA_BAND_MIN) ||
4080 (val > CFG_ROAM_INTRA_BAND_MAX)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304081 QDF_TRACE(QDF_MODULE_ID_HDD,
4082 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004083 "intra band mode value %d is out of range (Min: %d Max: %d)",
4084 val,
4085 CFG_ROAM_INTRA_BAND_MIN,
4086 CFG_ROAM_INTRA_BAND_MAX);
4087 ret = -EINVAL;
4088 goto exit;
4089 }
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304090 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004091 "%s: Received Command to change intra band = %d",
4092 __func__, val);
4093
4094 hdd_ctx->config->nRoamIntraBand = val;
4095 sme_set_roam_intra_band(hdd_ctx->hHal, val);
4096
4097exit:
4098 return ret;
4099}
4100
4101static int drv_cmd_get_roam_intra_band(hdd_adapter_t *adapter,
4102 hdd_context_t *hdd_ctx,
4103 uint8_t *command,
4104 uint8_t command_len,
4105 hdd_priv_data_t *priv_data)
4106{
4107 int ret = 0;
4108 uint16_t val = sme_get_roam_intra_band(hdd_ctx->hHal);
4109 char extra[32];
4110 uint8_t len = 0;
4111
4112 /* value is interms of msec */
4113 len = scnprintf(extra, sizeof(extra), "%s %d",
4114 "GETROAMINTRABAND", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304115 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004116 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304117 QDF_TRACE(QDF_MODULE_ID_HDD,
4118 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004119 "%s: failed to copy data to user buffer",
4120 __func__);
4121 ret = -EFAULT;
4122 }
4123
4124 return ret;
4125}
4126
4127static int drv_cmd_set_scan_n_probes(hdd_adapter_t *adapter,
4128 hdd_context_t *hdd_ctx,
4129 uint8_t *command,
4130 uint8_t command_len,
4131 hdd_priv_data_t *priv_data)
4132{
4133 int ret = 0;
4134 uint8_t *value = command;
4135 uint8_t nProbes = CFG_ROAM_SCAN_N_PROBES_DEFAULT;
4136
4137 /* Move pointer to ahead of SETSCANNPROBES<delimiter> */
4138 value = value + command_len + 1;
4139
4140 /* Convert the value from ascii to integer */
4141 ret = kstrtou8(value, 10, &nProbes);
4142 if (ret < 0) {
4143 /*
4144 * If the input value is greater than max value of datatype,
4145 * then also kstrtou8 fails
4146 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304147 QDF_TRACE(QDF_MODULE_ID_HDD,
4148 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004149 "%s: kstrtou8 failed range [%d - %d]",
4150 __func__, CFG_ROAM_SCAN_N_PROBES_MIN,
4151 CFG_ROAM_SCAN_N_PROBES_MAX);
4152 ret = -EINVAL;
4153 goto exit;
4154 }
4155
4156 if ((nProbes < CFG_ROAM_SCAN_N_PROBES_MIN) ||
4157 (nProbes > CFG_ROAM_SCAN_N_PROBES_MAX)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304158 QDF_TRACE(QDF_MODULE_ID_HDD,
4159 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004160 "NProbes value %d is out of range (Min: %d Max: %d)",
4161 nProbes,
4162 CFG_ROAM_SCAN_N_PROBES_MIN,
4163 CFG_ROAM_SCAN_N_PROBES_MAX);
4164 ret = -EINVAL;
4165 goto exit;
4166 }
4167
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304168 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004169 "%s: Received Command to Set nProbes = %d",
4170 __func__, nProbes);
4171
4172 hdd_ctx->config->nProbes = nProbes;
4173 sme_update_roam_scan_n_probes(hdd_ctx->hHal,
4174 adapter->sessionId, nProbes);
4175
4176exit:
4177 return ret;
4178}
4179
4180static int drv_cmd_get_scan_n_probes(hdd_adapter_t *adapter,
4181 hdd_context_t *hdd_ctx,
4182 uint8_t *command,
4183 uint8_t command_len,
4184 hdd_priv_data_t *priv_data)
4185{
4186 int ret = 0;
4187 uint8_t val = sme_get_roam_scan_n_probes(hdd_ctx->hHal);
4188 char extra[32];
4189 uint8_t len = 0;
4190
4191 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304192 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004193 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304194 QDF_TRACE(QDF_MODULE_ID_HDD,
4195 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004196 "%s: failed to copy data to user buffer",
4197 __func__);
4198 ret = -EFAULT;
4199 }
4200
4201 return ret;
4202}
4203
4204static int drv_cmd_set_scan_home_away_time(hdd_adapter_t *adapter,
4205 hdd_context_t *hdd_ctx,
4206 uint8_t *command,
4207 uint8_t command_len,
4208 hdd_priv_data_t *priv_data)
4209{
4210 int ret = 0;
4211 uint8_t *value = command;
4212 uint16_t homeAwayTime = CFG_ROAM_SCAN_HOME_AWAY_TIME_DEFAULT;
4213
4214 /* input value is in units of msec */
4215
4216 /* Move pointer to ahead of SETSCANHOMEAWAYTIME<delimiter> */
4217 value = value + command_len + 1;
4218
4219 /* Convert the value from ascii to integer */
4220 ret = kstrtou16(value, 10, &homeAwayTime);
4221 if (ret < 0) {
4222 /*
4223 * If the input value is greater than max value of datatype,
4224 * then also kstrtou8 fails
4225 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304226 QDF_TRACE(QDF_MODULE_ID_HDD,
4227 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004228 "%s: kstrtou8 failed range [%d - %d]",
4229 __func__,
4230 CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN,
4231 CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX);
4232 ret = -EINVAL;
4233 goto exit;
4234 }
4235
4236 if ((homeAwayTime < CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN) ||
4237 (homeAwayTime > CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304238 QDF_TRACE(QDF_MODULE_ID_HDD,
4239 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004240 "homeAwayTime value %d is out of range (Min: %d Max: %d)",
4241 homeAwayTime,
4242 CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN,
4243 CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX);
4244 ret = -EINVAL;
4245 goto exit;
4246 }
4247
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304248 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004249 "%s: Received Command to Set scan away time = %d",
4250 __func__, homeAwayTime);
4251
4252 if (hdd_ctx->config->nRoamScanHomeAwayTime !=
4253 homeAwayTime) {
4254 hdd_ctx->config->nRoamScanHomeAwayTime = homeAwayTime;
4255 sme_update_roam_scan_home_away_time(hdd_ctx->hHal,
4256 adapter->sessionId,
4257 homeAwayTime,
4258 true);
4259 }
4260
4261exit:
4262 return ret;
4263}
4264
4265static int drv_cmd_get_scan_home_away_time(hdd_adapter_t *adapter,
4266 hdd_context_t *hdd_ctx,
4267 uint8_t *command,
4268 uint8_t command_len,
4269 hdd_priv_data_t *priv_data)
4270{
4271 int ret = 0;
4272 uint16_t val = sme_get_roam_scan_home_away_time(hdd_ctx->hHal);
4273 char extra[32];
4274 uint8_t len = 0;
4275
4276 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304277 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004278
4279 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304280 QDF_TRACE(QDF_MODULE_ID_HDD,
4281 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004282 "%s: failed to copy data to user buffer",
4283 __func__);
4284 ret = -EFAULT;
4285 }
4286
4287 return ret;
4288}
4289
4290static int drv_cmd_reassoc(hdd_adapter_t *adapter,
4291 hdd_context_t *hdd_ctx,
4292 uint8_t *command,
4293 uint8_t command_len,
4294 hdd_priv_data_t *priv_data)
4295{
4296 return hdd_parse_reassoc(adapter, command);
4297}
4298
4299static int drv_cmd_set_wes_mode(hdd_adapter_t *adapter,
4300 hdd_context_t *hdd_ctx,
4301 uint8_t *command,
4302 uint8_t command_len,
4303 hdd_priv_data_t *priv_data)
4304{
4305 int ret = 0;
4306 uint8_t *value = command;
4307 uint8_t wesMode = CFG_ENABLE_WES_MODE_NAME_DEFAULT;
4308
4309 /* Move pointer to ahead of SETWESMODE<delimiter> */
4310 value = value + command_len + 1;
4311
4312 /* Convert the value from ascii to integer */
4313 ret = kstrtou8(value, 10, &wesMode);
4314 if (ret < 0) {
4315 /*
4316 * If the input value is greater than max value of datatype,
4317 * then also kstrtou8 fails
4318 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304319 QDF_TRACE(QDF_MODULE_ID_HDD,
4320 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004321 "%s: kstrtou8 failed range [%d - %d]",
4322 __func__,
4323 CFG_ENABLE_WES_MODE_NAME_MIN,
4324 CFG_ENABLE_WES_MODE_NAME_MAX);
4325 ret = -EINVAL;
4326 goto exit;
4327 }
4328
4329 if ((wesMode < CFG_ENABLE_WES_MODE_NAME_MIN) ||
4330 (wesMode > CFG_ENABLE_WES_MODE_NAME_MAX)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304331 QDF_TRACE(QDF_MODULE_ID_HDD,
4332 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004333 "WES Mode value %d is out of range (Min: %d Max: %d)",
4334 wesMode,
4335 CFG_ENABLE_WES_MODE_NAME_MIN,
4336 CFG_ENABLE_WES_MODE_NAME_MAX);
4337 ret = -EINVAL;
4338 goto exit;
4339 }
4340
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304341 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004342 "%s: Received Command to Set WES Mode rssi diff = %d",
4343 __func__, wesMode);
4344
4345 hdd_ctx->config->isWESModeEnabled = wesMode;
4346 sme_update_wes_mode(hdd_ctx->hHal, wesMode, adapter->sessionId);
4347
4348exit:
4349 return ret;
4350}
4351
4352static int drv_cmd_get_wes_mode(hdd_adapter_t *adapter,
4353 hdd_context_t *hdd_ctx,
4354 uint8_t *command,
4355 uint8_t command_len,
4356 hdd_priv_data_t *priv_data)
4357{
4358 int ret = 0;
4359 bool wesMode = sme_get_wes_mode(hdd_ctx->hHal);
4360 char extra[32];
4361 uint8_t len = 0;
4362
4363 len = scnprintf(extra, sizeof(extra), "%s %d", command, wesMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304364 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004365 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304366 QDF_TRACE(QDF_MODULE_ID_HDD,
4367 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004368 "%s: failed to copy data to user buffer",
4369 __func__);
4370 ret = -EFAULT;
4371 }
4372
4373 return ret;
4374}
4375
4376static int drv_cmd_set_opportunistic_rssi_diff(hdd_adapter_t *adapter,
4377 hdd_context_t *hdd_ctx,
4378 uint8_t *command,
4379 uint8_t command_len,
4380 hdd_priv_data_t *priv_data)
4381{
4382 int ret = 0;
4383 uint8_t *value = command;
4384 uint8_t nOpportunisticThresholdDiff =
4385 CFG_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF_DEFAULT;
4386
4387 /* Move pointer to ahead of SETOPPORTUNISTICRSSIDIFF<delimiter> */
4388 value = value + command_len + 1;
4389
4390 /* Convert the value from ascii to integer */
4391 ret = kstrtou8(value, 10, &nOpportunisticThresholdDiff);
4392 if (ret < 0) {
4393 /*
4394 * If the input value is greater than max value of datatype,
4395 * then also kstrtou8 fails
4396 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304397 QDF_TRACE(QDF_MODULE_ID_HDD,
4398 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004399 "%s: kstrtou8 failed.", __func__);
4400 ret = -EINVAL;
4401 goto exit;
4402 }
4403
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304404 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004405 "%s: Received Command to Set Opportunistic Threshold diff = %d",
4406 __func__, nOpportunisticThresholdDiff);
4407
4408 sme_set_roam_opportunistic_scan_threshold_diff(hdd_ctx->hHal,
4409 adapter->sessionId,
4410 nOpportunisticThresholdDiff);
4411
4412exit:
4413 return ret;
4414}
4415
4416static int drv_cmd_get_opportunistic_rssi_diff(hdd_adapter_t *adapter,
4417 hdd_context_t *hdd_ctx,
4418 uint8_t *command,
4419 uint8_t command_len,
4420 hdd_priv_data_t *priv_data)
4421{
4422 int ret = 0;
4423 int8_t val = sme_get_roam_opportunistic_scan_threshold_diff(
4424 hdd_ctx->hHal);
4425 char extra[32];
4426 uint8_t len = 0;
4427
4428 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304429 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004430 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304431 QDF_TRACE(QDF_MODULE_ID_HDD,
4432 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004433 "%s: failed to copy data to user buffer",
4434 __func__);
4435 ret = -EFAULT;
4436 }
4437
4438 return ret;
4439}
4440
4441static int drv_cmd_set_roam_rescan_rssi_diff(hdd_adapter_t *adapter,
4442 hdd_context_t *hdd_ctx,
4443 uint8_t *command,
4444 uint8_t command_len,
4445 hdd_priv_data_t *priv_data)
4446{
4447 int ret = 0;
4448 uint8_t *value = command;
4449 uint8_t nRoamRescanRssiDiff = CFG_ROAM_RESCAN_RSSI_DIFF_DEFAULT;
4450
4451 /* Move pointer to ahead of SETROAMRESCANRSSIDIFF<delimiter> */
4452 value = value + command_len + 1;
4453
4454 /* Convert the value from ascii to integer */
4455 ret = kstrtou8(value, 10, &nRoamRescanRssiDiff);
4456 if (ret < 0) {
4457 /*
4458 * If the input value is greater than max value of datatype,
4459 * then also kstrtou8 fails
4460 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304461 QDF_TRACE(QDF_MODULE_ID_HDD,
4462 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004463 "%s: kstrtou8 failed.", __func__);
4464 ret = -EINVAL;
4465 goto exit;
4466 }
4467
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304468 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004469 "%s: Received Command to Set Roam Rescan RSSI Diff = %d",
4470 __func__, nRoamRescanRssiDiff);
4471
4472 sme_set_roam_rescan_rssi_diff(hdd_ctx->hHal,
4473 adapter->sessionId,
4474 nRoamRescanRssiDiff);
4475
4476exit:
4477 return ret;
4478}
4479
4480static int drv_cmd_get_roam_rescan_rssi_diff(hdd_adapter_t *adapter,
4481 hdd_context_t *hdd_ctx,
4482 uint8_t *command,
4483 uint8_t command_len,
4484 hdd_priv_data_t *priv_data)
4485{
4486 int ret = 0;
4487 uint8_t val = sme_get_roam_rescan_rssi_diff(hdd_ctx->hHal);
4488 char extra[32];
4489 uint8_t len = 0;
4490
4491 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304492 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004493 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304494 QDF_TRACE(QDF_MODULE_ID_HDD,
4495 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004496 "%s: failed to copy data to user buffer",
4497 __func__);
4498 ret = -EFAULT;
4499 }
4500
4501 return ret;
4502}
4503
4504static int drv_cmd_set_fast_roam(hdd_adapter_t *adapter,
4505 hdd_context_t *hdd_ctx,
4506 uint8_t *command,
4507 uint8_t command_len,
4508 hdd_priv_data_t *priv_data)
4509{
4510 int ret = 0;
4511 uint8_t *value = command;
4512 uint8_t lfrMode = CFG_LFR_FEATURE_ENABLED_DEFAULT;
4513
4514 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4515 value = value + command_len + 1;
4516
4517 /* Convert the value from ascii to integer */
4518 ret = kstrtou8(value, 10, &lfrMode);
4519 if (ret < 0) {
4520 /*
4521 * If the input value is greater than max value of datatype,
4522 * then also kstrtou8 fails
4523 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304524 QDF_TRACE(QDF_MODULE_ID_HDD,
4525 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004526 "%s: kstrtou8 failed range [%d - %d]",
4527 __func__, CFG_LFR_FEATURE_ENABLED_MIN,
4528 CFG_LFR_FEATURE_ENABLED_MAX);
4529 ret = -EINVAL;
4530 goto exit;
4531 }
4532
4533 if ((lfrMode < CFG_LFR_FEATURE_ENABLED_MIN) ||
4534 (lfrMode > CFG_LFR_FEATURE_ENABLED_MAX)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304535 QDF_TRACE(QDF_MODULE_ID_HDD,
4536 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004537 "lfr mode value %d is out of range (Min: %d Max: %d)",
4538 lfrMode,
4539 CFG_LFR_FEATURE_ENABLED_MIN,
4540 CFG_LFR_FEATURE_ENABLED_MAX);
4541 ret = -EINVAL;
4542 goto exit;
4543 }
4544
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304545 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004546 "%s: Received Command to change lfr mode = %d",
4547 __func__, lfrMode);
4548
4549 hdd_ctx->config->isFastRoamIniFeatureEnabled = lfrMode;
4550 sme_update_is_fast_roam_ini_feature_enabled(hdd_ctx->hHal,
4551 adapter->
4552 sessionId,
4553 lfrMode);
4554
4555exit:
4556 return ret;
4557}
4558
4559static int drv_cmd_set_fast_transition(hdd_adapter_t *adapter,
4560 hdd_context_t *hdd_ctx,
4561 uint8_t *command,
4562 uint8_t command_len,
4563 hdd_priv_data_t *priv_data)
4564{
4565 int ret = 0;
4566 uint8_t *value = command;
4567 uint8_t ft = CFG_FAST_TRANSITION_ENABLED_NAME_DEFAULT;
4568
4569 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4570 value = value + command_len + 1;
4571
4572 /* Convert the value from ascii to integer */
4573 ret = kstrtou8(value, 10, &ft);
4574 if (ret < 0) {
4575 /*
4576 * If the input value is greater than max value of datatype,
4577 * then also kstrtou8 fails
4578 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304579 QDF_TRACE(QDF_MODULE_ID_HDD,
4580 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004581 "%s: kstrtou8 failed range [%d - %d]",
4582 __func__,
4583 CFG_FAST_TRANSITION_ENABLED_NAME_MIN,
4584 CFG_FAST_TRANSITION_ENABLED_NAME_MAX);
4585 ret = -EINVAL;
4586 goto exit;
4587 }
4588
4589 if ((ft < CFG_FAST_TRANSITION_ENABLED_NAME_MIN) ||
4590 (ft > CFG_FAST_TRANSITION_ENABLED_NAME_MAX)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304591 QDF_TRACE(QDF_MODULE_ID_HDD,
4592 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004593 "ft mode value %d is out of range (Min: %d Max: %d)",
4594 ft,
4595 CFG_FAST_TRANSITION_ENABLED_NAME_MIN,
4596 CFG_FAST_TRANSITION_ENABLED_NAME_MAX);
4597 ret = -EINVAL;
4598 goto exit;
4599 }
4600
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304601 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004602 "%s: Received Command to change ft mode = %d",
4603 __func__, ft);
4604
4605 hdd_ctx->config->isFastTransitionEnabled = ft;
4606 sme_update_fast_transition_enabled(hdd_ctx->hHal, ft);
4607
4608exit:
4609 return ret;
4610}
4611
4612#ifdef WLAN_FEATURE_ROAM_OFFLOAD
4613static void hdd_wma_send_fastreassoc_cmd(int sessionId, tSirMacAddr bssid,
4614 int channel)
4615{
4616 struct wma_roam_invoke_cmd *fastreassoc;
4617 cds_msg_t msg = {0};
4618
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304619 fastreassoc = qdf_mem_malloc(sizeof(*fastreassoc));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004620 if (NULL == fastreassoc) {
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05304621 hddLog(LOGE, FL("qdf_mem_malloc failed for fastreassoc"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004622 return;
4623 }
4624 fastreassoc->vdev_id = sessionId;
4625 fastreassoc->channel = channel;
4626 fastreassoc->bssid[0] = bssid[0];
4627 fastreassoc->bssid[1] = bssid[1];
4628 fastreassoc->bssid[2] = bssid[2];
4629 fastreassoc->bssid[3] = bssid[3];
4630 fastreassoc->bssid[4] = bssid[4];
4631 fastreassoc->bssid[5] = bssid[5];
4632
4633 msg.type = SIR_HAL_ROAM_INVOKE;
4634 msg.reserved = 0;
4635 msg.bodyptr = fastreassoc;
Anurag Chouhan6d760662016-02-20 16:05:43 +05304636 if (QDF_STATUS_SUCCESS != cds_mq_post_message(QDF_MODULE_ID_WMA,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004637 &msg)) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304638 qdf_mem_free(fastreassoc);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304639 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004640 FL("Not able to post ROAM_INVOKE_CMD message to WMA"));
4641 }
4642}
Varun Reddy Yeturubbbbe232016-02-29 14:01:57 -08004643#else
4644static inline void hdd_wma_send_fastreassoc_cmd(int sessionId,
4645 tSirMacAddr bssid, int channel)
4646{}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004647#endif
4648static int drv_cmd_fast_reassoc(hdd_adapter_t *adapter,
4649 hdd_context_t *hdd_ctx,
4650 uint8_t *command,
4651 uint8_t command_len,
4652 hdd_priv_data_t *priv_data)
4653{
4654 int ret = 0;
4655 uint8_t *value = command;
4656 uint8_t channel = 0;
4657 tSirMacAddr targetApBssid;
4658 uint32_t roamId = 0;
4659 tCsrRoamModifyProfileFields modProfileFields;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004660 tCsrHandoffRequest handoffInfo;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004661 hdd_station_ctx_t *pHddStaCtx;
4662
Krunal Sonibe766b02016-03-10 13:00:44 -08004663 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004664 hdd_warn("Unsupported in mode %s(%d)",
4665 hdd_device_mode_to_string(adapter->device_mode),
4666 adapter->device_mode);
4667 return -EINVAL;
4668 }
4669
4670 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
4671
4672 /* if not associated, no need to proceed with reassoc */
4673 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304674 QDF_TRACE(QDF_MODULE_ID_HDD,
4675 QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004676 "%s:Not associated!", __func__);
4677 ret = -EINVAL;
4678 goto exit;
4679 }
4680
4681 ret = hdd_parse_reassoc_command_v1_data(value, targetApBssid,
4682 &channel);
4683 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304684 QDF_TRACE(QDF_MODULE_ID_HDD,
4685 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004686 "%s: Failed to parse reassoc command data",
4687 __func__);
4688 goto exit;
4689 }
4690
4691 /*
4692 * if the target bssid is same as currently associated AP,
4693 * issue reassoc to same AP
4694 */
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304695 if (true != qdf_mem_cmp(targetApBssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004696 pHddStaCtx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05304697 QDF_MAC_ADDR_SIZE)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004698 /* Reassoc to same AP, only supported for Open Security*/
4699 if ((pHddStaCtx->conn_info.ucEncryptionType ||
4700 pHddStaCtx->conn_info.mcEncryptionType)) {
4701 hddLog(LOGE,
4702 FL("Reassoc to same AP, only supported for Open Security"));
4703 return -ENOTSUPP;
4704 }
4705 hddLog(LOG1,
4706 FL("Reassoc BSSID is same as currently associated AP bssid"));
4707 sme_get_modify_profile_fields(hdd_ctx->hHal, adapter->sessionId,
4708 &modProfileFields);
4709 sme_roam_reassoc(hdd_ctx->hHal, adapter->sessionId,
4710 NULL, modProfileFields, &roamId, 1);
4711 return 0;
4712 }
4713
4714 /* Check channel number is a valid channel number */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304715 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004716 wlan_hdd_validate_operation_channel(adapter, channel)) {
4717 hddLog(LOGE, FL("Invalid Channel [%d]"), channel);
4718 return -EINVAL;
4719 }
Varun Reddy Yeturubbbbe232016-02-29 14:01:57 -08004720 if (is_roaming_offload_enabled(hdd_ctx)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004721 hdd_wma_send_fastreassoc_cmd((int)adapter->sessionId,
4722 targetApBssid, (int)channel);
4723 goto exit;
4724 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004725 /* Proceed with reassoc */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004726 handoffInfo.channel = channel;
4727 handoffInfo.src = FASTREASSOC;
Varun Reddy Yeturua66f9c52016-02-17 09:58:40 -08004728 qdf_mem_copy(handoffInfo.bssid.bytes, targetApBssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004729 sizeof(tSirMacAddr));
4730 sme_handoff_request(hdd_ctx->hHal, adapter->sessionId,
4731 &handoffInfo);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004732exit:
4733 return ret;
4734}
4735
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004736static int drv_cmd_set_roam_scan_control(hdd_adapter_t *adapter,
4737 hdd_context_t *hdd_ctx,
4738 uint8_t *command,
4739 uint8_t command_len,
4740 hdd_priv_data_t *priv_data)
4741{
4742 int ret = 0;
4743 uint8_t *value = command;
4744 uint8_t roamScanControl = 0;
4745
4746 /* Move pointer to ahead of SETROAMSCANCONTROL<delimiter> */
4747 value = value + command_len + 1;
4748
4749 /* Convert the value from ascii to integer */
4750 ret = kstrtou8(value, 10, &roamScanControl);
4751 if (ret < 0) {
4752 /*
4753 * If the input value is greater than max value of datatype,
4754 * then also kstrtou8 fails
4755 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304756 QDF_TRACE(QDF_MODULE_ID_HDD,
4757 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004758 "%s: kstrtou8 failed ", __func__);
4759 ret = -EINVAL;
4760 goto exit;
4761 }
4762
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304763 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004764 "%s: Received Command to Set roam scan control = %d",
4765 __func__, roamScanControl);
4766
4767 if (0 != roamScanControl) {
4768 ret = 0; /* return success but ignore param value "true" */
4769 goto exit;
4770 }
4771
4772 sme_set_roam_scan_control(hdd_ctx->hHal,
4773 adapter->sessionId,
4774 roamScanControl);
4775
4776exit:
4777 return ret;
4778}
4779
4780static int drv_cmd_set_okc_mode(hdd_adapter_t *adapter,
4781 hdd_context_t *hdd_ctx,
4782 uint8_t *command,
4783 uint8_t command_len,
4784 hdd_priv_data_t *priv_data)
4785{
4786 int ret = 0;
4787 uint8_t *value = command;
4788 uint8_t okcMode = CFG_OKC_FEATURE_ENABLED_DEFAULT;
4789
4790 /*
4791 * Check if the features OKC/ESE/11R are supported simultaneously,
4792 * then this operation is not permitted (return FAILURE)
4793 */
4794 if (sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
4795 hdd_is_okc_mode_enabled(hdd_ctx) &&
4796 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304797 QDF_TRACE(QDF_MODULE_ID_HDD,
4798 QDF_TRACE_LEVEL_WARN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004799 "%s: OKC/ESE/11R are supported simultaneously hence this operation is not permitted!",
4800 __func__);
4801 ret = -EPERM;
4802 goto exit;
4803 }
4804
4805 /* Move pointer to ahead of SETOKCMODE<delimiter> */
4806 value = value + command_len + 1;
4807
4808 /* Convert the value from ascii to integer */
4809 ret = kstrtou8(value, 10, &okcMode);
4810 if (ret < 0) {
4811 /*
4812 * If the input value is greater than max value of datatype,
4813 * then also kstrtou8 fails
4814 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304815 QDF_TRACE(QDF_MODULE_ID_HDD,
4816 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004817 "%s: kstrtou8 failed range [%d - %d]",
4818 __func__, CFG_OKC_FEATURE_ENABLED_MIN,
4819 CFG_OKC_FEATURE_ENABLED_MAX);
4820 ret = -EINVAL;
4821 goto exit;
4822 }
4823
4824 if ((okcMode < CFG_OKC_FEATURE_ENABLED_MIN) ||
4825 (okcMode > CFG_OKC_FEATURE_ENABLED_MAX)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304826 QDF_TRACE(QDF_MODULE_ID_HDD,
4827 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004828 "Okc mode value %d is out of range (Min: %d Max: %d)",
4829 okcMode,
4830 CFG_OKC_FEATURE_ENABLED_MIN,
4831 CFG_OKC_FEATURE_ENABLED_MAX);
4832 ret = -EINVAL;
4833 goto exit;
4834 }
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304835 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004836 "%s: Received Command to change okc mode = %d",
4837 __func__, okcMode);
4838
4839 hdd_ctx->config->isOkcIniFeatureEnabled = okcMode;
4840
4841exit:
4842 return ret;
4843}
4844
4845static int drv_cmd_get_roam_scan_control(hdd_adapter_t *adapter,
4846 hdd_context_t *hdd_ctx,
4847 uint8_t *command,
4848 uint8_t command_len,
4849 hdd_priv_data_t *priv_data)
4850{
4851 int ret = 0;
4852 bool roamScanControl = sme_get_roam_scan_control(hdd_ctx->hHal);
4853 char extra[32];
4854 uint8_t len = 0;
4855
4856 len = scnprintf(extra, sizeof(extra), "%s %d",
4857 command, roamScanControl);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304858 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004859 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304860 QDF_TRACE(QDF_MODULE_ID_HDD,
4861 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004862 "%s: failed to copy data to user buffer",
4863 __func__);
4864 ret = -EFAULT;
4865 }
4866
4867 return ret;
4868}
4869
4870static int drv_cmd_bt_coex_mode(hdd_adapter_t *adapter,
4871 hdd_context_t *hdd_ctx,
4872 uint8_t *command,
4873 uint8_t command_len,
4874 hdd_priv_data_t *priv_data)
4875{
4876 int ret = 0;
4877 char *bcMode;
4878
4879 bcMode = command + 11;
4880 if ('1' == *bcMode) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304881 QDF_TRACE(QDF_MODULE_ID_HDD,
4882 QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004883 FL("BTCOEXMODE %d"), *bcMode);
4884 hdd_ctx->btCoexModeSet = true;
4885 ret = wlan_hdd_scan_abort(adapter);
4886 if (ret < 0) {
4887 hddLog(LOGE,
4888 FL("Failed to abort existing scan status:%d"), ret);
4889 }
4890 } else if ('2' == *bcMode) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304891 QDF_TRACE(QDF_MODULE_ID_HDD,
4892 QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004893 FL("BTCOEXMODE %d"), *bcMode);
4894 hdd_ctx->btCoexModeSet = false;
4895 }
4896
4897 return ret;
4898}
4899
4900static int drv_cmd_scan_active(hdd_adapter_t *adapter,
4901 hdd_context_t *hdd_ctx,
4902 uint8_t *command,
4903 uint8_t command_len,
4904 hdd_priv_data_t *priv_data)
4905{
4906 hdd_ctx->ioctl_scan_mode = eSIR_ACTIVE_SCAN;
4907 return 0;
4908}
4909
4910static int drv_cmd_scan_passive(hdd_adapter_t *adapter,
4911 hdd_context_t *hdd_ctx,
4912 uint8_t *command,
4913 uint8_t command_len,
4914 hdd_priv_data_t *priv_data)
4915{
4916 hdd_ctx->ioctl_scan_mode = eSIR_PASSIVE_SCAN;
4917 return 0;
4918}
4919
4920static int drv_cmd_get_dwell_time(hdd_adapter_t *adapter,
4921 hdd_context_t *hdd_ctx,
4922 uint8_t *command,
4923 uint8_t command_len,
4924 hdd_priv_data_t *priv_data)
4925{
4926 int ret = 0;
4927 struct hdd_config *pCfg =
4928 (WLAN_HDD_GET_CTX(adapter))->config;
4929 char extra[32];
4930 uint8_t len = 0;
4931
4932 memset(extra, 0, sizeof(extra));
4933 ret = hdd_get_dwell_time(pCfg, command, extra, sizeof(extra), &len);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304934 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004935 if (ret != 0 || copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304936 QDF_TRACE(QDF_MODULE_ID_HDD,
4937 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004938 "%s: failed to copy data to user buffer",
4939 __func__);
4940 ret = -EFAULT;
4941 goto exit;
4942 }
4943 ret = len;
4944exit:
4945 return ret;
4946}
4947
4948static int drv_cmd_set_dwell_time(hdd_adapter_t *adapter,
4949 hdd_context_t *hdd_ctx,
4950 uint8_t *command,
4951 uint8_t command_len,
4952 hdd_priv_data_t *priv_data)
4953{
4954 return hdd_set_dwell_time(adapter, command);
4955}
4956
4957static int drv_cmd_miracast(hdd_adapter_t *adapter,
4958 hdd_context_t *hdd_ctx,
4959 uint8_t *command,
4960 uint8_t command_len,
4961 hdd_priv_data_t *priv_data)
4962{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304963 QDF_STATUS ret_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004964 int ret = 0;
4965 tHalHandle hHal;
4966 uint8_t filterType = 0;
4967 hdd_context_t *pHddCtx = NULL;
4968 uint8_t *value;
4969
4970 pHddCtx = WLAN_HDD_GET_CTX(adapter);
4971 if (0 != wlan_hdd_validate_context(pHddCtx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304972 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004973 "%s pHddCtx is not valid, Unable to set miracast mode",
4974 __func__);
4975 return -EINVAL;
4976 }
4977
4978 hHal = pHddCtx->hHal;
4979 value = command + 9;
4980
4981 /* Convert the value from ascii to integer */
4982 ret = kstrtou8(value, 10, &filterType);
4983 if (ret < 0) {
4984 /*
4985 * If the input value is greater than max value of datatype,
4986 * then also kstrtou8 fails
4987 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304988 QDF_TRACE(QDF_MODULE_ID_HDD,
4989 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004990 "%s: kstrtou8 failed range ",
4991 __func__);
4992 ret = -EINVAL;
4993 goto exit;
4994 }
4995 if ((filterType < WLAN_HDD_DRIVER_MIRACAST_CFG_MIN_VAL)
4996 || (filterType >
4997 WLAN_HDD_DRIVER_MIRACAST_CFG_MAX_VAL)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304998 QDF_TRACE(QDF_MODULE_ID_HDD,
4999 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005000 "%s: Accepted Values are 0 to 2. 0-Disabled, 1-Source, 2-Sink ",
5001 __func__);
5002 ret = -EINVAL;
5003 goto exit;
5004 }
5005 /* Filtertype value should be either 0-Disabled, 1-Source, 2-sink */
5006 pHddCtx->miracast_value = filterType;
5007
5008 ret_status = sme_set_miracast(hHal, filterType);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305009 if (QDF_STATUS_SUCCESS != ret_status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005010 hddLog(LOGE, "Failed to set miracast");
5011 return -EBUSY;
5012 }
5013
Tushnim Bhattacharyyaca50b322015-12-28 17:14:36 -08005014 if (cds_is_mcc_in_24G())
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005015 return cds_set_mas(adapter, filterType);
5016
5017exit:
5018 return ret;
5019}
5020
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005021/* Function header is left blank intentionally */
5022static int hdd_parse_set_ibss_oui_data_command(uint8_t *command, uint8_t *ie,
5023 int32_t *oui_length, int32_t limit)
5024{
5025 uint8_t len;
5026 uint8_t data;
5027
5028 while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) {
5029 command++;
5030 limit--;
5031 }
5032
5033 len = 2;
5034
5035 while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) &&
5036 (limit > 1)) {
5037 sscanf(command, "%02x", (unsigned int *)&data);
5038 ie[len++] = data;
5039 command += 2;
5040 limit -= 2;
5041 }
5042
5043 *oui_length = len - 2;
5044
5045 while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) {
5046 command++;
5047 limit--;
5048 }
5049
5050 while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) &&
5051 (limit > 1)) {
5052 sscanf(command, "%02x", (unsigned int *)&data);
5053 ie[len++] = data;
5054 command += 2;
5055 limit -= 2;
5056 }
5057
5058 ie[0] = IE_EID_VENDOR;
5059 ie[1] = len - 2;
5060
5061 return len;
5062}
5063
5064/**
5065 * drv_cmd_set_ibss_beacon_oui_data() - set ibss oui data command
5066 * @adapter: Pointer to adapter
5067 * @hdd_ctx: Pointer to HDD context
5068 * @command: Pointer to command string
5069 * @command_len : Command length
5070 * @priv_data : Pointer to priv data
5071 *
5072 * Return:
5073 * int status code
5074 */
5075static int drv_cmd_set_ibss_beacon_oui_data(hdd_adapter_t *adapter,
5076 hdd_context_t *hdd_ctx,
5077 uint8_t *command,
5078 uint8_t command_len,
5079 hdd_priv_data_t *priv_data)
5080{
5081 int i = 0;
5082 int status;
5083 int ret = 0;
5084 uint8_t *ibss_ie;
5085 int32_t oui_length = 0;
5086 uint32_t ibss_ie_length;
5087 uint8_t *value = command;
5088 tSirModifyIE ibssModifyIE;
5089 tCsrRoamProfile *pRoamProfile;
5090 hdd_wext_state_t *pWextState;
5091
5092
Krunal Sonibe766b02016-03-10 13:00:44 -08005093 if (QDF_IBSS_MODE != adapter->device_mode) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005094 hddLog(LOG1, FL("Device_mode %s(%d) not IBSS"),
5095 hdd_device_mode_to_string(adapter->device_mode),
5096 adapter->device_mode);
5097 return ret;
5098 }
5099
5100 pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(adapter);
5101
5102 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
5103 "%s: received command %s", __func__,
5104 ((char *)value));
5105
5106
5107 /* validate argument of command */
5108 if (strlen(value) <= command_len) {
5109 hddLog(LOGE,
5110 FL("No arguements in command length %zu"),
5111 strlen(value));
5112 ret = -EFAULT;
5113 goto exit;
5114 }
5115
5116 /* moving to arguments of commands */
5117 value = value + command_len;
5118 command_len = strlen(value);
5119
5120 /* oui_data can't be less than 3 bytes */
5121 if (command_len < (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) {
5122 hddLog(LOGE,
5123 FL("Invalid SETIBSSBEACONOUIDATA command length %d"),
5124 command_len);
5125 ret = -EFAULT;
5126 goto exit;
5127 }
5128
5129 ibss_ie = qdf_mem_malloc(command_len);
5130 if (!ibss_ie) {
5131 hddLog(LOGE,
5132 FL("Could not allocate memory for command length %d"),
5133 command_len);
5134 ret = -ENOMEM;
5135 goto exit;
5136 }
5137 qdf_mem_zero(ibss_ie, command_len);
5138
5139 ibss_ie_length = hdd_parse_set_ibss_oui_data_command(value, ibss_ie,
5140 &oui_length,
5141 command_len);
5142 if (ibss_ie_length <= (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) {
5143 hddLog(LOGE, FL("Could not parse command %s return length %d"),
5144 value, ibss_ie_length);
5145 ret = -EFAULT;
5146 qdf_mem_free(ibss_ie);
5147 goto exit;
5148 }
5149
5150 pRoamProfile = &pWextState->roamProfile;
5151
5152 qdf_copy_macaddr(&ibssModifyIE.bssid,
5153 pRoamProfile->BSSIDs.bssid);
5154
5155 ibssModifyIE.smeSessionId = adapter->sessionId;
5156 ibssModifyIE.notify = true;
5157 ibssModifyIE.ieID = IE_EID_VENDOR;
5158 ibssModifyIE.ieIDLen = ibss_ie_length;
5159 ibssModifyIE.ieBufferlength = ibss_ie_length;
5160 ibssModifyIE.pIEBuffer = ibss_ie;
5161 ibssModifyIE.oui_length = oui_length;
5162
5163 hddLog(LOGW, FL("ibss_ie length %d oui_length %d ibss_ie:"),
5164 ibss_ie_length, oui_length);
5165 while (i < ibssModifyIE.ieBufferlength)
5166 hddLog(LOGW, FL("0x%x"), ibss_ie[i++]);
5167
5168 /* Probe Bcn modification */
5169 sme_modify_add_ie(WLAN_HDD_GET_HAL_CTX(adapter),
5170 &ibssModifyIE, eUPDATE_IE_PROBE_BCN);
5171
5172 /* Populating probe resp frame */
5173 sme_modify_add_ie(WLAN_HDD_GET_HAL_CTX(adapter),
5174 &ibssModifyIE, eUPDATE_IE_PROBE_RESP);
5175
5176 qdf_mem_free(ibss_ie);
5177
5178 status = sme_send_cesium_enable_ind((tHalHandle)(hdd_ctx->hHal),
5179 adapter->sessionId);
5180 if (QDF_STATUS_SUCCESS != status) {
5181 QDF_TRACE(QDF_MODULE_ID_HDD,
5182 QDF_TRACE_LEVEL_ERROR,
5183 "Could not send cesium enable indication %d",
5184 status);
5185 ret = -EINVAL;
5186 goto exit;
5187 }
5188
5189exit:
5190 return ret;
5191}
5192
5193static int drv_cmd_set_rmc_enable(hdd_adapter_t *adapter,
5194 hdd_context_t *hdd_ctx,
5195 uint8_t *command,
5196 uint8_t command_len,
5197 hdd_priv_data_t *priv_data)
5198{
5199 int ret = 0;
5200 uint8_t *value = command;
5201 uint8_t ucRmcEnable = 0;
5202 int status;
5203
Krunal Sonibe766b02016-03-10 13:00:44 -08005204 if ((QDF_IBSS_MODE != adapter->device_mode) &&
5205 (QDF_SAP_MODE != adapter->device_mode)) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005206 hddLog(LOGE,
5207 "Received SETRMCENABLE cmd in invalid mode %s(%d)",
5208 hdd_device_mode_to_string(adapter->device_mode),
5209 adapter->device_mode);
5210 hddLog(LOGE,
5211 "SETRMCENABLE cmd is allowed only in IBSS/SOFTAP mode");
5212 ret = -EINVAL;
5213 goto exit;
5214 }
5215
5216 status = hdd_parse_setrmcenable_command(value, &ucRmcEnable);
5217 if (status) {
5218 QDF_TRACE(QDF_MODULE_ID_HDD,
5219 QDF_TRACE_LEVEL_ERROR,
5220 "Invalid SETRMCENABLE command ");
5221 ret = -EINVAL;
5222 goto exit;
5223 }
5224
5225 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
5226 "%s: ucRmcEnable %d ", __func__, ucRmcEnable);
5227
5228 if (true == ucRmcEnable) {
5229 status = sme_enable_rmc((tHalHandle)
5230 (hdd_ctx->hHal),
5231 adapter->sessionId);
5232 } else if (false == ucRmcEnable) {
5233 status = sme_disable_rmc((tHalHandle)
5234 (hdd_ctx->hHal),
5235 adapter->sessionId);
5236 } else {
5237 QDF_TRACE(QDF_MODULE_ID_HDD,
5238 QDF_TRACE_LEVEL_ERROR,
5239 "Invalid SETRMCENABLE command %d",
5240 ucRmcEnable);
5241 ret = -EINVAL;
5242 goto exit;
5243 }
5244
5245 if (QDF_STATUS_SUCCESS != status) {
5246 QDF_TRACE(QDF_MODULE_ID_HDD,
5247 QDF_TRACE_LEVEL_ERROR,
5248 "%s: SETRMC %d failed status %d",
5249 __func__, ucRmcEnable, status);
5250 ret = -EINVAL;
5251 goto exit;
5252 }
5253
5254exit:
5255 return ret;
5256}
5257
5258static int drv_cmd_set_rmc_action_period(hdd_adapter_t *adapter,
5259 hdd_context_t *hdd_ctx,
5260 uint8_t *command,
5261 uint8_t command_len,
5262 hdd_priv_data_t *priv_data)
5263{
5264 int ret = 0;
5265 uint8_t *value = command;
5266 uint32_t uActionPeriod = 0;
5267 int status;
5268
Krunal Sonibe766b02016-03-10 13:00:44 -08005269 if ((QDF_IBSS_MODE != adapter->device_mode) &&
5270 (QDF_SAP_MODE != adapter->device_mode)) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005271 hddLog(LOGE, "Received SETRMC cmd in invalid mode %s(%d)",
5272 hdd_device_mode_to_string(adapter->device_mode),
5273 adapter->device_mode);
5274 hddLog(LOGE,
5275 "SETRMC cmd is allowed only in IBSS/SOFTAP mode");
5276 ret = -EINVAL;
5277 goto exit;
5278 }
5279
5280 status = hdd_parse_setrmcactionperiod_command(value, &uActionPeriod);
5281 if (status) {
5282 QDF_TRACE(QDF_MODULE_ID_HDD,
5283 QDF_TRACE_LEVEL_ERROR,
5284 "Invalid SETRMCACTIONPERIOD command ");
5285 ret = -EINVAL;
5286 goto exit;
5287 }
5288
5289 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
5290 "%s: uActionPeriod %d ", __func__,
5291 uActionPeriod);
5292
5293 if (sme_cfg_set_int(hdd_ctx->hHal,
5294 WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY,
5295 uActionPeriod)) {
5296 QDF_TRACE(QDF_MODULE_ID_HDD,
5297 QDF_TRACE_LEVEL_ERROR,
5298 "%s: Could not set SETRMCACTIONPERIOD %d",
5299 __func__, uActionPeriod);
5300 ret = -EINVAL;
5301 goto exit;
5302 }
5303
5304 status = sme_send_rmc_action_period((tHalHandle)(hdd_ctx->hHal),
5305 adapter->sessionId);
5306 if (QDF_STATUS_SUCCESS != status) {
5307 QDF_TRACE(QDF_MODULE_ID_HDD,
5308 QDF_TRACE_LEVEL_ERROR,
5309 "Could not send cesium enable indication %d",
5310 status);
5311 ret = -EINVAL;
5312 goto exit;
5313 }
5314
5315exit:
5316 return ret;
5317}
5318
5319static int drv_cmd_get_ibss_peer_info_all(hdd_adapter_t *adapter,
5320 hdd_context_t *hdd_ctx,
5321 uint8_t *command,
5322 uint8_t command_len,
5323 hdd_priv_data_t *priv_data)
5324{
5325 int ret = 0;
5326 int status = QDF_STATUS_SUCCESS;
5327 hdd_station_ctx_t *pHddStaCtx = NULL;
5328 char *extra = NULL;
5329 int idx = 0;
5330 int length = 0;
5331 struct qdf_mac_addr *macAddr;
5332 uint32_t txRateMbps = 0;
5333 uint32_t numOfBytestoPrint = 0;
5334
Krunal Sonibe766b02016-03-10 13:00:44 -08005335 if (QDF_IBSS_MODE != adapter->device_mode) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005336 hdd_warn("Unsupported in mode %s(%d)",
5337 hdd_device_mode_to_string(adapter->device_mode),
5338 adapter->device_mode);
5339 return -EINVAL;
5340 }
5341
5342 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5343 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
5344 "%s: Received GETIBSSPEERINFOALL Command",
5345 __func__);
5346
5347 /* Handle the command */
5348 status = hdd_cfg80211_get_ibss_peer_info_all(adapter);
5349 if (QDF_STATUS_SUCCESS == status) {
5350 /*
5351 * The variable extra needed to be allocated on the heap since
5352 * amount of memory required to copy the data for 32 devices
5353 * exceeds the size of 1024 bytes of default stack size. On
5354 * 64 bit devices, the default max stack size of 2048 bytes
5355 */
5356 extra = kmalloc(WLAN_MAX_BUF_SIZE, GFP_KERNEL);
5357
5358 if (NULL == extra) {
5359 QDF_TRACE(QDF_MODULE_ID_HDD,
5360 QDF_TRACE_LEVEL_ERROR,
5361 "%s:kmalloc failed",
5362 __func__);
5363 ret = -EINVAL;
5364 goto exit;
5365 }
5366
5367 /* Copy number of stations */
5368 length = scnprintf(extra, WLAN_MAX_BUF_SIZE, "%d ",
5369 pHddStaCtx->ibss_peer_info.
5370 numIBSSPeers);
5371 numOfBytestoPrint = length;
5372 for (idx = 0; idx < pHddStaCtx->ibss_peer_info.numIBSSPeers;
5373 idx++) {
5374 macAddr = hdd_wlan_get_ibss_mac_addr_from_staid
5375 (adapter,
5376 pHddStaCtx->ibss_peer_info.
5377 ibssPeerList[idx].staIdx);
5378 if (NULL != macAddr) {
5379 txRateMbps = ((pHddStaCtx->
5380 ibss_peer_info.
5381 ibssPeerList[idx].txRate)
5382 * 500 * 1000) / 1000000;
5383 length += scnprintf((extra + length),
5384 WLAN_MAX_BUF_SIZE - length,
5385 "%02x:%02x:%02x:%02x:%02x:%02x %d %d ",
5386 macAddr->bytes[0],
5387 macAddr->bytes[1],
5388 macAddr->bytes[2],
5389 macAddr->bytes[3],
5390 macAddr->bytes[4],
5391 macAddr->bytes[5],
5392 (int)txRateMbps,
5393 (int)pHddStaCtx->
5394 ibss_peer_info.
5395 ibssPeerList[idx].
5396 rssi);
5397 } else {
5398 QDF_TRACE(QDF_MODULE_ID_HDD,
5399 QDF_TRACE_LEVEL_ERROR,
5400 "%s: MAC ADDR is NULL for staIdx: %d",
5401 __func__,
5402 pHddStaCtx->
5403 ibss_peer_info.
5404 ibssPeerList[idx].
5405 staIdx);
5406 }
5407
5408 /*
5409 * QDF_TRACE() macro has limitation of 512 bytes
5410 * for the print buffer. Hence printing the data
5411 * in two chunks. The first chunk will have the data
5412 * for 16 devices and the second chunk will
5413 * have the rest.
5414 */
5415 if (idx < NUM_OF_STA_DATA_TO_PRINT)
5416 numOfBytestoPrint = length;
5417 }
5418
5419 /*
5420 * Copy the data back into buffer, if the data to copy is
5421 * more than 512 bytes than we will split the data and do
5422 * it in two shots
5423 */
5424 if (copy_to_user(priv_data->buf, extra, numOfBytestoPrint)) {
5425 QDF_TRACE(QDF_MODULE_ID_HDD,
5426 QDF_TRACE_LEVEL_ERROR,
5427 "%s: Copy into user data buffer failed ",
5428 __func__);
5429 ret = -EFAULT;
5430 goto exit;
5431 }
5432
5433 priv_data->buf[numOfBytestoPrint] = '\0';
5434 QDF_TRACE(QDF_MODULE_ID_HDD,
5435 QDF_TRACE_LEVEL_INFO_MED, "%s",
5436 priv_data->buf);
5437
5438 if (length > numOfBytestoPrint) {
5439 if (copy_to_user
5440 (priv_data->buf + numOfBytestoPrint,
5441 extra + numOfBytestoPrint,
5442 length - numOfBytestoPrint + 1)) {
5443 QDF_TRACE(QDF_MODULE_ID_HDD,
5444 QDF_TRACE_LEVEL_ERROR,
5445 "%s: Copy into user data buffer failed ",
5446 __func__);
5447 ret = -EFAULT;
5448 goto exit;
5449 }
5450 QDF_TRACE(QDF_MODULE_ID_HDD,
5451 QDF_TRACE_LEVEL_INFO_MED,
5452 "%s",
5453 &priv_data->buf[numOfBytestoPrint]);
5454 }
5455
5456 /* Free temporary buffer */
5457 kfree(extra);
5458 } else {
5459 /* Command failed, log error */
5460 QDF_TRACE(QDF_MODULE_ID_HDD,
5461 QDF_TRACE_LEVEL_ERROR,
5462 "%s: GETIBSSPEERINFOALL command failed with status code %d",
5463 __func__, status);
5464 ret = -EINVAL;
5465 goto exit;
5466 }
5467 ret = 0;
5468
5469exit:
5470 return ret;
5471}
5472
5473/* Peer Info <Peer Addr> command */
5474static int drv_cmd_get_ibss_peer_info(hdd_adapter_t *adapter,
5475 hdd_context_t *hdd_ctx,
5476 uint8_t *command,
5477 uint8_t command_len,
5478 hdd_priv_data_t *priv_data)
5479{
5480 int ret = 0;
5481 uint8_t *value = command;
5482 QDF_STATUS status;
5483 hdd_station_ctx_t *pHddStaCtx = NULL;
5484 char extra[128] = { 0 };
5485 uint32_t length = 0;
5486 uint8_t staIdx = 0;
5487 uint32_t txRateMbps = 0;
5488 uint32_t txRate;
5489 struct qdf_mac_addr peerMacAddr;
5490
Krunal Sonibe766b02016-03-10 13:00:44 -08005491 if (QDF_IBSS_MODE != adapter->device_mode) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005492 hdd_warn("Unsupported in mode %s(%d)",
5493 hdd_device_mode_to_string(adapter->device_mode),
5494 adapter->device_mode);
5495 return -EINVAL;
5496 }
5497
5498 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5499
5500 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
5501 "%s: Received GETIBSSPEERINFO Command",
5502 __func__);
5503
5504 /* if there are no peers, no need to continue with the command */
5505 if (eConnectionState_IbssConnected !=
5506 pHddStaCtx->conn_info.connState) {
5507 QDF_TRACE(QDF_MODULE_ID_HDD,
5508 QDF_TRACE_LEVEL_INFO,
5509 "%s:No IBSS Peers coalesced",
5510 __func__);
5511 ret = -EINVAL;
5512 goto exit;
5513 }
5514
5515 /* Parse the incoming command buffer */
5516 status = hdd_parse_get_ibss_peer_info(value, &peerMacAddr);
5517 if (QDF_STATUS_SUCCESS != status) {
5518 QDF_TRACE(QDF_MODULE_ID_HDD,
5519 QDF_TRACE_LEVEL_ERROR,
5520 "%s: Invalid GETIBSSPEERINFO command",
5521 __func__);
5522 ret = -EINVAL;
5523 goto exit;
5524 }
5525
5526 /* Get station index for the peer mac address */
5527 hdd_ibss_get_sta_id(pHddStaCtx, &peerMacAddr, &staIdx);
5528
5529 if (staIdx > MAX_IBSS_PEERS) {
5530 QDF_TRACE(QDF_MODULE_ID_HDD,
5531 QDF_TRACE_LEVEL_ERROR,
5532 "%s: Invalid StaIdx %d returned",
5533 __func__, staIdx);
5534 ret = -EINVAL;
5535 goto exit;
5536 }
5537
5538 /* Handle the command */
5539 status = hdd_cfg80211_get_ibss_peer_info(adapter, staIdx);
5540 if (QDF_STATUS_SUCCESS == status) {
5541 txRate = pHddStaCtx->ibss_peer_info.ibssPeerList[0].txRate;
5542 txRateMbps = (txRate * 500 * 1000) / 1000000;
5543
5544 length = scnprintf(extra, sizeof(extra), "%d %d",
5545 (int)txRateMbps,
5546 (int)pHddStaCtx->ibss_peer_info.
5547 ibssPeerList[0].rssi);
5548
5549 /* Copy the data back into buffer */
5550 if (copy_to_user(priv_data->buf, &extra, length + 1)) {
5551 QDF_TRACE(QDF_MODULE_ID_HDD,
5552 QDF_TRACE_LEVEL_ERROR,
5553 "%s: copy data to user buffer failed GETIBSSPEERINFO command",
5554 __func__);
5555 ret = -EFAULT;
5556 goto exit;
5557 }
5558 } else {
5559 /* Command failed, log error */
5560 QDF_TRACE(QDF_MODULE_ID_HDD,
5561 QDF_TRACE_LEVEL_ERROR,
5562 "%s: GETIBSSPEERINFO command failed with status code %d",
5563 __func__, status);
5564 ret = -EINVAL;
5565 goto exit;
5566 }
5567
5568 /* Success ! */
5569 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO_MED,
5570 "%s", priv_data->buf);
5571 ret = 0;
5572
5573exit:
5574 return ret;
5575}
5576
5577static int drv_cmd_set_rmc_tx_rate(hdd_adapter_t *adapter,
5578 hdd_context_t *hdd_ctx,
5579 uint8_t *command,
5580 uint8_t command_len,
5581 hdd_priv_data_t *priv_data)
5582{
5583 int ret = 0;
5584 uint8_t *value = command;
5585 uint32_t uRate = 0;
5586 tTxrateinfoflags txFlags = 0;
5587 tSirRateUpdateInd rateUpdateParams = {0};
5588 int status;
5589 struct hdd_config *pConfig = hdd_ctx->config;
5590
Krunal Sonibe766b02016-03-10 13:00:44 -08005591 if ((QDF_IBSS_MODE != adapter->device_mode) &&
5592 (QDF_SAP_MODE != adapter->device_mode)) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005593 hddLog(LOGE,
5594 "Received SETRMCTXRATE cmd in invalid mode %s(%d)",
5595 hdd_device_mode_to_string(adapter->device_mode),
5596 adapter->device_mode);
5597 hddLog(LOGE,
5598 "SETRMCTXRATE cmd is allowed only in IBSS/SOFTAP mode");
5599 ret = -EINVAL;
5600 goto exit;
5601 }
5602
5603 status = hdd_parse_setrmcrate_command(value, &uRate, &txFlags);
5604 if (status) {
5605 QDF_TRACE(QDF_MODULE_ID_HDD,
5606 QDF_TRACE_LEVEL_ERROR,
5607 "Invalid SETRMCTXRATE command ");
5608 ret = -EINVAL;
5609 goto exit;
5610 }
5611 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
5612 "%s: uRate %d ", __func__, uRate);
5613 /* -1 implies ignore this param */
5614 rateUpdateParams.ucastDataRate = -1;
5615
5616 /*
5617 * Fill the user specifieed RMC rate param
5618 * and the derived tx flags.
5619 */
5620 rateUpdateParams.nss = (pConfig->enable2x2 == 0) ? 0 : 1;
5621 rateUpdateParams.reliableMcastDataRate = uRate;
5622 rateUpdateParams.reliableMcastDataRateTxFlag = txFlags;
5623 rateUpdateParams.dev_mode = adapter->device_mode;
5624 rateUpdateParams.bcastDataRate = -1;
5625 memcpy(rateUpdateParams.bssid.bytes,
5626 adapter->macAddressCurrent.bytes,
5627 sizeof(rateUpdateParams.bssid));
5628 status = sme_send_rate_update_ind((tHalHandle) (hdd_ctx->hHal),
5629 &rateUpdateParams);
5630
5631exit:
5632 return ret;
5633}
5634
5635static int drv_cmd_set_ibss_tx_fail_event(hdd_adapter_t *adapter,
5636 hdd_context_t *hdd_ctx,
5637 uint8_t *command,
5638 uint8_t command_len,
5639 hdd_priv_data_t *priv_data)
5640{
5641 int ret = 0;
5642 char *value;
5643 uint8_t tx_fail_count = 0;
5644 uint16_t pid = 0;
5645
5646 value = command;
5647
5648 ret = hdd_parse_ibsstx_fail_event_params(value, &tx_fail_count, &pid);
5649
5650 if (0 != ret) {
5651 hddLog(QDF_TRACE_LEVEL_INFO,
5652 "%s: Failed to parse SETIBSSTXFAILEVENT arguments",
5653 __func__);
5654 goto exit;
5655 }
5656
5657 hddLog(QDF_TRACE_LEVEL_INFO,
5658 "%s: tx_fail_cnt=%hhu, pid=%hu", __func__,
5659 tx_fail_count, pid);
5660
5661 if (0 == tx_fail_count) {
5662 /* Disable TX Fail Indication */
5663 if (QDF_STATUS_SUCCESS ==
5664 sme_tx_fail_monitor_start_stop_ind(hdd_ctx->hHal,
5665 tx_fail_count,
5666 NULL)) {
5667 cesium_pid = 0;
5668 } else {
5669 QDF_TRACE(QDF_MODULE_ID_HDD,
5670 QDF_TRACE_LEVEL_ERROR,
5671 "%s: failed to disable TX Fail Event ",
5672 __func__);
5673 ret = -EINVAL;
5674 }
5675 } else {
5676 if (QDF_STATUS_SUCCESS ==
5677 sme_tx_fail_monitor_start_stop_ind(hdd_ctx->hHal,
5678 tx_fail_count,
5679 (void *)hdd_tx_fail_ind_callback)) {
5680 cesium_pid = pid;
5681 QDF_TRACE(QDF_MODULE_ID_HDD,
5682 QDF_TRACE_LEVEL_INFO,
5683 "%s: Registered Cesium pid %u",
5684 __func__, cesium_pid);
5685 } else {
5686 QDF_TRACE(QDF_MODULE_ID_HDD,
5687 QDF_TRACE_LEVEL_ERROR,
5688 "%s: Failed to enable TX Fail Monitoring",
5689 __func__);
5690 ret = -EINVAL;
5691 }
5692 }
5693
5694exit:
5695 return ret;
5696}
5697
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08005698#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005699static int drv_cmd_set_ccx_roam_scan_channels(hdd_adapter_t *adapter,
5700 hdd_context_t *hdd_ctx,
5701 uint8_t *command,
5702 uint8_t command_len,
5703 hdd_priv_data_t *priv_data)
5704{
5705 int ret = 0;
5706 uint8_t *value = command;
5707 uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
5708 uint8_t numChannels = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305709 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005710
5711 ret = hdd_parse_channellist(value, ChannelList, &numChannels);
5712 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305713 QDF_TRACE(QDF_MODULE_ID_HDD,
5714 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005715 "%s: Failed to parse channel list information",
5716 __func__);
5717 goto exit;
5718 }
5719 if (numChannels > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305720 QDF_TRACE(QDF_MODULE_ID_HDD,
5721 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005722 "%s: number of channels (%d) supported exceeded max (%d)",
5723 __func__,
5724 numChannels,
5725 WNI_CFG_VALID_CHANNEL_LIST_LEN);
5726 ret = -EINVAL;
5727 goto exit;
5728 }
5729 status = sme_set_ese_roam_scan_channel_list(hdd_ctx->hHal,
5730 adapter->sessionId,
5731 ChannelList,
5732 numChannels);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305733 if (QDF_STATUS_SUCCESS != status) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305734 QDF_TRACE(QDF_MODULE_ID_HDD,
5735 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005736 "%s: Failed to update channel list information",
5737 __func__);
5738 ret = -EINVAL;
5739 goto exit;
5740 }
5741
5742exit:
5743 return ret;
5744}
5745
5746static int drv_cmd_get_tsm_stats(hdd_adapter_t *adapter,
5747 hdd_context_t *hdd_ctx,
5748 uint8_t *command,
5749 uint8_t command_len,
5750 hdd_priv_data_t *priv_data)
5751{
5752 int ret = 0;
5753 uint8_t *value = command;
5754 char extra[128] = { 0 };
5755 int len = 0;
5756 uint8_t tid = 0;
5757 hdd_station_ctx_t *pHddStaCtx;
5758 tAniTrafStrmMetrics tsm_metrics;
5759
Krunal Sonibe766b02016-03-10 13:00:44 -08005760 if ((QDF_STA_MODE != adapter->device_mode) &&
5761 (QDF_P2P_CLIENT_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005762 hdd_warn("Unsupported in mode %s(%d)",
5763 hdd_device_mode_to_string(adapter->device_mode),
5764 adapter->device_mode);
5765 return -EINVAL;
5766 }
5767
5768 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5769
5770 /* if not associated, return error */
5771 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305772 QDF_TRACE(QDF_MODULE_ID_HDD,
5773 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005774 "%s:Not associated!", __func__);
5775 ret = -EINVAL;
5776 goto exit;
5777 }
5778
5779 /* Move pointer to ahead of GETTSMSTATS<delimiter> */
5780 value = value + command_len + 1;
5781
5782 /* Convert the value from ascii to integer */
5783 ret = kstrtou8(value, 10, &tid);
5784 if (ret < 0) {
5785 /*
5786 * If the input value is greater than max value of datatype,
5787 * then also kstrtou8 fails
5788 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305789 QDF_TRACE(QDF_MODULE_ID_HDD,
5790 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005791 "%s: kstrtou8 failed range [%d - %d]",
5792 __func__, TID_MIN_VALUE,
5793 TID_MAX_VALUE);
5794 ret = -EINVAL;
5795 goto exit;
5796 }
5797 if ((tid < TID_MIN_VALUE) || (tid > TID_MAX_VALUE)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305798 QDF_TRACE(QDF_MODULE_ID_HDD,
5799 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005800 "tid value %d is out of range (Min: %d Max: %d)",
5801 tid, TID_MIN_VALUE, TID_MAX_VALUE);
5802 ret = -EINVAL;
5803 goto exit;
5804 }
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305805 QDF_TRACE(QDF_MODULE_ID_HDD,
5806 QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005807 "%s: Received Command to get tsm stats tid = %d",
5808 __func__, tid);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305809 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005810 hdd_get_tsm_stats(adapter, tid, &tsm_metrics)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305811 QDF_TRACE(QDF_MODULE_ID_HDD,
5812 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005813 "%s: failed to get tsm stats",
5814 __func__);
5815 ret = -EFAULT;
5816 goto exit;
5817 }
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305818 QDF_TRACE(QDF_MODULE_ID_HDD,
5819 QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005820 "UplinkPktQueueDly(%d) UplinkPktQueueDlyHist[0](%d) UplinkPktQueueDlyHist[1](%d) UplinkPktQueueDlyHist[2](%d) UplinkPktQueueDlyHist[3](%d) UplinkPktTxDly(%u) UplinkPktLoss(%d) UplinkPktCount(%d) RoamingCount(%d) RoamingDly(%d)",
5821 tsm_metrics.UplinkPktQueueDly,
5822 tsm_metrics.UplinkPktQueueDlyHist[0],
5823 tsm_metrics.UplinkPktQueueDlyHist[1],
5824 tsm_metrics.UplinkPktQueueDlyHist[2],
5825 tsm_metrics.UplinkPktQueueDlyHist[3],
5826 tsm_metrics.UplinkPktTxDly,
5827 tsm_metrics.UplinkPktLoss,
5828 tsm_metrics.UplinkPktCount,
5829 tsm_metrics.RoamingCount,
5830 tsm_metrics.RoamingDly);
5831 /*
5832 * Output TSM stats is of the format
5833 * GETTSMSTATS [PktQueueDly]
5834 * [PktQueueDlyHist[0]]:[PktQueueDlyHist[1]] ...[RoamingDly]
5835 * eg., GETTSMSTATS 10 1:0:0:161 20 1 17 8 39800
5836 */
5837 len = scnprintf(extra,
5838 sizeof(extra),
5839 "%s %d %d:%d:%d:%d %u %d %d %d %d",
5840 command,
5841 tsm_metrics.UplinkPktQueueDly,
5842 tsm_metrics.UplinkPktQueueDlyHist[0],
5843 tsm_metrics.UplinkPktQueueDlyHist[1],
5844 tsm_metrics.UplinkPktQueueDlyHist[2],
5845 tsm_metrics.UplinkPktQueueDlyHist[3],
5846 tsm_metrics.UplinkPktTxDly,
5847 tsm_metrics.UplinkPktLoss,
5848 tsm_metrics.UplinkPktCount,
5849 tsm_metrics.RoamingCount,
5850 tsm_metrics.RoamingDly);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305851 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005852 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305853 QDF_TRACE(QDF_MODULE_ID_HDD,
5854 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005855 "%s: failed to copy data to user buffer",
5856 __func__);
5857 ret = -EFAULT;
5858 goto exit;
5859 }
5860
5861exit:
5862 return ret;
5863}
5864
5865static int drv_cmd_set_cckm_ie(hdd_adapter_t *adapter,
5866 hdd_context_t *hdd_ctx,
5867 uint8_t *command,
5868 uint8_t command_len,
5869 hdd_priv_data_t *priv_data)
5870{
5871 int ret;
5872 uint8_t *value = command;
5873 uint8_t *cckmIe = NULL;
5874 uint8_t cckmIeLen = 0;
5875
5876 ret = hdd_parse_get_cckm_ie(value, &cckmIe, &cckmIeLen);
5877 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305878 QDF_TRACE(QDF_MODULE_ID_HDD,
5879 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005880 "%s: Failed to parse cckm ie data",
5881 __func__);
5882 goto exit;
5883 }
5884
5885 if (cckmIeLen > DOT11F_IE_RSN_MAX_LEN) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305886 QDF_TRACE(QDF_MODULE_ID_HDD,
5887 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005888 "%s: CCKM Ie input length is more than max[%d]",
5889 __func__, DOT11F_IE_RSN_MAX_LEN);
5890 if (NULL != cckmIe) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305891 qdf_mem_free(cckmIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005892 cckmIe = NULL;
5893 }
5894 ret = -EINVAL;
5895 goto exit;
5896 }
5897
5898 sme_set_cckm_ie(hdd_ctx->hHal, adapter->sessionId,
5899 cckmIe, cckmIeLen);
5900 if (NULL != cckmIe) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305901 qdf_mem_free(cckmIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005902 cckmIe = NULL;
5903 }
5904
5905exit:
5906 return ret;
5907}
5908
5909static int drv_cmd_ccx_beacon_req(hdd_adapter_t *adapter,
5910 hdd_context_t *hdd_ctx,
5911 uint8_t *command,
5912 uint8_t command_len,
5913 hdd_priv_data_t *priv_data)
5914{
5915 int ret;
5916 uint8_t *value = command;
5917 tCsrEseBeaconReq eseBcnReq;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305918 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005919
Krunal Sonibe766b02016-03-10 13:00:44 -08005920 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005921 hdd_warn("Unsupported in mode %s(%d)",
5922 hdd_device_mode_to_string(adapter->device_mode),
5923 adapter->device_mode);
5924 return -EINVAL;
5925 }
5926
5927 ret = hdd_parse_ese_beacon_req(value, &eseBcnReq);
5928 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305929 QDF_TRACE(QDF_MODULE_ID_HDD,
5930 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005931 "%s: Failed to parse ese beacon req",
5932 __func__);
5933 goto exit;
5934 }
5935
5936 if (!hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305937 hddLog(QDF_TRACE_LEVEL_INFO, FL("Not associated"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005938 hdd_indicate_ese_bcn_report_no_results(adapter,
5939 eseBcnReq.bcnReq[0].measurementToken,
5940 0x02, /* BIT(1) set for measurement done */
5941 0); /* no BSS */
5942 goto exit;
5943 }
5944
5945 status = sme_set_ese_beacon_request(hdd_ctx->hHal,
5946 adapter->sessionId,
5947 &eseBcnReq);
5948
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305949 if (QDF_STATUS_E_RESOURCES == status) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305950 hddLog(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005951 FL("sme_set_ese_beacon_request failed (%d), a request already in progress"),
5952 status);
5953 ret = -EBUSY;
5954 goto exit;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305955 } else if (QDF_STATUS_SUCCESS != status) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305956 QDF_TRACE(QDF_MODULE_ID_HDD,
5957 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005958 "%s: sme_set_ese_beacon_request failed (%d)",
5959 __func__, status);
5960 ret = -EINVAL;
5961 goto exit;
5962 }
5963
5964exit:
5965 return ret;
5966}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08005967#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005968
5969static int drv_cmd_set_mc_rate(hdd_adapter_t *adapter,
5970 hdd_context_t *hdd_ctx,
5971 uint8_t *command,
5972 uint8_t command_len,
5973 hdd_priv_data_t *priv_data)
5974{
5975 int ret = 0;
5976 uint8_t *value = command;
5977 int targetRate;
5978
5979 /* input value is in units of hundred kbps */
5980
5981 /* Move pointer to ahead of SETMCRATE<delimiter> */
5982 value = value + command_len + 1;
5983
5984 /* Convert the value from ascii to integer, decimal base */
5985 ret = kstrtouint(value, 10, &targetRate);
5986
5987 ret = wlan_hdd_set_mc_rate(adapter, targetRate);
5988 return ret;
5989}
5990
5991static int drv_cmd_max_tx_power(hdd_adapter_t *adapter,
5992 hdd_context_t *hdd_ctx,
5993 uint8_t *command,
5994 uint8_t command_len,
5995 hdd_priv_data_t *priv_data)
5996{
5997 int ret = 0;
5998 int status;
5999 int txPower;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306000 QDF_STATUS qdf_status;
6001 QDF_STATUS smeStatus;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006002 uint8_t *value = command;
Anurag Chouhan6d760662016-02-20 16:05:43 +05306003 struct qdf_mac_addr bssid = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
6004 struct qdf_mac_addr selfMac = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006005 hdd_adapter_list_node_t *pAdapterNode = NULL;
6006 hdd_adapter_list_node_t *pNext = NULL;
6007
6008 status = hdd_parse_setmaxtxpower_command(value, &txPower);
6009 if (status) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306010 QDF_TRACE(QDF_MODULE_ID_HDD,
6011 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006012 "Invalid MAXTXPOWER command ");
6013 ret = -EINVAL;
6014 goto exit;
6015 }
6016
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306017 qdf_status = hdd_get_front_adapter(hdd_ctx, &pAdapterNode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006018 while (NULL != pAdapterNode
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306019 && QDF_STATUS_SUCCESS == qdf_status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006020 adapter = pAdapterNode->pAdapter;
6021 /* Assign correct self MAC address */
Anurag Chouhanc5548422016-02-24 18:33:27 +05306022 qdf_copy_macaddr(&bssid,
Srinivas Girigowda97215232015-09-24 12:26:28 -07006023 &adapter->macAddressCurrent);
Anurag Chouhanc5548422016-02-24 18:33:27 +05306024 qdf_copy_macaddr(&selfMac,
Srinivas Girigowda97215232015-09-24 12:26:28 -07006025 &adapter->macAddressCurrent);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006026
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306027 hddLog(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006028 "Device mode %d max tx power %d selfMac: " MAC_ADDRESS_STR " bssId: " MAC_ADDRESS_STR " ",
6029 adapter->device_mode, txPower,
Srinivas Girigowda97215232015-09-24 12:26:28 -07006030 MAC_ADDR_ARRAY(selfMac.bytes),
6031 MAC_ADDR_ARRAY(bssid.bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006032
Srinivas Girigowda97215232015-09-24 12:26:28 -07006033 smeStatus = sme_set_max_tx_power(hdd_ctx->hHal,
6034 bssid, selfMac, txPower);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306035 if (QDF_STATUS_SUCCESS != status) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306036 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006037 "%s:Set max tx power failed",
6038 __func__);
6039 ret = -EINVAL;
6040 goto exit;
6041 }
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306042 hddLog(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006043 "%s: Set max tx power success",
6044 __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306045 qdf_status = hdd_get_next_adapter(hdd_ctx, pAdapterNode,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006046 &pNext);
6047 pAdapterNode = pNext;
6048 }
6049
6050exit:
6051 return ret;
6052}
6053
6054static int drv_cmd_set_dfs_scan_mode(hdd_adapter_t *adapter,
6055 hdd_context_t *hdd_ctx,
6056 uint8_t *command,
6057 uint8_t command_len,
6058 hdd_priv_data_t *priv_data)
6059{
6060 int ret = 0;
6061 uint8_t *value = command;
6062 uint8_t dfsScanMode = CFG_ROAMING_DFS_CHANNEL_DEFAULT;
6063
6064 /* Move pointer to ahead of SETDFSSCANMODE<delimiter> */
6065 value = value + command_len + 1;
6066
6067 /* Convert the value from ascii to integer */
6068 ret = kstrtou8(value, 10, &dfsScanMode);
6069 if (ret < 0) {
6070 /*
6071 * If the input value is greater than max value of datatype,
6072 * then also kstrtou8 fails
6073 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306074 QDF_TRACE(QDF_MODULE_ID_HDD,
6075 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006076 "%s: kstrtou8 failed range [%d - %d]",
6077 __func__, CFG_ROAMING_DFS_CHANNEL_MIN,
6078 CFG_ROAMING_DFS_CHANNEL_MAX);
6079 ret = -EINVAL;
6080 goto exit;
6081 }
6082
6083 if ((dfsScanMode < CFG_ROAMING_DFS_CHANNEL_MIN) ||
6084 (dfsScanMode > CFG_ROAMING_DFS_CHANNEL_MAX)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306085 QDF_TRACE(QDF_MODULE_ID_HDD,
6086 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006087 "dfsScanMode value %d is out of range (Min: %d Max: %d)",
6088 dfsScanMode,
6089 CFG_ROAMING_DFS_CHANNEL_MIN,
6090 CFG_ROAMING_DFS_CHANNEL_MAX);
6091 ret = -EINVAL;
6092 goto exit;
6093 }
6094
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306095 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006096 "%s: Received Command to Set DFS Scan Mode = %d",
6097 __func__, dfsScanMode);
6098
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08006099 /* When DFS scanning is disabled, the DFS channels need to be
6100 * removed from the operation of device.
6101 */
6102 ret = wlan_hdd_disable_dfs_chan_scan(hdd_ctx, adapter,
6103 (dfsScanMode == CFG_ROAMING_DFS_CHANNEL_DISABLED));
6104 if (ret < 0) {
6105 /* Some conditions prevented it from disabling DFS channels */
6106 hddLog(LOGE,
6107 FL("disable/enable DFS channel request was denied"));
6108 goto exit;
6109 }
6110
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006111 hdd_ctx->config->allowDFSChannelRoam = dfsScanMode;
6112 sme_update_dfs_scan_mode(hdd_ctx->hHal, adapter->sessionId,
6113 dfsScanMode);
6114
6115exit:
6116 return ret;
6117}
6118
6119static int drv_cmd_get_dfs_scan_mode(hdd_adapter_t *adapter,
6120 hdd_context_t *hdd_ctx,
6121 uint8_t *command,
6122 uint8_t command_len,
6123 hdd_priv_data_t *priv_data)
6124{
6125 int ret = 0;
6126 uint8_t dfsScanMode = sme_get_dfs_scan_mode(hdd_ctx->hHal);
6127 char extra[32];
6128 uint8_t len = 0;
6129
6130 len = scnprintf(extra, sizeof(extra), "%s %d", command, dfsScanMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05306131 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006132 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306133 QDF_TRACE(QDF_MODULE_ID_HDD,
6134 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006135 "%s: failed to copy data to user buffer",
6136 __func__);
6137 ret = -EFAULT;
6138 }
6139
6140 return ret;
6141}
6142
6143static int drv_cmd_get_link_status(hdd_adapter_t *adapter,
6144 hdd_context_t *hdd_ctx,
6145 uint8_t *command,
6146 uint8_t command_len,
6147 hdd_priv_data_t *priv_data)
6148{
6149 int ret = 0;
6150 int value = wlan_hdd_get_link_status(adapter);
6151 char extra[32];
6152 uint8_t len;
6153
6154 len = scnprintf(extra, sizeof(extra), "%s %d", command, value);
Anurag Chouhan6d760662016-02-20 16:05:43 +05306155 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006156 if (copy_to_user(priv_data->buf, &extra, len)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306157 QDF_TRACE(QDF_MODULE_ID_HDD,
6158 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006159 "%s: failed to copy data to user buffer",
6160 __func__);
6161 ret = -EFAULT;
6162 }
6163
6164 return ret;
6165}
6166
6167#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
6168static int drv_cmd_enable_ext_wow(hdd_adapter_t *adapter,
6169 hdd_context_t *hdd_ctx,
6170 uint8_t *command,
6171 uint8_t command_len,
6172 hdd_priv_data_t *priv_data)
6173{
6174 uint8_t *value = command;
6175 int set_value;
6176
6177 /* Move pointer to ahead of ENABLEEXTWOW */
6178 value = value + command_len;
6179
6180 sscanf(value, "%d", &set_value);
6181
6182 return hdd_enable_ext_wow_parser(adapter,
6183 adapter->sessionId,
6184 set_value);
6185}
6186
6187static int drv_cmd_set_app1_params(hdd_adapter_t *adapter,
6188 hdd_context_t *hdd_ctx,
6189 uint8_t *command,
6190 uint8_t command_len,
6191 hdd_priv_data_t *priv_data)
6192{
6193 int ret;
6194 uint8_t *value = command;
6195
6196 /* Move pointer to ahead of SETAPP1PARAMS */
6197 value = value + command_len;
6198
6199 ret = hdd_set_app_type1_parser(adapter,
6200 value, strlen(value));
6201 if (ret >= 0)
6202 hdd_ctx->is_extwow_app_type1_param_set = true;
6203
6204 return ret;
6205}
6206
6207static int drv_cmd_set_app2_params(hdd_adapter_t *adapter,
6208 hdd_context_t *hdd_ctx,
6209 uint8_t *command,
6210 uint8_t command_len,
6211 hdd_priv_data_t *priv_data)
6212{
6213 int ret;
6214 uint8_t *value = command;
6215
6216 /* Move pointer to ahead of SETAPP2PARAMS */
6217 value = value + command_len;
6218
6219 ret = hdd_set_app_type2_parser(adapter, value, strlen(value));
6220 if (ret >= 0)
6221 hdd_ctx->is_extwow_app_type2_param_set = true;
6222
6223 return ret;
6224}
6225#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
6226
6227#ifdef FEATURE_WLAN_TDLS
6228/**
6229 * drv_cmd_tdls_secondary_channel_offset() - secondary tdls off channel offset
6230 * @adapter: Pointer to the HDD adapter
6231 * @hdd_ctx: Pointer to the HDD context
6232 * @command: Driver command string
6233 * @command_len: Driver command string length
6234 * @priv_data: Private data coming with the driver command. Unused here
6235 *
6236 * This function handles driver command that sets the secondary tdls off channel
6237 * offset
6238 *
6239 * Return: 0 on success; negative errno otherwise
6240 */
6241static int drv_cmd_tdls_secondary_channel_offset(hdd_adapter_t *adapter,
6242 hdd_context_t *hdd_ctx,
6243 uint8_t *command,
6244 uint8_t command_len,
6245 hdd_priv_data_t *priv_data)
6246{
6247 int ret;
6248 uint8_t *value = command;
6249 int set_value;
6250
6251 /* Move pointer to point the string */
6252 value += command_len;
6253
6254 ret = sscanf(value, "%d", &set_value);
6255 if (ret != 1)
6256 return -EINVAL;
6257
6258 hddLog(LOG1, FL("Tdls offchannel offset:%d"), set_value);
6259
6260 ret = hdd_set_tdls_secoffchanneloffset(hdd_ctx, set_value);
6261
6262 return ret;
6263}
6264
6265/**
6266 * drv_cmd_tdls_off_channel_mode() - set tdls off channel mode
6267 * @adapter: Pointer to the HDD adapter
6268 * @hdd_ctx: Pointer to the HDD context
6269 * @command: Driver command string
6270 * @command_len: Driver command string length
6271 * @priv_data: Private data coming with the driver command. Unused here
6272 *
6273 * This function handles driver command that sets tdls off channel mode
6274 *
6275 * Return: 0 on success; negative errno otherwise
6276 */
6277static int drv_cmd_tdls_off_channel_mode(hdd_adapter_t *adapter,
6278 hdd_context_t *hdd_ctx,
6279 uint8_t *command,
6280 uint8_t command_len,
6281 hdd_priv_data_t *priv_data)
6282{
6283 int ret;
6284 uint8_t *value = command;
6285 int set_value;
6286
6287 /* Move pointer to point the string */
6288 value += command_len;
6289
6290 ret = sscanf(value, "%d", &set_value);
6291 if (ret != 1)
6292 return -EINVAL;
6293
6294 hddLog(LOG1, FL("Tdls offchannel mode:%d"), set_value);
6295
6296 ret = hdd_set_tdls_offchannelmode(adapter, set_value);
6297
6298 return ret;
6299}
6300
6301/**
6302 * drv_cmd_tdls_off_channel() - set tdls off channel number
6303 * @adapter: Pointer to the HDD adapter
6304 * @hdd_ctx: Pointer to the HDD context
6305 * @command: Driver command string
6306 * @command_len: Driver command string length
6307 * @priv_data: Private data coming with the driver command. Unused here
6308 *
6309 * This function handles driver command that sets tdls off channel number
6310 *
6311 * Return: 0 on success; negative errno otherwise
6312 */
6313static int drv_cmd_tdls_off_channel(hdd_adapter_t *adapter,
6314 hdd_context_t *hdd_ctx,
6315 uint8_t *command,
6316 uint8_t command_len,
6317 hdd_priv_data_t *priv_data)
6318{
6319 int ret;
6320 uint8_t *value = command;
6321 int set_value;
6322
6323 /* Move pointer to point the string */
6324 value += command_len;
6325
6326 ret = sscanf(value, "%d", &set_value);
6327 if (ret != 1)
6328 return -EINVAL;
6329
Krishna Kumaar Natarajan4d090352015-10-26 18:30:53 -07006330 if (CDS_IS_DFS_CH(set_value)) {
6331 hdd_err("DFS channel %d is passed for hdd_set_tdls_offchannel",
6332 set_value);
6333 return -EINVAL;
6334 }
6335
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006336 hddLog(LOG1, FL("Tdls offchannel num: %d"), set_value);
6337
6338 ret = hdd_set_tdls_offchannel(hdd_ctx, set_value);
6339
6340 return ret;
6341}
6342
6343/**
6344 * drv_cmd_tdls_scan() - set tdls scan type
6345 * @adapter: Pointer to the HDD adapter
6346 * @hdd_ctx: Pointer to the HDD context
6347 * @command: Driver command string
6348 * @command_len: Driver command string length
6349 * @priv_data: Private data coming with the driver command. Unused here
6350 *
6351 * This function handles driver command that sets tdls scan type
6352 *
6353 * Return: 0 on success; negative errno otherwise
6354 */
6355static int drv_cmd_tdls_scan(hdd_adapter_t *adapter,
6356 hdd_context_t *hdd_ctx,
6357 uint8_t *command,
6358 uint8_t command_len,
6359 hdd_priv_data_t *priv_data)
6360{
6361 int ret;
6362 uint8_t *value = command;
6363 int set_value;
6364
6365 /* Move pointer to point the string */
6366 value += command_len;
6367
6368 ret = sscanf(value, "%d", &set_value);
6369 if (ret != 1)
6370 return -EINVAL;
6371
6372 hddLog(LOG1, FL("Tdls scan type val: %d"), set_value);
6373
6374 ret = hdd_set_tdls_scan_type(hdd_ctx, set_value);
6375
6376 return ret;
6377}
6378#endif
6379
6380static int drv_cmd_get_rssi(hdd_adapter_t *adapter,
6381 hdd_context_t *hdd_ctx,
6382 uint8_t *command,
6383 uint8_t command_len,
6384 hdd_priv_data_t *priv_data)
6385{
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006386 int ret = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006387 int8_t rssi = 0;
6388 char extra[32];
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006389
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006390 uint8_t len = 0;
6391
6392 wlan_hdd_get_rssi(adapter, &rssi);
6393
6394 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
Anurag Chouhan6d760662016-02-20 16:05:43 +05306395 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006396
6397 if (copy_to_user(priv_data->buf, &extra, len)) {
6398 hddLog(LOGE, FL("Failed to copy data to user buffer"));
6399 ret = -EFAULT;
6400 }
6401
6402 return ret;
6403}
6404
6405static int drv_cmd_get_linkspeed(hdd_adapter_t *adapter,
6406 hdd_context_t *hdd_ctx,
6407 uint8_t *command,
6408 uint8_t command_len,
6409 hdd_priv_data_t *priv_data)
6410{
6411 int ret;
6412 uint32_t link_speed = 0;
6413 char extra[32];
6414 uint8_t len = 0;
6415
6416 ret = wlan_hdd_get_link_speed(adapter, &link_speed);
6417 if (0 != ret)
6418 return ret;
6419
6420 len = scnprintf(extra, sizeof(extra), "%s %d", command, link_speed);
Anurag Chouhan6d760662016-02-20 16:05:43 +05306421 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006422 if (copy_to_user(priv_data->buf, &extra, len)) {
6423 hddLog(LOGE, FL("Failed to copy data to user buffer"));
6424 ret = -EFAULT;
6425 }
6426
6427 return ret;
6428}
6429
6430#ifdef FEATURE_NAPI
6431/**
6432 * hdd_parse_napi() - helper functions to drv_cmd_napi
6433 * @str : source string to parse
6434 * @cmd : pointer to cmd part after parsing
6435 * @sub : pointer to subcmd part after parsing
6436 * @aux : pointer to optional aux part after parsing
6437 *
6438 * Example:
6439 * NAPI SCALE <n> +-- IN str
6440 * | | +------ OUT aux
6441 * | +------------ OUT subcmd
6442 * +----------------- OUT cmd
6443 *
6444 * Return: ==0: success; !=0: failure
6445 */
6446static int hdd_parse_napi(char **str, char **cmd, char **sub, char **aux)
6447{
6448 int rc;
6449 char *token, *lcmd = NULL, *lsub = NULL, *laux = NULL;
6450
6451 NAPI_DEBUG("-->\n");
6452
6453 token = strsep(str, " \t");
6454 if (NULL == token) {
6455 hdd_err("cannot parse cmd");
6456 goto parse_end;
6457 }
6458 lcmd = token;
6459
6460 token = strsep(str, " \t");
6461 if (NULL == token) {
6462 hdd_err("cannot parse subcmd");
6463 goto parse_end;
6464 }
6465 lsub = token;
6466
6467 token = strsep(str, " \t");
6468 if (NULL == token)
6469 hdd_warn("cannot parse aux\n");
6470 else
6471 laux = token;
6472
6473parse_end:
6474 if ((NULL == lcmd) || (NULL == lsub))
6475 rc = -EINVAL;
6476 else {
6477 rc = 0;
6478 *cmd = lcmd;
6479 *sub = lsub;
6480 if (NULL != aux)
6481 *aux = laux;
6482 }
6483 NAPI_DEBUG("<--[rc=%d]\n", rc);
6484 return rc;
6485}
6486
6487
6488/**
6489 * hdd_parse_stats() - print NAPI stats into a buffer
6490 * @buf : buffer to write stats into
6491 * @max : "size of buffer"
6492 * @idp : NULL: all stats, otherwise, ptr to the NAPI instance
6493 * @napid: binary structure to retrieve the stats from
6494 *
6495 * Return: number of bytes written into the buffer
6496 */
6497int hdd_napi_stats(char *buf,
6498 int max,
6499 char *indp,
6500 struct qca_napi_data *napid)
6501{
6502 int n = 0;
6503 int i, j, k; /* NAPI, CPU, bucket indices */
6504 int from, to;
6505 struct qca_napi_info *napii;
6506 struct qca_napi_stat *napis;
6507
6508 NAPI_DEBUG("-->\n");
6509
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006510 if (NULL == napid)
6511 return n;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006512 if (NULL == indp) {
6513 from = 0;
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006514 to = CE_COUNT_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006515 } else {
6516 if (0 > kstrtoint(indp, 10, &to)) {
6517 from = 0;
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006518 to = CE_COUNT_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006519 } else
6520 from = to;
6521 }
6522
6523 for (i = from; i < to; i++)
6524 if (napid->ce_map & (0x01 << i)) {
6525 napii = &(napid->napis[i]);
6526 for (j = 0; j < NR_CPUS; j++) {
6527 napis = &(napii->stats[j]);
6528 n += scnprintf(buf + n, max - n,
6529 "STATS: NAPI[%d] CPU: %d scheds: %d polls: %d completes: %d done: %d ",
6530 i, j,
6531 napis->napi_schedules,
6532 napis->napi_polls,
6533 napis->napi_completes,
6534 napis->napi_workdone);
6535
6536 for (k = 0; k < QCA_NAPI_NUM_BUCKETS; k++) {
6537 n += scnprintf(
6538 buf + n, max - n,
6539 " %d",
6540 napis->napi_budget_uses[k]);
6541 }
6542 n += scnprintf(buf+n, max - n, "\n");
6543 }
6544 }
6545
6546 NAPI_DEBUG("<--[n=%d]\n", n);
6547 return n;
6548}
6549
6550/**
6551 * napi_set_scale() - sets the scale attribute in all NAPI entries
6552 * @sc : scale to set
6553 *
6554 * Return: void
6555 */
6556static void napi_set_scale(uint8_t sc)
6557{
6558 uint32_t i;
6559 struct qca_napi_data *napi_data;
6560
6561 napi_data = hdd_napi_get_all();
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006562 if (likely(NULL != napi_data))
6563 for (i = 0; i < CE_COUNT_MAX; i++)
6564 if (napi_data->ce_map & (0x01 << i))
6565 napi_data->napis[i].scale = sc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006566
6567 return;
6568}
6569/**
6570 * drv_cmd_napi() - processes NAPI commands
6571 * @adapter : net_device
6572 * @hdd_ctx : HDD context
6573 * @command : command string from user command (including "NAPI")
6574 * @command_len: length of command
6575 * @priv_data : ifr_data
6576 *
6577 * Commands supported:
6578 * NAPI ENABLE : enables NAPI administratively. Note that this may not
6579 * enable NAPI functionally, as some other conditions
6580 * may not have been satisfied yet
6581 * NAPI DISABLE : reverse operation of "enable"
6582 * NAPI STATUS : get global status of NAPI instances
6583 * NAPI STATS [<n>] : get the stats for a given NAPI instance
6584 * NAPI SCALE <n> : set the scale factor
6585 *
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006586 * Return: 0: success; !0: failure
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006587 */
6588static int drv_cmd_napi(hdd_adapter_t *adapter,
6589 hdd_context_t *hdd_ctx,
6590 uint8_t *command,
6591 uint8_t command_len,
6592 hdd_priv_data_t *priv_data)
6593{
6594 int rc = 0;
6595 int n, l;
6596 char *cmd = NULL, *subcmd = NULL, *aux = NULL;
6597 char *synopsis = "NAPI ENABLE\n"
6598 "NAPI DISABLE\n"
6599 "NAPI STATUS\n"
6600 "NAPI STATS [<n>] -- if no <n> then all\n"
6601 "NAPI SCALE <n> -- set the scale\n";
6602 char *reply = NULL;
6603
6604 /* make a local copy, as strsep modifies the str in place */
6605 char *str = NULL;
6606
6607 NAPI_DEBUG("-->\n");
6608
6609 /**
6610 * NOTE TO MAINTAINER: from this point to the end of the function,
6611 * please do not return anywhere in the code except the very end
6612 * to avoid memory leakage (goto end_drv_napi instead)
6613 * or make sure that reply+str is freed
6614 */
6615 reply = kmalloc(MAX_USER_COMMAND_SIZE, GFP_KERNEL);
6616 if (NULL == reply) {
6617 hdd_err("could not allocate reply buffer");
6618 rc = -ENOMEM;
6619 goto end_drv_napi;
6620 }
6621
6622 str = kmalloc(strlen(command) + 1, GFP_KERNEL);
6623 if (NULL == str) {
6624 hdd_err("could not allocate copy of input buffer");
6625 rc = -ENOMEM;
6626 goto end_drv_napi;
6627 }
6628
6629 strlcpy(str, command, strlen(command) + 1);
6630 hdd_debug("parsing command into cmd=0x%p sub=0x%p aux=0x%p\n",
6631 cmd, subcmd, aux);
6632
6633
6634 rc = hdd_parse_napi(&str, &cmd, &subcmd, &aux);
6635
6636 if (0 != rc) {
6637 const char *msg = "unknown or badly formatted cmd\n%s";
Anurag Chouhan6d760662016-02-20 16:05:43 +05306638 l = QDF_MIN(MAX_USER_COMMAND_SIZE,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006639 strlen(msg)+strlen(synopsis));
6640 n = scnprintf(reply, l, msg, synopsis);
6641
6642 if (copy_to_user(priv_data->buf, reply,
Anurag Chouhan6d760662016-02-20 16:05:43 +05306643 QDF_MIN(priv_data->total_len, l)))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006644 hdd_err("failed to copy data to user buffer");
6645 hdd_debug("reply: %s", reply);
6646
6647 rc = -EINVAL;
6648 } else {
6649 hdd_debug("cmd=(%s) subcmd=(%s) aux=(%s)\n",
6650 cmd, subcmd, aux);
6651 if (!strcmp(subcmd, "ENABLE"))
6652 hdd_napi_event(NAPI_EVT_CMD_STATE, (void *)1);
6653 else if (!strcmp(subcmd, "DISABLE"))
6654 hdd_napi_event(NAPI_EVT_CMD_STATE, (void *)0);
6655 else if (!strcmp(subcmd, "STATUS")) {
6656 int n = 0;
6657 uint32_t i;
6658 struct qca_napi_data *napi_data;
6659
6660 napi_data = hdd_napi_get_all();
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006661 if (unlikely(NULL == napi_data))
6662 goto status_end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006663 n += scnprintf(reply+n, MAX_USER_COMMAND_SIZE - n,
6664 "NAPI state: 0x%08x map: 0x%08x\n",
6665 napi_data->state,
6666 napi_data->ce_map);
6667
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006668 for (i = 0; i < CE_COUNT_MAX; i++)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006669 if (napi_data->ce_map & (0x01 << i)) {
6670 n += scnprintf(
6671 reply + n,
6672 MAX_USER_COMMAND_SIZE - n,
6673 "#%d: id: %d, scale=%d\n",
6674 i,
6675 napi_data->napis[i].id,
6676 napi_data->napis[i].scale);
6677 }
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006678 status_end:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006679 hdd_info("wlan: STATUS DATA:\n%s", reply);
6680 if (copy_to_user(priv_data->buf, reply,
Anurag Chouhan6d760662016-02-20 16:05:43 +05306681 QDF_MIN(n, priv_data->total_len)))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006682 rc = -EINVAL;
6683 } else if (!strcmp(subcmd, "STATS")) {
6684 int n = 0;
6685 struct qca_napi_data *napi_data;
6686
6687 napi_data = hdd_napi_get_all();
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006688 if (NULL != napi_data) {
6689 n = hdd_napi_stats(reply, MAX_USER_COMMAND_SIZE,
6690 aux, napi_data);
6691 NAPI_DEBUG("STATS: returns %d\n", n);
6692 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006693 if (n > 0) {
6694 if (copy_to_user(priv_data->buf, reply,
Anurag Chouhan6d760662016-02-20 16:05:43 +05306695 QDF_MIN(priv_data->total_len,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006696 n)))
6697 rc = -EINVAL;
6698 hdd_info("wlan: STATS_DATA\n%s\n", reply);
6699 } else
6700 rc = -EINVAL;
6701 } else if (!strcmp(subcmd, "SCALE")) {
6702 if (NULL == aux) {
6703 rc = -EINVAL;
6704 hdd_err("wlan: SCALE cmd requires <n>");
6705 } else {
6706 uint8_t sc;
6707 rc = kstrtou8(aux, 10, &sc);
6708 if (rc) {
6709 hdd_err("wlan: bad scale (%s)", aux);
6710 rc = -EINVAL;
6711 } else
6712 napi_set_scale(sc);
6713 }
6714 } /* SCALE */
6715 }
6716end_drv_napi:
6717 if (NULL != str)
6718 kfree(str);
6719 if (NULL != reply)
6720 kfree(reply);
6721
6722 NAPI_DEBUG("<--[rc=%d]\n", rc);
6723 return rc;
6724}
6725#endif /* FEATURE_NAPI */
6726
6727/**
6728 * hdd_set_rx_filter() - set RX filter
6729 * @adapter: Pointer to adapter
6730 * @action: Filter action
6731 * @pattern: Address pattern
6732 *
6733 * Address pattern is most significant byte of address for example
6734 * 0x01 for IPV4 multicast address
6735 * 0x33 for IPV6 multicast address
6736 * 0xFF for broadcast address
6737 *
6738 * Return: 0 for success, non-zero for failure
6739 */
6740static int hdd_set_rx_filter(hdd_adapter_t *adapter, bool action,
6741 uint8_t pattern)
6742{
6743 int ret;
6744 uint8_t i;
6745 tHalHandle handle;
6746 tSirRcvFltMcAddrList *filter;
6747 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
6748
6749 ret = wlan_hdd_validate_context(hdd_ctx);
6750 if (0 != ret)
6751 return ret;
6752
6753 handle = hdd_ctx->hHal;
6754
6755 if (NULL == handle) {
6756 hdd_err("HAL Handle is NULL");
6757 return -EINVAL;
6758 }
6759
6760 /*
6761 * If action is false it means start dropping packets
6762 * Set addr_filter_pattern which will be used when sending
6763 * MC/BC address list to target
6764 */
6765 if (!action)
6766 adapter->addr_filter_pattern = pattern;
6767 else
6768 adapter->addr_filter_pattern = 0;
6769
Krunal Sonibe766b02016-03-10 13:00:44 -08006770 if (((adapter->device_mode == QDF_STA_MODE) ||
6771 (adapter->device_mode == QDF_P2P_CLIENT_MODE)) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006772 adapter->mc_addr_list.mc_cnt &&
6773 hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
6774
6775
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306776 filter = qdf_mem_malloc(sizeof(*filter));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006777 if (NULL == filter) {
6778 hdd_err("Could not allocate Memory");
6779 return -ENOMEM;
6780 }
6781 filter->action = action;
6782 for (i = 0; i < adapter->mc_addr_list.mc_cnt; i++) {
6783 if (!memcmp(adapter->mc_addr_list.addr[i],
6784 &pattern, 1)) {
Srinivas Girigowda98530492015-11-20 17:39:24 -08006785 memcpy(filter->multicastAddr[i].bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006786 adapter->mc_addr_list.addr[i],
6787 sizeof(adapter->mc_addr_list.addr[i]));
6788 filter->ulMulticastAddrCnt++;
Srinivas Girigowdaf2599dd2015-11-16 18:20:46 -08006789 hdd_info("%s RX filter : addr ="
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006790 MAC_ADDRESS_STR,
6791 action ? "setting" : "clearing",
Srinivas Girigowda98530492015-11-20 17:39:24 -08006792 MAC_ADDR_ARRAY(filter->multicastAddr[i].bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006793 }
6794 }
6795 /* Set rx filter */
6796 sme_8023_multicast_list(handle, adapter->sessionId, filter);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306797 qdf_mem_free(filter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006798 } else {
Srinivas Girigowdaf2599dd2015-11-16 18:20:46 -08006799 hdd_info("mode %d mc_cnt %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006800 adapter->device_mode, adapter->mc_addr_list.mc_cnt);
6801 }
6802
6803 return 0;
6804}
6805
6806/**
6807 * hdd_driver_rxfilter_comand_handler() - RXFILTER driver command handler
6808 * @command: Pointer to input string driver command
6809 * @adapter: Pointer to adapter
6810 * @action: Action to enable/disable filtering
6811 *
6812 * If action == false
6813 * Start filtering out data packets based on type
6814 * RXFILTER-REMOVE 0 -> Start filtering out unicast data packets
6815 * RXFILTER-REMOVE 1 -> Start filtering out broadcast data packets
6816 * RXFILTER-REMOVE 2 -> Start filtering out IPV4 mcast data packets
6817 * RXFILTER-REMOVE 3 -> Start filtering out IPV6 mcast data packets
6818 *
6819 * if action == true
6820 * Stop filtering data packets based on type
6821 * RXFILTER-ADD 0 -> Stop filtering unicast data packets
6822 * RXFILTER-ADD 1 -> Stop filtering broadcast data packets
6823 * RXFILTER-ADD 2 -> Stop filtering IPV4 mcast data packets
6824 * RXFILTER-ADD 3 -> Stop filtering IPV6 mcast data packets
6825 *
6826 * Current implementation only supports IPV4 address filtering by
6827 * selectively allowing IPV4 multicast data packest based on
6828 * address list received in .ndo_set_rx_mode
6829 *
6830 * Return: 0 for success, non-zero for failure
6831 */
6832static int hdd_driver_rxfilter_comand_handler(uint8_t *command,
6833 hdd_adapter_t *adapter,
6834 bool action)
6835{
6836 int ret = 0;
6837 uint8_t *value;
6838 uint8_t type;
6839
6840 value = command;
6841 /* Skip space after RXFILTER-REMOVE OR RXFILTER-ADD based on action */
6842 if (!action)
6843 value = command + 16;
6844 else
6845 value = command + 13;
6846 ret = kstrtou8(value, 10, &type);
6847 if (ret < 0) {
6848 hdd_err("kstrtou8 failed invalid input value %d", type);
6849 return -EINVAL;
6850 }
6851
6852 switch (type) {
6853 case 2:
6854 /* Set rx filter for IPV4 multicast data packets */
6855 ret = hdd_set_rx_filter(adapter, action, 0x01);
6856 break;
6857 default:
6858 hdd_info("Unsupported RXFILTER type %d", type);
6859 break;
6860 }
6861
6862 return ret;
6863}
6864
6865/**
6866 * drv_cmd_rx_filter_remove() - RXFILTER REMOVE driver command handler
6867 * @adapter: Pointer to network adapter
6868 * @hdd_ctx: Pointer to hdd context
6869 * @command: Pointer to input command
6870 * @command_len: Command length
6871 * @priv_data: Pointer to private data in command
6872 */
6873static int drv_cmd_rx_filter_remove(hdd_adapter_t *adapter,
6874 hdd_context_t *hdd_ctx,
6875 uint8_t *command,
6876 uint8_t command_len,
6877 hdd_priv_data_t *priv_data)
6878{
6879 return hdd_driver_rxfilter_comand_handler(command, adapter, false);
6880}
6881
6882/**
6883 * drv_cmd_rx_filter_add() - RXFILTER ADD driver command handler
6884 * @adapter: Pointer to network adapter
6885 * @hdd_ctx: Pointer to hdd context
6886 * @command: Pointer to input command
6887 * @command_len: Command length
6888 * @priv_data: Pointer to private data in command
6889 */
6890static int drv_cmd_rx_filter_add(hdd_adapter_t *adapter,
6891 hdd_context_t *hdd_ctx,
6892 uint8_t *command,
6893 uint8_t command_len,
6894 hdd_priv_data_t *priv_data)
6895{
6896 return hdd_driver_rxfilter_comand_handler(command, adapter, true);
6897}
6898
Archana Ramachandran393f3792015-11-13 17:13:21 -08006899/**
6900 * hdd_parse_setantennamode_command() - HDD Parse SETANTENNAMODE
6901 * command
6902 * @value: Pointer to SETANTENNAMODE command
6903 * @mode: Pointer to antenna mode
6904 * @reason: Pointer to reason for set antenna mode
6905 *
6906 * This function parses the SETANTENNAMODE command passed in the format
6907 * SETANTENNAMODE<space>mode
6908 *
6909 * Return: 0 for success non-zero for failure
6910 */
6911static int hdd_parse_setantennamode_command(const uint8_t *value)
6912{
6913 const uint8_t *in_ptr = value;
6914 int tmp, v;
6915 char arg1[32];
6916
6917 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
6918
6919 /* no argument after the command */
6920 if (NULL == in_ptr) {
6921 hddLog(LOGE, FL("No argument after the command"));
6922 return -EINVAL;
6923 }
6924
6925 /* no space after the command */
6926 if (SPACE_ASCII_VALUE != *in_ptr) {
6927 hddLog(LOGE, FL("No space after the command"));
6928 return -EINVAL;
6929 }
6930
6931 /* remove empty spaces */
6932 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
6933 in_ptr++;
6934
6935 /* no argument followed by spaces */
6936 if ('\0' == *in_ptr) {
6937 hddLog(LOGE, FL("No argument followed by spaces"));
6938 return -EINVAL;
6939 }
6940
6941 /* get the argument i.e. antenna mode */
6942 v = sscanf(in_ptr, "%31s ", arg1);
6943 if (1 != v) {
6944 hddLog(LOGE, FL("argument retrieval from cmd string failed"));
6945 return -EINVAL;
6946 }
6947
6948 v = kstrtos32(arg1, 10, &tmp);
6949 if (v < 0) {
6950 hddLog(LOGE, FL("argument string to int conversion failed"));
6951 return -EINVAL;
6952 }
6953
6954 return tmp;
6955}
6956
6957/**
6958 * hdd_is_supported_chain_mask_2x2() - Verify if supported chain
6959 * mask is 2x2 mode
6960 * @hdd_ctx: Pointer to hdd contex
6961 *
6962 * Return: true if supported chain mask 2x2 else false
6963 */
6964static bool hdd_is_supported_chain_mask_2x2(hdd_context_t *hdd_ctx)
6965{
6966 /*
6967 * Revisit and the update logic to determine the number
6968 * of TX/RX chains supported in the system when
6969 * antenna sharing per band chain mask support is
6970 * brought in
6971 */
6972 return (hdd_ctx->config->enable2x2 == 0x01) ? true : false;
6973}
6974
6975/**
6976 * hdd_is_supported_chain_mask_1x1() - Verify if the supported
6977 * chain mask is 1x1
6978 * @hdd_ctx: Pointer to hdd contex
6979 *
6980 * Return: true if supported chain mask 1x1 else false
6981 */
6982static bool hdd_is_supported_chain_mask_1x1(hdd_context_t *hdd_ctx)
6983{
6984 /*
6985 * Revisit and update the logic to determine the number
6986 * of TX/RX chains supported in the system when
6987 * antenna sharing per band chain mask support is
6988 * brought in
6989 */
6990 return (!hdd_ctx->config->enable2x2) ? true : false;
6991}
6992
6993/**
6994 * drv_cmd_set_antenna_mode() - SET ANTENNA MODE driver command
6995 * handler
6996 * @adapter: Pointer to network adapter
6997 * @hdd_ctx: Pointer to hdd context
6998 * @command: Pointer to input command
6999 * @command_len: Command length
7000 * @priv_data: Pointer to private data in command
7001 */
7002static int drv_cmd_set_antenna_mode(hdd_adapter_t *adapter,
7003 hdd_context_t *hdd_ctx,
7004 uint8_t *command,
7005 uint8_t command_len,
7006 hdd_priv_data_t *priv_data)
7007{
7008 struct sir_antenna_mode_param params;
7009 QDF_STATUS status;
7010 int ret = 0;
7011 int mode;
7012 uint8_t *value = command;
7013 uint8_t smps_mode;
7014 uint8_t smps_enable;
7015
7016 if (((1 << QDF_STA_MODE) != hdd_ctx->concurrency_mode) ||
7017 (hdd_ctx->no_of_active_sessions[QDF_STA_MODE] > 1)) {
7018 hdd_err("Operation invalid in non sta or concurrent mode");
7019 ret = -EPERM;
7020 goto exit;
7021 }
7022
7023 mode = hdd_parse_setantennamode_command(value);
7024 if (mode < 0) {
7025 hdd_err("Invalid SETANTENNA command");
7026 ret = mode;
7027 goto exit;
7028 }
7029
7030 hdd_info("Processing antenna mode switch to: %d", mode);
7031
7032 if (hdd_ctx->current_antenna_mode == mode) {
7033 hdd_err("System already in the requested mode");
7034 ret = 0;
7035 goto exit;
7036 }
7037
7038 if ((HDD_ANTENNA_MODE_2X2 == mode) &&
7039 (!hdd_is_supported_chain_mask_2x2(hdd_ctx))) {
7040 hdd_err("System does not support 2x2 mode");
7041 ret = -EPERM;
7042 goto exit;
7043 }
7044
7045 if ((HDD_ANTENNA_MODE_1X1 == mode) &&
7046 hdd_is_supported_chain_mask_1x1(hdd_ctx)) {
7047 hdd_err("System only supports 1x1 mode");
7048 ret = 0;
7049 goto exit;
7050 }
7051
7052 switch (mode) {
7053 case HDD_ANTENNA_MODE_1X1:
7054 params.num_rx_chains = 1;
7055 params.num_tx_chains = 1;
7056 break;
7057 case HDD_ANTENNA_MODE_2X2:
7058 params.num_rx_chains = 2;
7059 params.num_tx_chains = 2;
7060 break;
7061 default:
7062 hdd_err("unsupported antenna mode");
7063 ret = -EINVAL;
7064 goto exit;
7065 }
7066
7067 params.set_antenna_mode_resp =
7068 (void *)wlan_hdd_soc_set_antenna_mode_cb;
7069 hdd_info("Set antenna mode rx chains: %d tx chains: %d",
7070 params.num_rx_chains,
7071 params.num_tx_chains);
7072
7073
7074 INIT_COMPLETION(hdd_ctx->set_antenna_mode_cmpl);
7075 status = sme_soc_set_antenna_mode(hdd_ctx->hHal, &params);
7076 if (QDF_STATUS_SUCCESS != status) {
7077 hdd_err("set antenna mode failed status : %d", status);
7078 ret = -EFAULT;
7079 goto exit;
7080 }
7081
7082 ret = wait_for_completion_timeout(
7083 &hdd_ctx->set_antenna_mode_cmpl,
7084 msecs_to_jiffies(WLAN_WAIT_TIME_ANTENNA_MODE_REQ));
7085 if (!ret) {
7086 ret = -EFAULT;
7087 hdd_err("send set antenna mode timed out");
7088 goto exit;
7089 }
7090
7091 /* Update SME SMPS config */
7092 if (HDD_ANTENNA_MODE_1X1 == mode) {
7093 smps_enable = true;
7094 smps_mode = HDD_SMPS_MODE_STATIC;
7095 } else {
7096 smps_enable = false;
7097 smps_mode = HDD_SMPS_MODE_DISABLED;
7098 }
7099
7100 hdd_info("Update SME SMPS enable: %d mode: %d",
7101 smps_enable, smps_mode);
7102 status = sme_update_mimo_power_save(
7103 hdd_ctx->hHal, smps_enable, smps_mode, false);
7104 if (QDF_STATUS_SUCCESS != status) {
7105 hdd_err("Update SMPS config failed enable: %d mode: %d status: %d",
7106 smps_enable, smps_mode, status);
7107 ret = -EFAULT;
7108 goto exit;
7109 }
7110
7111 hdd_info("Successfully switched to mode: %d x %d", mode, mode);
7112 ret = 0;
7113 hdd_ctx->current_antenna_mode = mode;
7114
7115exit:
7116 hdd_info("Set antenna status: %d current mode: %d",
7117 ret, hdd_ctx->current_antenna_mode);
7118 return ret;
7119
7120}
7121
7122/**
7123 * drv_cmd_get_antenna_mode() - GET ANTENNA MODE driver command
7124 * handler
7125 * @adapter: Pointer to hdd adapter
7126 * @hdd_ctx: Pointer to hdd context
7127 * @command: Pointer to input command
7128 * @command_len: length of the command
7129 * @priv_data: private data coming with the driver command
7130 *
7131 * Return: 0 for success non-zero for failure
7132 */
7133static inline int drv_cmd_get_antenna_mode(hdd_adapter_t *adapter,
7134 hdd_context_t *hdd_ctx,
7135 uint8_t *command,
7136 uint8_t command_len,
7137 hdd_priv_data_t *priv_data)
7138{
7139 uint32_t antenna_mode = 0;
7140 char extra[32];
7141 uint8_t len = 0;
7142
7143 antenna_mode = hdd_ctx->current_antenna_mode;
7144 len = scnprintf(extra, sizeof(extra), "%s %d", command,
7145 antenna_mode);
7146 len = QDF_MIN(priv_data->total_len, len + 1);
7147 if (copy_to_user(priv_data->buf, &extra, len)) {
7148 hdd_err("Failed to copy data to user buffer");
7149 return -EFAULT;
7150 }
7151
7152 hdd_info("Get antenna mode: %d", antenna_mode);
7153
7154 return 0;
7155}
7156
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007157/*
7158 * dummy (no-op) hdd driver command handler
7159 */
7160static int drv_cmd_dummy(hdd_adapter_t *adapter,
7161 hdd_context_t *hdd_ctx,
7162 uint8_t *command,
7163 uint8_t command_len,
7164 hdd_priv_data_t *priv_data)
7165{
7166 hdd_info("%s: Ignoring driver command \"%s\"",
7167 adapter->dev->name, command);
7168 return 0;
7169}
7170
7171/*
7172 * handler for any unsupported wlan hdd driver command
7173 */
7174static int drv_cmd_invalid(hdd_adapter_t *adapter,
7175 hdd_context_t *hdd_ctx,
7176 uint8_t *command,
7177 uint8_t command_len,
7178 hdd_priv_data_t *priv_data)
7179{
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05307180 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007181 TRACE_CODE_HDD_UNSUPPORTED_IOCTL,
7182 adapter->sessionId, 0));
7183
7184 hdd_warn("%s: Unsupported driver command \"%s\"",
7185 adapter->dev->name, command);
7186
7187 return -ENOTSUPP;
7188}
7189
7190/**
7191 * drv_cmd_set_fcc_channel() - handle fcc constraint request
7192 * @adapter: HDD adapter
7193 * @hdd_ctx: HDD context
7194 * @command: command ptr, SET_FCC_CHANNEL 0/1 is the command
7195 * @command_len: command len
7196 * @priv_data: private data
7197 *
7198 * Return: status
7199 */
7200static int drv_cmd_set_fcc_channel(hdd_adapter_t *adapter,
7201 hdd_context_t *hdd_ctx,
7202 uint8_t *command,
7203 uint8_t command_len,
7204 hdd_priv_data_t *priv_data)
7205{
7206 uint8_t *value;
7207 uint8_t fcc_constraint;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05307208 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007209 int ret = 0;
7210
7211 /*
7212 * this command would be called by user-space when it detects WLAN
7213 * ON after airplane mode is set. When APM is set, WLAN turns off.
7214 * But it can be turned back on. Otherwise; when APM is turned back
7215 * off, WLAN would turn back on. So at that point the command is
7216 * expected to come down. 0 means disable, 1 means enable. The
7217 * constraint is removed when parameter 1 is set or different
7218 * country code is set
7219 */
7220
7221 value = command + command_len + 1;
7222
7223 ret = kstrtou8(value, 10, &fcc_constraint);
7224 if ((ret < 0) || (fcc_constraint > 1)) {
7225 /*
7226 * If the input value is greater than max value of datatype,
7227 * then also it is a failure
7228 */
7229 hdd_err("value out of range");
7230 return -EINVAL;
7231 }
7232
7233 status = sme_disable_non_fcc_channel(hdd_ctx->hHal, !fcc_constraint);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05307234 if (status != QDF_STATUS_SUCCESS) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007235 hdd_err("sme disable fn. returned err");
7236 ret = -EPERM;
7237 }
7238
7239 return ret;
7240}
7241
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307242/**
7243 * hdd_parse_set_channel_switch_command() - Parse and validate CHANNEL_SWITCH
7244 * command
7245 * @value: Pointer to the command
7246 * @chan_number: Pointer to the channel number
7247 * @chan_bw: Pointer to the channel bandwidth
7248 *
7249 * Parses and provides the channel number and channel width from the input
7250 * command which is expected to be of the format: CHANNEL_SWITCH <CH> <BW>
7251 * <CH> is channel number to move (where 1 = channel 1, 149 = channel 149, ...)
7252 * <BW> is bandwidth to move (where 20 = BW 20, 40 = BW 40, 80 = BW 80)
7253 *
7254 * Return: 0 for success, non-zero for failure
7255 */
7256static int hdd_parse_set_channel_switch_command(uint8_t *value,
7257 uint32_t *chan_number,
7258 uint32_t *chan_bw)
7259{
7260 const uint8_t *in_ptr = value;
7261 int ret;
7262
7263 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
7264
7265 /* no argument after the command */
7266 if (NULL == in_ptr) {
7267 hdd_err("No argument after the command");
7268 return -EINVAL;
7269 }
7270
7271 /* no space after the command */
7272 if (SPACE_ASCII_VALUE != *in_ptr) {
7273 hdd_err("No space after the command ");
7274 return -EINVAL;
7275 }
7276
7277 /* remove empty spaces and move the next argument */
7278 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
7279 in_ptr++;
7280
7281 /* no argument followed by spaces */
7282 if ('\0' == *in_ptr) {
7283 hdd_err("No argument followed by spaces");
7284 return -EINVAL;
7285 }
7286
7287 /* get the two arguments: channel number and bandwidth */
7288 ret = sscanf(in_ptr, "%u %u", chan_number, chan_bw);
7289 if (ret != 2) {
7290 hdd_err("Arguments retrieval from cmd string failed");
7291 return -EINVAL;
7292 }
7293
7294 return 0;
7295}
7296
7297/**
7298 * drv_cmd_set_channel_switch() - Switch SAP/P2P-GO operating channel
7299 * @adapter: HDD adapter
7300 * @hdd_ctx: HDD context
7301 * @command: Pointer to the input command CHANNEL_SWITCH
7302 * @command_len: Command len
7303 * @priv_data: Private data
7304 *
7305 * Handles private IOCTL CHANNEL_SWITCH command to switch the operating channel
7306 * of SAP/P2P-GO
7307 *
7308 * Return: 0 for success, non-zero for failure
7309 */
7310static int drv_cmd_set_channel_switch(hdd_adapter_t *adapter,
7311 hdd_context_t *hdd_ctx,
7312 uint8_t *command,
7313 uint8_t command_len,
7314 hdd_priv_data_t *priv_data)
7315{
7316 struct net_device *dev = adapter->dev;
7317 int status;
7318 uint32_t chan_number = 0, chan_bw = 0;
7319 uint8_t *value = command;
Kiran Kumar Lokere13644672016-02-29 15:40:10 -08007320 enum phy_ch_width width;
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307321
Krunal Sonibe766b02016-03-10 13:00:44 -08007322 if ((adapter->device_mode != QDF_P2P_GO_MODE) &&
7323 (adapter->device_mode != QDF_SAP_MODE)) {
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307324 hdd_err("IOCTL CHANNEL_SWITCH not supported for mode %d",
7325 adapter->device_mode);
7326 return -EINVAL;
7327 }
7328
7329 status = hdd_parse_set_channel_switch_command(value,
7330 &chan_number, &chan_bw);
7331 if (status) {
7332 hdd_err("Invalid CHANNEL_SWITCH command");
7333 return status;
7334 }
7335
7336 if ((chan_bw != 20) && (chan_bw != 40) && (chan_bw != 80)) {
7337 hdd_err("BW %d is not allowed for CHANNEL_SWITCH", chan_bw);
7338 return -EINVAL;
7339 }
7340
7341 if (chan_bw == 80)
7342 width = CH_WIDTH_80MHZ;
7343 else if (chan_bw == 40)
7344 width = CH_WIDTH_40MHZ;
7345 else
7346 width = CH_WIDTH_20MHZ;
7347
7348 hdd_info("CH:%d BW:%d", chan_number, chan_bw);
7349
7350 status = hdd_softap_set_channel_change(dev, chan_number, width);
7351 if (status) {
7352 hdd_err("Set channel change fail");
7353 return status;
7354 }
7355
7356 return 0;
7357}
7358
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007359/*
7360 * The following table contains all supported WLAN HDD
7361 * IOCTL driver commands and the handler for each of them.
7362 */
7363static const hdd_drv_cmd_t hdd_drv_cmds[] = {
7364 {"P2P_DEV_ADDR", drv_cmd_p2p_dev_addr},
7365 {"P2P_SET_NOA", drv_cmd_p2p_set_noa},
7366 {"P2P_SET_PS", drv_cmd_p2p_set_ps},
7367 {"SETBAND", drv_cmd_set_band},
7368 {"SETWMMPS", drv_cmd_set_wmmps},
7369 {"COUNTRY", drv_cmd_country},
7370 {"SETSUSPENDMODE", drv_cmd_dummy},
7371 {"SET_AP_WPS_P2P_IE", drv_cmd_dummy},
7372 {"BTCOEXSCAN", drv_cmd_dummy},
7373 {"RXFILTER", drv_cmd_dummy},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007374 {"SETROAMTRIGGER", drv_cmd_set_roam_trigger},
7375 {"GETROAMTRIGGER", drv_cmd_get_roam_trigger},
7376 {"SETROAMSCANPERIOD", drv_cmd_set_roam_scan_period},
7377 {"GETROAMSCANPERIOD", drv_cmd_get_roam_scan_period},
7378 {"SETROAMSCANREFRESHPERIOD", drv_cmd_set_roam_scan_refresh_period},
7379 {"GETROAMSCANREFRESHPERIOD", drv_cmd_get_roam_scan_refresh_period},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007380 {"SETROAMMODE", drv_cmd_set_roam_mode},
7381 {"GETROAMMODE", drv_cmd_get_roam_mode},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007382 {"SETROAMDELTA", drv_cmd_set_roam_delta},
7383 {"GETROAMDELTA", drv_cmd_get_roam_delta},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007384 {"GETBAND", drv_cmd_get_band},
7385 {"SETROAMSCANCHANNELS", drv_cmd_set_roam_scan_channels},
7386 {"GETROAMSCANCHANNELS", drv_cmd_get_roam_scan_channels},
7387 {"GETCCXMODE", drv_cmd_get_ccx_mode},
7388 {"GETOKCMODE", drv_cmd_get_okc_mode},
7389 {"GETFASTROAM", drv_cmd_get_fast_roam},
7390 {"GETFASTTRANSITION", drv_cmd_get_fast_transition},
7391 {"SETROAMSCANCHANNELMINTIME", drv_cmd_set_roam_scan_channel_min_time},
7392 {"SENDACTIONFRAME", drv_cmd_send_action_frame},
7393 {"GETROAMSCANCHANNELMINTIME", drv_cmd_get_roam_scan_channel_min_time},
7394 {"SETSCANCHANNELTIME", drv_cmd_set_scan_channel_time},
7395 {"GETSCANCHANNELTIME", drv_cmd_get_scan_channel_time},
7396 {"SETSCANHOMETIME", drv_cmd_set_scan_home_time},
7397 {"GETSCANHOMETIME", drv_cmd_get_scan_home_time},
7398 {"SETROAMINTRABAND", drv_cmd_set_roam_intra_band},
7399 {"GETROAMINTRABAND", drv_cmd_get_roam_intra_band},
7400 {"SETSCANNPROBES", drv_cmd_set_scan_n_probes},
7401 {"GETSCANNPROBES", drv_cmd_get_scan_n_probes},
7402 {"SETSCANHOMEAWAYTIME", drv_cmd_set_scan_home_away_time},
7403 {"GETSCANHOMEAWAYTIME", drv_cmd_get_scan_home_away_time},
7404 {"REASSOC", drv_cmd_reassoc},
7405 {"SETWESMODE", drv_cmd_set_wes_mode},
7406 {"GETWESMODE", drv_cmd_get_wes_mode},
7407 {"SETOPPORTUNISTICRSSIDIFF", drv_cmd_set_opportunistic_rssi_diff},
7408 {"GETOPPORTUNISTICRSSIDIFF", drv_cmd_get_opportunistic_rssi_diff},
7409 {"SETROAMRESCANRSSIDIFF", drv_cmd_set_roam_rescan_rssi_diff},
7410 {"GETROAMRESCANRSSIDIFF", drv_cmd_get_roam_rescan_rssi_diff},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007411 {"SETFASTROAM", drv_cmd_set_fast_roam},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007412 {"SETFASTTRANSITION", drv_cmd_set_fast_transition},
7413 {"FASTREASSOC", drv_cmd_fast_reassoc},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007414 {"SETROAMSCANCONTROL", drv_cmd_set_roam_scan_control},
7415#ifdef FEATURE_WLAN_OKC
7416 {"SETOKCMODE", drv_cmd_set_okc_mode},
7417#endif /* FEATURE_WLAN_OKC */
7418 {"GETROAMSCANCONTROL", drv_cmd_get_roam_scan_control},
7419 {"BTCOEXMODE", drv_cmd_bt_coex_mode},
7420 {"SCAN-ACTIVE", drv_cmd_scan_active},
7421 {"SCAN-PASSIVE", drv_cmd_scan_passive},
7422 {"GETDWELLTIME", drv_cmd_get_dwell_time},
7423 {"SETDWELLTIME", drv_cmd_set_dwell_time},
7424 {"MIRACAST", drv_cmd_miracast},
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08007425 {"SETIBSSBEACONOUIDATA", drv_cmd_set_ibss_beacon_oui_data},
7426 {"SETRMCENABLE", drv_cmd_set_rmc_enable},
7427 {"SETRMCACTIONPERIOD", drv_cmd_set_rmc_action_period},
7428 {"GETIBSSPEERINFOALL", drv_cmd_get_ibss_peer_info_all},
7429 {"GETIBSSPEERINFO", drv_cmd_get_ibss_peer_info},
7430 {"SETRMCTXRATE", drv_cmd_set_rmc_tx_rate},
7431 {"SETIBSSTXFAILEVENT", drv_cmd_set_ibss_tx_fail_event},
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08007432#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007433 {"SETCCXROAMSCANCHANNELS", drv_cmd_set_ccx_roam_scan_channels},
7434 {"GETTSMSTATS", drv_cmd_get_tsm_stats},
7435 {"SETCCKMIE", drv_cmd_set_cckm_ie},
7436 {"CCXBEACONREQ", drv_cmd_ccx_beacon_req},
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08007437#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007438 {"SETMCRATE", drv_cmd_set_mc_rate},
7439 {"MAXTXPOWER", drv_cmd_max_tx_power},
7440 {"SETDFSSCANMODE", drv_cmd_set_dfs_scan_mode},
7441 {"GETDFSSCANMODE", drv_cmd_get_dfs_scan_mode},
7442 {"GETLINKSTATUS", drv_cmd_get_link_status},
7443#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
7444 {"ENABLEEXTWOW", drv_cmd_enable_ext_wow},
7445 {"SETAPP1PARAMS", drv_cmd_set_app1_params},
7446 {"SETAPP2PARAMS", drv_cmd_set_app2_params},
7447#endif
7448#ifdef FEATURE_WLAN_TDLS
7449 {"TDLSSECONDARYCHANNELOFFSET", drv_cmd_tdls_secondary_channel_offset},
7450 {"TDLSOFFCHANNELMODE", drv_cmd_tdls_off_channel_mode},
7451 {"TDLSOFFCHANNEL", drv_cmd_tdls_off_channel},
7452 {"TDLSSCAN", drv_cmd_tdls_scan},
7453#endif
7454 {"RSSI", drv_cmd_get_rssi},
7455 {"LINKSPEED", drv_cmd_get_linkspeed},
7456#ifdef FEATURE_NAPI
7457 {"NAPI", drv_cmd_napi},
7458#endif /* FEATURE_NAPI */
7459 {"RXFILTER-REMOVE", drv_cmd_rx_filter_remove},
7460 {"RXFILTER-ADD", drv_cmd_rx_filter_add},
7461 {"SET_FCC_CHANNEL", drv_cmd_set_fcc_channel},
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307462 {"CHANNEL_SWITCH", drv_cmd_set_channel_switch},
Archana Ramachandran393f3792015-11-13 17:13:21 -08007463 {"SETANTENNAMODE", drv_cmd_set_antenna_mode},
7464 {"GETANTENNAMODE", drv_cmd_get_antenna_mode},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007465};
7466
7467/**
7468 * hdd_drv_cmd_process() - chooses and runs the proper
7469 * handler based on the input command
7470 * @adapter: Pointer to the hdd adapter
7471 * @cmd: Pointer to the driver command
7472 * @priv_data: Pointer to the data associated with the command
7473 *
7474 * This function parses the input hdd driver command and runs
7475 * the proper handler
7476 *
7477 * Return: 0 for success non-zero for failure
7478 */
7479static int hdd_drv_cmd_process(hdd_adapter_t *adapter,
7480 uint8_t *cmd,
7481 hdd_priv_data_t *priv_data)
7482{
7483 hdd_context_t *hdd_ctx;
7484 int i;
7485 const int cmd_num_total = ARRAY_SIZE(hdd_drv_cmds);
7486 uint8_t *cmd_i = NULL;
7487 hdd_drv_cmd_handler_t handler = NULL;
7488 int len = 0;
7489
7490 if (!adapter || !cmd || !priv_data) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05307491 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007492 "%s: at least 1 param is NULL", __func__);
7493 return -EINVAL;
7494 }
7495
7496 hdd_ctx = (hdd_context_t *)adapter->pHddCtx;
7497
7498 for (i = 0; i < cmd_num_total; i++) {
7499
7500 cmd_i = (uint8_t *)hdd_drv_cmds[i].cmd;
7501 handler = hdd_drv_cmds[i].handler;
7502 len = strlen(cmd_i);
7503
7504 if (!handler) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05307505 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007506 "%s: no. %d handler is NULL", __func__, i);
7507 return -EINVAL;
7508 }
7509
7510 if (strncasecmp(cmd, cmd_i, len) == 0)
7511 return handler(adapter, hdd_ctx,
7512 cmd, len, priv_data);
7513 }
7514
7515 return drv_cmd_invalid(adapter, hdd_ctx, cmd, len, priv_data);
7516}
7517
7518/**
7519 * hdd_driver_command() - top level wlan hdd driver command handler
7520 * @adapter: Pointer to the hdd adapter
7521 * @priv_data: Pointer to the raw command data
7522 *
7523 * This function is the top level wlan hdd driver command handler. It
7524 * handles the command with the help of hdd_drv_cmd_process()
7525 *
7526 * Return: 0 for success non-zero for failure
7527 */
7528static int hdd_driver_command(hdd_adapter_t *adapter,
7529 hdd_priv_data_t *priv_data)
7530{
7531 uint8_t *command = NULL;
7532 int ret = 0;
7533
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307534 ENTER();
7535
Anurag Chouhan6d760662016-02-20 16:05:43 +05307536 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007537 hddLog(LOGE, FL("Command not allowed in FTM mode"));
7538 return -EINVAL;
7539 }
7540
7541 /*
7542 * Note that valid pointers are provided by caller
7543 */
7544
7545 /* copy to local struct to avoid numerous changes to legacy code */
7546 if (priv_data->total_len <= 0 ||
7547 priv_data->total_len > WLAN_PRIV_DATA_MAX_LEN) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05307548 hddLog(QDF_TRACE_LEVEL_WARN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007549 "%s:invalid priv_data.total_len(%d)!!!", __func__,
7550 priv_data->total_len);
7551 ret = -EINVAL;
7552 goto exit;
7553 }
7554
7555 /* Allocate +1 for '\0' */
7556 command = kmalloc(priv_data->total_len + 1, GFP_KERNEL);
7557 if (!command) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05307558 hddLog(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007559 "%s: failed to allocate memory", __func__);
7560 ret = -ENOMEM;
7561 goto exit;
7562 }
7563
7564 if (copy_from_user(command, priv_data->buf, priv_data->total_len)) {
7565 ret = -EFAULT;
7566 goto exit;
7567 }
7568
7569 /* Make sure the command is NUL-terminated */
7570 command[priv_data->total_len] = '\0';
7571
7572 hdd_info("%s: %s", adapter->dev->name, command);
7573 ret = hdd_drv_cmd_process(adapter, command, priv_data);
7574
7575exit:
7576 if (command)
7577 kfree(command);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307578 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007579 return ret;
7580}
7581
7582#ifdef CONFIG_COMPAT
7583static int hdd_driver_compat_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
7584{
7585 struct {
7586 compat_uptr_t buf;
7587 int used_len;
7588 int total_len;
7589 } compat_priv_data;
7590 hdd_priv_data_t priv_data;
7591 int ret = 0;
7592
7593 /*
7594 * Note that adapter and ifr have already been verified by caller,
7595 * and HDD context has also been validated
7596 */
7597 if (copy_from_user(&compat_priv_data, ifr->ifr_data,
7598 sizeof(compat_priv_data))) {
7599 ret = -EFAULT;
7600 goto exit;
7601 }
7602 priv_data.buf = compat_ptr(compat_priv_data.buf);
7603 priv_data.used_len = compat_priv_data.used_len;
7604 priv_data.total_len = compat_priv_data.total_len;
7605 ret = hdd_driver_command(adapter, &priv_data);
7606exit:
7607 return ret;
7608}
7609#else /* CONFIG_COMPAT */
7610static int hdd_driver_compat_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
7611{
7612 /* will never be invoked */
7613 return 0;
7614}
7615#endif /* CONFIG_COMPAT */
7616
7617static int hdd_driver_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
7618{
7619 hdd_priv_data_t priv_data;
7620 int ret = 0;
7621
7622 /*
7623 * Note that adapter and ifr have already been verified by caller,
7624 * and HDD context has also been validated
7625 */
7626 if (copy_from_user(&priv_data, ifr->ifr_data, sizeof(priv_data)))
7627 ret = -EFAULT;
7628 else
7629 ret = hdd_driver_command(adapter, &priv_data);
7630
7631 return ret;
7632}
7633
7634/**
7635 * __hdd_ioctl() - ioctl handler for wlan network interfaces
7636 * @dev: device upon which the ioctl was received
7637 * @ifr: ioctl request information
7638 * @cmd: ioctl command
7639 *
7640 * This function does initial processing of wlan device ioctls.
7641 * Currently two flavors of ioctls are supported. The primary ioctl
7642 * that is supported is the (SIOCDEVPRIVATE + 1) ioctl which is used
7643 * for Android "DRIVER" commands. The other ioctl that is
7644 * conditionally supported is the SIOCIOCTLTX99 ioctl which is used
7645 * for FTM on some platforms. This function simply verifies that the
7646 * driver is in a sane state, and that the ioctl is one of the
7647 * supported flavors, in which case flavor-specific handlers are
7648 * dispatched.
7649 *
7650 * Return: 0 on success, non-zero on error
7651 */
7652static int __hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7653{
7654 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
7655 hdd_context_t *hdd_ctx;
7656 int ret;
7657
Jeff Johnson3c3994a2016-02-11 08:12:30 -08007658 ENTER_DEV(dev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307659
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007660 if (dev != adapter->dev) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05307661 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_FATAL,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007662 "%s: HDD adapter/dev inconsistency", __func__);
7663 ret = -ENODEV;
7664 goto exit;
7665 }
7666
7667 if ((!ifr) || (!ifr->ifr_data)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05307668 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007669 "%s: invalid data", __func__);
7670 ret = -EINVAL;
7671 goto exit;
7672 }
7673#if defined(QCA_WIFI_FTM) && defined(LINUX_QCMBR)
Anurag Chouhan6d760662016-02-20 16:05:43 +05307674 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007675 if (SIOCIOCTLTX99 == cmd) {
7676 ret = wlan_hdd_qcmbr_unified_ioctl(adapter, ifr);
7677 goto exit;
7678 }
7679 }
7680#endif
7681
7682 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
7683 ret = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307684 if (ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007685 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007686
7687 switch (cmd) {
7688 case (SIOCDEVPRIVATE + 1):
7689 if (is_compat_task())
7690 ret = hdd_driver_compat_ioctl(adapter, ifr);
7691 else
7692 ret = hdd_driver_ioctl(adapter, ifr);
7693 break;
7694 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05307695 hddLog(QDF_TRACE_LEVEL_ERROR, "%s: unknown ioctl %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007696 __func__, cmd);
7697 ret = -EINVAL;
7698 break;
7699 }
7700exit:
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307701 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007702 return ret;
7703}
7704
7705/**
7706 * hdd_ioctl() - ioctl handler (wrapper) for wlan network interfaces
7707 * @dev: device upon which the ioctl was received
7708 * @ifr: ioctl request information
7709 * @cmd: ioctl command
7710 *
7711 * This function acts as an SSR-protecting wrapper to __hdd_ioctl()
7712 * which is where the ioctls are really handled.
7713 *
7714 * Return: 0 on success, non-zero on error
7715 */
7716int hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7717{
7718 int ret;
7719
7720 cds_ssr_protect(__func__);
7721 ret = __hdd_ioctl(dev, ifr, cmd);
7722 cds_ssr_unprotect(__func__);
7723 return ret;
7724}