blob: ba48e4c695da0979ba677c63cfdefd85d30a7fea [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) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700139 hdd_err("Bad param, context [%p]", context);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800140 return;
141 }
142
143 /*
144 * there is a race condition that exists between this callback
145 * function and the caller since the caller could time out either
146 * before or while this code is executing. we use a spinlock to
147 * serialize these actions
148 */
149 spin_lock(&hdd_context_lock);
150
151 stats_context = context;
152 adapter = stats_context->pAdapter;
153 if ((NULL == adapter) ||
154 (STATS_CONTEXT_MAGIC != stats_context->magic)) {
155 /*
156 * the caller presumably timed out so there is
157 * nothing we can do
158 */
159 spin_unlock(&hdd_context_lock);
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700160 hdd_warn("Invalid context, adapter [%p] magic [%08x]",
161 adapter, stats_context->magic);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800162 return;
163 }
164
165 /* context is valid so caller is still waiting */
166
167 /* paranoia: invalidate the magic */
168 stats_context->magic = 0;
169
170 /* copy over the tsm stats */
171 adapter->tsmStats.UplinkPktQueueDly = tsm_metrics.UplinkPktQueueDly;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530172 qdf_mem_copy(adapter->tsmStats.UplinkPktQueueDlyHist,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800173 tsm_metrics.UplinkPktQueueDlyHist,
174 sizeof(adapter->tsmStats.UplinkPktQueueDlyHist) /
175 sizeof(adapter->tsmStats.UplinkPktQueueDlyHist[0]));
176 adapter->tsmStats.UplinkPktTxDly = tsm_metrics.UplinkPktTxDly;
177 adapter->tsmStats.UplinkPktLoss = tsm_metrics.UplinkPktLoss;
178 adapter->tsmStats.UplinkPktCount = tsm_metrics.UplinkPktCount;
179 adapter->tsmStats.RoamingCount = tsm_metrics.RoamingCount;
180 adapter->tsmStats.RoamingDly = tsm_metrics.RoamingDly;
181
182 /* notify the caller */
183 complete(&stats_context->completion);
184
185 /* serialization is complete */
186 spin_unlock(&hdd_context_lock);
187}
188
189static
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530190QDF_STATUS hdd_get_tsm_stats(hdd_adapter_t *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800191 const uint8_t tid,
192 tAniTrafStrmMetrics *tsm_metrics)
193{
194 hdd_station_ctx_t *hdd_sta_ctx = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530195 QDF_STATUS hstatus;
196 QDF_STATUS vstatus = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800197 unsigned long rc;
Houston Hoffman59c097f2016-11-09 15:50:25 -0800198 static struct statsContext context;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800199 hdd_context_t *hdd_ctx = NULL;
200
201 if (NULL == adapter) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700202 hdd_err("adapter is NULL");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530203 return QDF_STATUS_E_FAULT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800204 }
205
206 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
207 hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
208
209 /* we are connected prepare our callback context */
210 init_completion(&context.completion);
211 context.pAdapter = adapter;
212 context.magic = STATS_CONTEXT_MAGIC;
213
214 /* query tsm stats */
215 hstatus = sme_get_tsm_stats(hdd_ctx->hHal, hdd_get_tsm_stats_cb,
216 hdd_sta_ctx->conn_info.staId[0],
217 hdd_sta_ctx->conn_info.bssId,
218 &context, hdd_ctx->pcds_context, tid);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530219 if (QDF_STATUS_SUCCESS != hstatus) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700220 hdd_err("Unable to retrieve statistics");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530221 vstatus = QDF_STATUS_E_FAULT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800222 } else {
223 /* request was sent -- wait for the response */
224 rc = wait_for_completion_timeout(&context.completion,
225 msecs_to_jiffies(WLAN_WAIT_TIME_STATS));
226 if (!rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700227 hdd_err("SME timed out while retrieving statistics");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530228 vstatus = QDF_STATUS_E_TIMEOUT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800229 }
230 }
231
232 /*
233 * either we never sent a request, we sent a request and received a
234 * response or we sent a request and timed out. if we never sent a
235 * request or if we sent a request and got a response, we want to
236 * clear the magic out of paranoia. if we timed out there is a
237 * race condition such that the callback function could be
238 * executing at the same time we are. of primary concern is if the
239 * callback function had already verified the "magic" but had not
240 * yet set the completion variable when a timeout occurred. we
241 * serialize these activities by invalidating the magic while
242 * holding a shared spinlock which will cause us to block if the
243 * callback is currently executing
244 */
245 spin_lock(&hdd_context_lock);
246 context.magic = 0;
247 spin_unlock(&hdd_context_lock);
248
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530249 if (QDF_STATUS_SUCCESS == vstatus) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800250 tsm_metrics->UplinkPktQueueDly =
251 adapter->tsmStats.UplinkPktQueueDly;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530252 qdf_mem_copy(tsm_metrics->UplinkPktQueueDlyHist,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800253 adapter->tsmStats.UplinkPktQueueDlyHist,
254 sizeof(adapter->tsmStats.UplinkPktQueueDlyHist) /
255 sizeof(adapter->tsmStats.
256 UplinkPktQueueDlyHist[0]));
257 tsm_metrics->UplinkPktTxDly = adapter->tsmStats.UplinkPktTxDly;
258 tsm_metrics->UplinkPktLoss = adapter->tsmStats.UplinkPktLoss;
259 tsm_metrics->UplinkPktCount = adapter->tsmStats.UplinkPktCount;
260 tsm_metrics->RoamingCount = adapter->tsmStats.RoamingCount;
261 tsm_metrics->RoamingDly = adapter->tsmStats.RoamingDly;
262 }
263 return vstatus;
264}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -0800265#endif /*FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800266
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800267/* Function header is left blank intentionally */
268static int hdd_parse_setrmcenable_command(uint8_t *pValue,
269 uint8_t *pRmcEnable)
270{
271 uint8_t *inPtr = pValue;
272 int tempInt;
273 int v = 0;
274 char buf[32];
275 *pRmcEnable = 0;
276
277 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
278
279 if (NULL == inPtr) {
280 return 0;
281 }
282
283 else if (SPACE_ASCII_VALUE != *inPtr) {
284 return 0;
285 }
286
287 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
288 inPtr++;
289
290 if ('\0' == *inPtr) {
291 return 0;
292 }
293
294 sscanf(inPtr, "%32s ", buf);
295 v = kstrtos32(buf, 10, &tempInt);
296 if (v < 0) {
297 return -EINVAL;
298 }
299
300 *pRmcEnable = tempInt;
301
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700302 hdd_info("ucRmcEnable: %d", *pRmcEnable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800303
304 return 0;
305}
306
307/* Function header is left blank intentionally */
308static int hdd_parse_setrmcactionperiod_command(uint8_t *pValue,
309 uint32_t *pActionPeriod)
310{
311 uint8_t *inPtr = pValue;
312 int tempInt;
313 int v = 0;
314 char buf[32];
315 *pActionPeriod = 0;
316
317 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
318
319 if (NULL == inPtr) {
320 return -EINVAL;
321 }
322
323 else if (SPACE_ASCII_VALUE != *inPtr) {
324 return -EINVAL;
325 }
326
327 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
328 inPtr++;
329
330 if ('\0' == *inPtr) {
331 return 0;
332 }
333
334 sscanf(inPtr, "%32s ", buf);
335 v = kstrtos32(buf, 10, &tempInt);
336 if (v < 0) {
337 return -EINVAL;
338 }
339
340 if ((tempInt < WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STAMIN) ||
341 (tempInt > WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STAMAX)) {
342 return -EINVAL;
343 }
344
345 *pActionPeriod = tempInt;
346
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700347 hdd_info("uActionPeriod: %d", *pActionPeriod);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800348
349 return 0;
350}
351
352/* Function header is left blank intentionally */
353static int hdd_parse_setrmcrate_command(uint8_t *pValue,
354 uint32_t *pRate,
355 tTxrateinfoflags *pTxFlags)
356{
357 uint8_t *inPtr = pValue;
358 int tempInt;
359 int v = 0;
360 char buf[32];
361 *pRate = 0;
362 *pTxFlags = 0;
363
364 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
365
366 if (NULL == inPtr) {
367 return -EINVAL;
368 }
369
370 else if (SPACE_ASCII_VALUE != *inPtr) {
371 return -EINVAL;
372 }
373
374 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
375 inPtr++;
376
377 if ('\0' == *inPtr) {
378 return 0;
379 }
380
381 sscanf(inPtr, "%32s ", buf);
382 v = kstrtos32(buf, 10, &tempInt);
383 if (v < 0) {
384 return -EINVAL;
385 }
386
387 switch (tempInt) {
388 default:
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700389 hdd_warn("Unsupported rate: %d", tempInt);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800390 return -EINVAL;
391 case 0:
392 case 6:
393 case 9:
394 case 12:
395 case 18:
396 case 24:
397 case 36:
398 case 48:
399 case 54:
400 *pTxFlags = eHAL_TX_RATE_LEGACY;
401 *pRate = tempInt * 10;
402 break;
403 case 65:
404 *pTxFlags = eHAL_TX_RATE_HT20;
405 *pRate = tempInt * 10;
406 break;
407 case 72:
408 *pTxFlags = eHAL_TX_RATE_HT20 | eHAL_TX_RATE_SGI;
409 *pRate = 722;
410 break;
411 }
412
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700413 hdd_info("Rate: %d", *pRate);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800414
415 return 0;
416}
417
418/**
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700419 * hdd_get_ibss_peer_info_cb() - IBSS peer Info request callback
420 * @UserData: Adapter private data
421 * @pPeerInfoRsp: Peer info response
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800422 *
423 * This is an asynchronous callback function from SME when the peer info
424 * is received
425 *
426 * Return: 0 for success non-zero for failure
427 */
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700428void
429hdd_get_ibss_peer_info_cb(void *pUserData,
430 tSirPeerInfoRspParams *pPeerInfo)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800431{
432 hdd_adapter_t *adapter = (hdd_adapter_t *) pUserData;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800433 hdd_station_ctx_t *pStaCtx;
434 uint8_t i;
435
436 /* Sanity check */
437 if ((NULL == adapter) ||
438 (WLAN_HDD_ADAPTER_MAGIC != adapter->magic)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700439 hdd_alert("invalid adapter or adapter has invalid magic");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800440 return;
441 }
442
443 pStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
444 if (NULL != pPeerInfo && QDF_STATUS_SUCCESS == pPeerInfo->status) {
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700445 /* validate number of peers */
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530446 if (pPeerInfo->numPeers > SIR_MAX_NUM_STA_IN_IBSS) {
447 hdd_warn("Limiting num_peers %u to %u",
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700448 pPeerInfo->numPeers, SIR_MAX_NUM_STA_IN_IBSS);
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530449 pPeerInfo->numPeers = SIR_MAX_NUM_STA_IN_IBSS;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800450 }
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530451 pStaCtx->ibss_peer_info.status = pPeerInfo->status;
452 pStaCtx->ibss_peer_info.numPeers = pPeerInfo->numPeers;
453
454 for (i = 0; i < pPeerInfo->numPeers; i++)
455 pStaCtx->ibss_peer_info.peerInfoParams[i] =
456 pPeerInfo->peerInfoParams[i];
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800457 } else {
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530458 hdd_err("peerInfo %s: status %u, numPeers %u",
459 pPeerInfo ? "valid" : "null",
460 pPeerInfo ? pPeerInfo->status : QDF_STATUS_E_FAILURE,
461 pPeerInfo ? pPeerInfo->numPeers : 0);
462 pStaCtx->ibss_peer_info.numPeers = 0;
463 pStaCtx->ibss_peer_info.status = QDF_STATUS_E_FAILURE;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800464 }
465
466 complete(&adapter->ibss_peer_info_comp);
467}
468
469/**
470 * hdd_cfg80211_get_ibss_peer_info_all() - get ibss peers' info
471 * @adapter: Adapter context
472 *
473 * Request function to get IBSS peer info from lower layers
474 *
475 * Return: 0 for success non-zero for failure
476 */
477static
478QDF_STATUS hdd_cfg80211_get_ibss_peer_info_all(hdd_adapter_t *adapter)
479{
480 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
481 QDF_STATUS retStatus = QDF_STATUS_E_FAILURE;
482 unsigned long rc;
483
484 INIT_COMPLETION(adapter->ibss_peer_info_comp);
485
486 retStatus = sme_request_ibss_peer_info(hHal, adapter,
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700487 hdd_get_ibss_peer_info_cb,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800488 true, 0xFF);
489
490 if (QDF_STATUS_SUCCESS == retStatus) {
491 rc = wait_for_completion_timeout
492 (&adapter->ibss_peer_info_comp,
493 msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT));
494
495 /* status will be 0 if timed out */
496 if (!rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700497 hdd_warn("Warning: IBSS_PEER_INFO_TIMEOUT");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800498 retStatus = QDF_STATUS_E_FAILURE;
499 return retStatus;
500 }
501 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700502 hdd_warn("Warning: sme_request_ibss_peer_info Request failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800503 }
504
505 return retStatus;
506}
507
508/**
509 * hdd_cfg80211_get_ibss_peer_info() - get ibss peer info
510 * @adapter: Adapter context
511 * @staIdx: Sta index for which the peer info is requested
512 *
513 * Request function to get IBSS peer info from lower layers
514 *
515 * Return: 0 for success non-zero for failure
516 */
517static QDF_STATUS
518hdd_cfg80211_get_ibss_peer_info(hdd_adapter_t *adapter, uint8_t staIdx)
519{
520 unsigned long rc;
521 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
522 QDF_STATUS retStatus = QDF_STATUS_E_FAILURE;
523
524 INIT_COMPLETION(adapter->ibss_peer_info_comp);
525
526 retStatus = sme_request_ibss_peer_info(hHal, adapter,
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700527 hdd_get_ibss_peer_info_cb,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800528 false, staIdx);
529
530 if (QDF_STATUS_SUCCESS == retStatus) {
531 rc = wait_for_completion_timeout(
532 &adapter->ibss_peer_info_comp,
533 msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT));
534
535 /* status = 0 on timeout */
536 if (!rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700537 hdd_warn("Warning: IBSS_PEER_INFO_TIMEOUT");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800538 retStatus = QDF_STATUS_E_FAILURE;
539 return retStatus;
540 }
541 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700542 hdd_warn("Warning: sme_request_ibss_peer_info Request failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800543 }
544
545 return retStatus;
546}
547
548/* Function header is left blank intentionally */
Jeff Johnsonf731b302016-10-05 16:00:55 -0700549static QDF_STATUS
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800550hdd_parse_get_ibss_peer_info(uint8_t *pValue, struct qdf_mac_addr *pPeerMacAddr)
551{
552 uint8_t *inPtr = pValue;
553 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
554
555 if (NULL == inPtr) {
556 return QDF_STATUS_E_FAILURE;;
557 }
558
559 else if (SPACE_ASCII_VALUE != *inPtr) {
560 return QDF_STATUS_E_FAILURE;;
561 }
562
563 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
564 inPtr++;
565
566 if ('\0' == *inPtr) {
567 return QDF_STATUS_E_FAILURE;;
568 }
569
570 if (inPtr[2] != ':' || inPtr[5] != ':' || inPtr[8] != ':' ||
571 inPtr[11] != ':' || inPtr[14] != ':') {
572 return QDF_STATUS_E_FAILURE;;
573 }
574 sscanf(inPtr, "%2x:%2x:%2x:%2x:%2x:%2x",
575 (unsigned int *)&pPeerMacAddr->bytes[0],
576 (unsigned int *)&pPeerMacAddr->bytes[1],
577 (unsigned int *)&pPeerMacAddr->bytes[2],
578 (unsigned int *)&pPeerMacAddr->bytes[3],
579 (unsigned int *)&pPeerMacAddr->bytes[4],
580 (unsigned int *)&pPeerMacAddr->bytes[5]);
581
582 return QDF_STATUS_SUCCESS;
583}
584
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800585static void hdd_get_band_helper(hdd_context_t *hdd_ctx, int *pBand)
586{
587 eCsrBand band = -1;
588 sme_get_freq_band((tHalHandle) (hdd_ctx->hHal), &band);
589 switch (band) {
590 case eCSR_BAND_ALL:
591 *pBand = WLAN_HDD_UI_BAND_AUTO;
592 break;
593
594 case eCSR_BAND_24:
595 *pBand = WLAN_HDD_UI_BAND_2_4_GHZ;
596 break;
597
598 case eCSR_BAND_5G:
599 *pBand = WLAN_HDD_UI_BAND_5_GHZ;
600 break;
601
602 default:
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700603 hdd_warn("Invalid Band %d", band);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800604 *pBand = -1;
605 break;
606 }
607}
608
609/**
610 * _hdd_parse_bssid_and_chan() - helper function to parse bssid and channel
611 * @data: input data
612 * @target_ap_bssid: pointer to bssid (output parameter)
613 * @channel: pointer to channel (output parameter)
614 *
615 * Return: 0 if parsing is successful; -EINVAL otherwise
616 */
617static int _hdd_parse_bssid_and_chan(const uint8_t **data,
618 uint8_t *bssid,
619 uint8_t *channel)
620{
621 const uint8_t *in_ptr;
622 int v = 0;
623 int temp_int;
624 uint8_t temp_buf[32];
625
626 /* 12 hexa decimal digits, 5 ':' and '\0' */
627 uint8_t mac_addr[18];
628
629 if (!data || !*data)
630 return -EINVAL;
631
632 in_ptr = *data;
633
634 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
635 /* no argument after the command */
636 if (NULL == in_ptr)
637 goto error;
638 /* no space after the command */
639 else if (SPACE_ASCII_VALUE != *in_ptr)
640 goto error;
641
642 /* remove empty spaces */
643 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
644 in_ptr++;
645
646 /* no argument followed by spaces */
647 if ('\0' == *in_ptr)
648 goto error;
649
650 v = sscanf(in_ptr, "%17s", mac_addr);
651 if (!((1 == v) && hdd_is_valid_mac_address(mac_addr))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700652 hdd_err("Invalid MAC address or All hex inputs are not read (%d)",
653 v);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800654 goto error;
655 }
656
657 bssid[0] = hex_to_bin(mac_addr[0]) << 4 |
658 hex_to_bin(mac_addr[1]);
659 bssid[1] = hex_to_bin(mac_addr[3]) << 4 |
660 hex_to_bin(mac_addr[4]);
661 bssid[2] = hex_to_bin(mac_addr[6]) << 4 |
662 hex_to_bin(mac_addr[7]);
663 bssid[3] = hex_to_bin(mac_addr[9]) << 4 |
664 hex_to_bin(mac_addr[10]);
665 bssid[4] = hex_to_bin(mac_addr[12]) << 4 |
666 hex_to_bin(mac_addr[13]);
667 bssid[5] = hex_to_bin(mac_addr[15]) << 4 |
668 hex_to_bin(mac_addr[16]);
669
670 /* point to the next argument */
671 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
672 /* no argument after the command */
673 if (NULL == in_ptr)
674 goto error;
675
676 /* remove empty spaces */
677 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
678 in_ptr++;
679
680 /* no argument followed by spaces */
681 if ('\0' == *in_ptr)
682 goto error;
683
684 /* get the next argument ie the channel number */
685 v = sscanf(in_ptr, "%31s ", temp_buf);
686 if (1 != v)
687 goto error;
688
689 v = kstrtos32(temp_buf, 10, &temp_int);
690 if ((v < 0) || (temp_int < 0) ||
691 (temp_int > WNI_CFG_CURRENT_CHANNEL_STAMAX))
692 return -EINVAL;
693
694 *channel = temp_int;
695 *data = in_ptr;
696 return 0;
697error:
698 *data = in_ptr;
699 return -EINVAL;
700}
701
702/**
703 * hdd_parse_send_action_frame_data() - HDD Parse send action frame data
704 * @pValue: Pointer to input data
705 * @pTargetApBssid: Pointer to target Ap bssid
706 * @pChannel: Pointer to the Target AP channel
707 * @pDwellTime: Pointer to the time to stay off-channel
708 * after transmitting action frame
709 * @pBuf: Pointer to data
710 * @pBufLen: Pointer to data length
711 *
712 * This function parses the send action frame data passed in the format
713 * SENDACTIONFRAME<space><bssid><space><channel><space><dwelltime><space><data>
714 *
715 * Return: 0 for success non-zero for failure
716 */
717static int
718hdd_parse_send_action_frame_v1_data(const uint8_t *pValue,
719 uint8_t *pTargetApBssid,
720 uint8_t *pChannel, uint8_t *pDwellTime,
721 uint8_t **pBuf, uint8_t *pBufLen)
722{
723 const uint8_t *inPtr = pValue;
724 const uint8_t *dataEnd;
725 int tempInt;
726 int j = 0;
727 int i = 0;
728 int v = 0;
729 uint8_t tempBuf[32];
730 uint8_t tempByte = 0;
731
732 if (_hdd_parse_bssid_and_chan(&inPtr, pTargetApBssid, pChannel))
733 return -EINVAL;
734
735 /* point to the next argument */
736 inPtr = strnchr(inPtr, strlen(inPtr), SPACE_ASCII_VALUE);
737 /* no argument after the command */
738 if (NULL == inPtr)
739 return -EINVAL;
740 /* removing empty spaces */
741 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
742 inPtr++;
743
744 /* no argument followed by spaces */
745 if ('\0' == *inPtr) {
746 return -EINVAL;
747 }
748
749 /* getting the next argument ie the dwell time */
750 v = sscanf(inPtr, "%31s ", tempBuf);
751 if (1 != v)
752 return -EINVAL;
753
754 v = kstrtos32(tempBuf, 10, &tempInt);
755 if (v < 0 || tempInt < 0)
756 return -EINVAL;
757
758 *pDwellTime = tempInt;
759
760 /* point to the next argument */
761 inPtr = strnchr(inPtr, strlen(inPtr), SPACE_ASCII_VALUE);
762 /* no argument after the command */
763 if (NULL == inPtr)
764 return -EINVAL;
765 /* removing empty spaces */
766 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
767 inPtr++;
768
769 /* no argument followed by spaces */
770 if ('\0' == *inPtr) {
771 return -EINVAL;
772 }
773
774 /* find the length of data */
775 dataEnd = inPtr;
776 while (('\0' != *dataEnd)) {
777 dataEnd++;
778 }
779 *pBufLen = dataEnd - inPtr;
780 if (*pBufLen <= 0)
781 return -EINVAL;
782
783 /*
784 * Allocate the number of bytes based on the number of input characters
785 * whether it is even or odd.
786 * if the number of input characters are even, then we need N/2 byte.
787 * if the number of input characters are odd, then we need do (N+1)/2
788 * to compensate rounding off.
789 * For example, if N = 18, then (18 + 1)/2 = 9 bytes are enough.
790 * If N = 19, then we need 10 bytes, hence (19 + 1)/2 = 10 bytes
791 */
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530792 *pBuf = qdf_mem_malloc((*pBufLen + 1) / 2);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800793 if (NULL == *pBuf) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700794 hdd_err("qdf_mem_malloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800795 return -ENOMEM;
796 }
797
798 /* the buffer received from the upper layer is character buffer,
799 * we need to prepare the buffer taking 2 characters in to a U8 hex
800 * decimal number for example 7f0000f0...form a buffer to contain 7f
801 * in 0th location, 00 in 1st and f0 in 3rd location
802 */
803 for (i = 0, j = 0; j < *pBufLen; j += 2) {
804 if (j + 1 == *pBufLen) {
805 tempByte = hex_to_bin(inPtr[j]);
806 } else {
807 tempByte =
808 (hex_to_bin(inPtr[j]) << 4) |
809 (hex_to_bin(inPtr[j + 1]));
810 }
811 (*pBuf)[i++] = tempByte;
812 }
813 *pBufLen = i;
814 return 0;
815}
816
817/**
818 * hdd_parse_reassoc_command_data() - HDD Parse reassoc command data
819 * @pValue: Pointer to input data (its a NULL terminated string)
820 * @pTargetApBssid: Pointer to target Ap bssid
821 * @pChannel: Pointer to the Target AP channel
822 *
823 * This function parses the reasoc command data passed in the format
824 * REASSOC<space><bssid><space><channel>
825 *
826 * Return: 0 for success non-zero for failure
827 */
828static int hdd_parse_reassoc_command_v1_data(const uint8_t *pValue,
829 uint8_t *pTargetApBssid,
830 uint8_t *pChannel)
831{
832 const uint8_t *inPtr = pValue;
833
834 if (_hdd_parse_bssid_and_chan(&inPtr, pTargetApBssid, pChannel))
835 return -EINVAL;
836
837 return 0;
838}
839
Naveen Rawat05376ee2016-07-18 16:43:32 -0700840#ifdef WLAN_FEATURE_ROAM_OFFLOAD
841void hdd_wma_send_fastreassoc_cmd(int sessionId, const tSirMacAddr bssid,
842 int channel)
843{
844 struct wma_roam_invoke_cmd *fastreassoc;
845 cds_msg_t msg = {0};
846
847 fastreassoc = qdf_mem_malloc(sizeof(*fastreassoc));
848 if (NULL == fastreassoc) {
849 hdd_err("qdf_mem_malloc failed for fastreassoc");
850 return;
851 }
852 fastreassoc->vdev_id = sessionId;
853 fastreassoc->channel = channel;
854 fastreassoc->bssid[0] = bssid[0];
855 fastreassoc->bssid[1] = bssid[1];
856 fastreassoc->bssid[2] = bssid[2];
857 fastreassoc->bssid[3] = bssid[3];
858 fastreassoc->bssid[4] = bssid[4];
859 fastreassoc->bssid[5] = bssid[5];
860
861 msg.type = SIR_HAL_ROAM_INVOKE;
862 msg.reserved = 0;
863 msg.bodyptr = fastreassoc;
864 if (QDF_STATUS_SUCCESS != cds_mq_post_message(QDF_MODULE_ID_WMA,
865 &msg)) {
866 qdf_mem_free(fastreassoc);
867 hdd_err("Not able to post ROAM_INVOKE_CMD message to WMA");
868 }
869}
Naveen Rawat05376ee2016-07-18 16:43:32 -0700870#endif
871
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800872/**
873 * hdd_reassoc() - perform a userspace-directed reassoc
Deepak Dhamdhere5a36a4a2016-11-12 15:08:22 -0800874 * @adapter: Adapter upon which the command was received
875 * @bssid: BSSID with which to reassociate
876 * @channel: channel upon which to reassociate
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700877 * @src: The source for the trigger of this action
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800878 *
879 * This function performs a userspace-directed reassoc operation
880 *
881 * Return: 0 for success non-zero for failure
882 */
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700883int hdd_reassoc(hdd_adapter_t *adapter, const uint8_t *bssid,
Deepak Dhamdhere5a36a4a2016-11-12 15:08:22 -0800884 uint8_t channel, const handoff_src src)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800885{
886 hdd_station_ctx_t *pHddStaCtx;
Naveen Rawat05376ee2016-07-18 16:43:32 -0700887 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800888 int ret = 0;
889
Naveen Rawat05376ee2016-07-18 16:43:32 -0700890 if (hdd_ctx == NULL) {
891 hdd_err("Invalid hdd ctx");
892 return -EINVAL;
893 }
894
Krunal Sonibe766b02016-03-10 13:00:44 -0800895 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800896 hdd_warn("Unsupported in mode %s(%d)",
897 hdd_device_mode_to_string(adapter->device_mode),
898 adapter->device_mode);
899 return -EINVAL;
900 }
901
902 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
903
904 /* if not associated, no need to proceed with reassoc */
905 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700906 hdd_info("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800907 ret = -EINVAL;
908 goto exit;
909 }
910
911 /*
912 * if the target bssid is same as currently associated AP,
Deepak Dhamdhere5a36a4a2016-11-12 15:08:22 -0800913 * use the current connections's channel.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800914 */
915 if (!memcmp(bssid, pHddStaCtx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530916 QDF_MAC_ADDR_SIZE)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700917 hdd_info("Reassoc BSSID is same as currently associated AP bssid");
Deepak Dhamdhere5a36a4a2016-11-12 15:08:22 -0800918 channel = pHddStaCtx->conn_info.operationChannel;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800919 }
920
921 /* Check channel number is a valid channel number */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530922 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800923 wlan_hdd_validate_operation_channel(adapter, channel)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700924 hdd_err("Invalid Channel %d", channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800925 ret = -EINVAL;
926 goto exit;
927 }
928
929 /* Proceed with reassoc */
Naveen Rawat05376ee2016-07-18 16:43:32 -0700930 if (roaming_offload_enabled(hdd_ctx)) {
931 hdd_wma_send_fastreassoc_cmd((int)adapter->sessionId,
932 bssid, (int)channel);
933 } else {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800934 tCsrHandoffRequest handoffInfo;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800935
936 handoffInfo.channel = channel;
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700937 handoffInfo.src = src;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530938 qdf_mem_copy(handoffInfo.bssid.bytes, bssid, QDF_MAC_ADDR_SIZE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800939 sme_handoff_request(hdd_ctx->hHal, adapter->sessionId,
940 &handoffInfo);
941 }
942exit:
943 return ret;
944}
945
946/**
947 * hdd_parse_reassoc_v1() - parse version 1 of the REASSOC command
948 * @adapter: Adapter upon which the command was received
949 * @command: ASCII text command that was received
950 *
951 * This function parses the v1 REASSOC command with the format
952 *
953 * REASSOC xx:xx:xx:xx:xx:xx CH
954 *
955 * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the
956 * BSSID and CH is the ASCII representation of the channel. For
957 * example
958 *
959 * REASSOC 00:0a:0b:11:22:33 48
960 *
961 * Return: 0 for success non-zero for failure
962 */
963static int hdd_parse_reassoc_v1(hdd_adapter_t *adapter, const char *command)
964{
965 uint8_t channel = 0;
966 tSirMacAddr bssid;
967 int ret;
968
969 ret = hdd_parse_reassoc_command_v1_data(command, bssid, &channel);
970 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700971 hdd_err("Failed to parse reassoc command data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800972 } else {
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700973 ret = hdd_reassoc(adapter, bssid, channel, REASSOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800974 }
975 return ret;
976}
977
978/**
979 * hdd_parse_reassoc_v2() - parse version 2 of the REASSOC command
980 * @adapter: Adapter upon which the command was received
981 * @command: Command that was received, ASCII command
982 * followed by binary data
983 *
984 * This function parses the v2 REASSOC command with the format
985 *
986 * REASSOC <android_wifi_reassoc_params>
987 *
988 * Return: 0 for success non-zero for failure
989 */
990static int hdd_parse_reassoc_v2(hdd_adapter_t *adapter, const char *command)
991{
992 struct android_wifi_reassoc_params params;
993 tSirMacAddr bssid;
994 int ret;
995
996 /* The params are located after "REASSOC " */
997 memcpy(&params, command + 8, sizeof(params));
998
999 if (!mac_pton(params.bssid, (u8 *) &bssid)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001000 hdd_err("MAC address parsing failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001001 ret = -EINVAL;
1002 } else {
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -07001003 ret = hdd_reassoc(adapter, bssid, params.channel, REASSOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001004 }
1005 return ret;
1006}
1007
1008/**
1009 * hdd_parse_reassoc() - parse the REASSOC command
1010 * @adapter: Adapter upon which the command was received
1011 * @command: Command that was received
1012 *
1013 * There are two different versions of the REASSOC command. Version 1
1014 * of the command contains a parameter list that is ASCII characters
1015 * whereas version 2 contains a combination of ASCII and binary
1016 * payload. Determine if a version 1 or a version 2 command is being
1017 * parsed by examining the parameters, and then dispatch the parser
1018 * that is appropriate for the command.
1019 *
1020 * Return: 0 for success non-zero for failure
1021 */
1022static int hdd_parse_reassoc(hdd_adapter_t *adapter, const char *command)
1023{
1024 int ret;
1025
1026 /* both versions start with "REASSOC "
1027 * v1 has a bssid and channel # as an ASCII string
1028 * REASSOC xx:xx:xx:xx:xx:xx CH
1029 * v2 has a C struct
1030 * REASSOC <binary c struct>
1031 *
1032 * The first field in the v2 struct is also the bssid in ASCII.
1033 * But in the case of a v2 message the BSSID is NUL-terminated.
1034 * Hence we can peek at that offset to see if this is V1 or V2
1035 * REASSOC xx:xx:xx:xx:xx:xx*
1036 * 1111111111222222
1037 * 01234567890123456789012345
1038 */
1039 if (command[25]) {
1040 ret = hdd_parse_reassoc_v1(adapter, command);
1041 } else {
1042 ret = hdd_parse_reassoc_v2(adapter, command);
1043 }
1044
1045 return ret;
1046}
1047
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001048/**
1049 * hdd_sendactionframe() - send a userspace-supplied action frame
1050 * @adapter: Adapter upon which the command was received
1051 * @bssid: BSSID target of the action frame
1052 * @channel: Channel upon which to send the frame
1053 * @dwell_time: Amount of time to dwell when the frame is sent
1054 * @payload_len:Length of the payload
1055 * @payload: Payload of the frame
1056 *
1057 * This function sends a userspace-supplied action frame
1058 *
1059 * Return: 0 for success non-zero for failure
1060 */
1061static int
1062hdd_sendactionframe(hdd_adapter_t *adapter, const uint8_t *bssid,
1063 const uint8_t channel, const uint8_t dwell_time,
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001064 const int payload_len, const uint8_t *payload)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001065{
1066 struct ieee80211_channel chan;
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001067 int frame_len, ret = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001068 uint8_t *frame;
1069 struct ieee80211_hdr_3addr *hdr;
1070 u64 cookie;
1071 hdd_station_ctx_t *pHddStaCtx;
1072 hdd_context_t *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001073 tpSirMacVendorSpecificFrameHdr pVendorSpecific =
1074 (tpSirMacVendorSpecificFrameHdr) payload;
1075#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
1076 struct cfg80211_mgmt_tx_params params;
1077#endif
1078
Krunal Sonibe766b02016-03-10 13:00:44 -08001079 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001080 hdd_warn("Unsupported in mode %s(%d)",
1081 hdd_device_mode_to_string(adapter->device_mode),
1082 adapter->device_mode);
1083 return -EINVAL;
1084 }
1085
1086 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
1087 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1088
1089 /* if not associated, no need to send action frame */
1090 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001091 hdd_info("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001092 ret = -EINVAL;
1093 goto exit;
1094 }
1095
1096 /*
1097 * if the target bssid is different from currently associated AP,
1098 * then no need to send action frame
1099 */
1100 if (memcmp(bssid, pHddStaCtx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05301101 QDF_MAC_ADDR_SIZE)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001102 hdd_info("STA is not associated to this AP");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001103 ret = -EINVAL;
1104 goto exit;
1105 }
1106
1107 chan.center_freq = sme_chn_to_freq(channel);
1108 /* Check if it is specific action frame */
1109 if (pVendorSpecific->category ==
1110 SIR_MAC_ACTION_VENDOR_SPECIFIC_CATEGORY) {
1111 static const uint8_t Oui[] = { 0x00, 0x00, 0xf0 };
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301112 if (!qdf_mem_cmp(pVendorSpecific->Oui, (void *)Oui, 3)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001113 /*
1114 * if the channel number is different from operating
1115 * channel then no need to send action frame
1116 */
1117 if (channel != 0) {
1118 if (channel !=
1119 pHddStaCtx->conn_info.operationChannel) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001120 hdd_info("channel(%d) is different from operating channel(%d)",
1121 channel,
1122 pHddStaCtx->conn_info.
1123 operationChannel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001124 ret = -EINVAL;
1125 goto exit;
1126 }
1127 /*
1128 * If channel number is specified and same
1129 * as home channel, ensure that action frame
1130 * is sent immediately by cancelling
1131 * roaming scans. Otherwise large dwell times
1132 * may cause long delays in sending action
1133 * frames.
1134 */
1135 sme_abort_roam_scan(hdd_ctx->hHal,
1136 adapter->sessionId);
1137 } else {
1138 /*
1139 * 0 is accepted as current home channel,
1140 * delayed transmission of action frame is ok.
1141 */
1142 chan.center_freq =
1143 sme_chn_to_freq(pHddStaCtx->conn_info.
1144 operationChannel);
1145 }
1146 }
1147 }
1148 if (chan.center_freq == 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001149 hdd_err("Invalid channel number %d", channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001150 ret = -EINVAL;
1151 goto exit;
1152 }
1153
1154 frame_len = payload_len + 24;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301155 frame = qdf_mem_malloc(frame_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001156 if (!frame) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001157 hdd_err("memory allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001158 ret = -ENOMEM;
1159 goto exit;
1160 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001161
1162 hdr = (struct ieee80211_hdr_3addr *)frame;
1163 hdr->frame_control =
1164 cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301165 qdf_mem_copy(hdr->addr1, bssid, QDF_MAC_ADDR_SIZE);
1166 qdf_mem_copy(hdr->addr2, adapter->macAddressCurrent.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05301167 QDF_MAC_ADDR_SIZE);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301168 qdf_mem_copy(hdr->addr3, bssid, QDF_MAC_ADDR_SIZE);
1169 qdf_mem_copy(hdr + 1, payload, payload_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001170
1171#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
1172 params.chan = &chan;
1173 params.offchan = 0;
1174 params.wait = dwell_time;
1175 params.buf = frame;
1176 params.len = frame_len;
1177 params.no_cck = 1;
1178 params.dont_wait_for_ack = 1;
1179 ret = wlan_hdd_mgmt_tx(NULL, &adapter->wdev, &params, &cookie);
1180#else
1181 ret = wlan_hdd_mgmt_tx(NULL,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001182 &(adapter->wdev),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001183 &chan, 0,
Amar Singhal01098f72015-10-08 11:55:32 -07001184
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001185 dwell_time, frame, frame_len, 1, 1, &cookie);
1186#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
1187
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301188 qdf_mem_free(frame);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001189exit:
1190 return ret;
1191}
1192
1193/**
1194 * hdd_parse_sendactionframe_v1() - parse version 1 of the
1195 * SENDACTIONFRAME command
1196 * @adapter: Adapter upon which the command was received
1197 * @command: ASCII text command that was received
1198 *
1199 * This function parses the v1 SENDACTIONFRAME command with the format
1200 *
1201 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DW xxxxxx
1202 *
1203 * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the
1204 * BSSID, CH is the ASCII representation of the channel, DW is the
1205 * ASCII representation of the dwell time, and xxxxxx is the Hex-ASCII
1206 * payload. For example
1207 *
1208 * SENDACTIONFRAME 00:0a:0b:11:22:33 48 40 aabbccddee
1209 *
1210 * Return: 0 for success non-zero for failure
1211 */
1212static int
1213hdd_parse_sendactionframe_v1(hdd_adapter_t *adapter, const char *command)
1214{
1215 uint8_t channel = 0;
1216 uint8_t dwell_time = 0;
1217 uint8_t payload_len = 0;
1218 uint8_t *payload = NULL;
1219 tSirMacAddr bssid;
1220 int ret;
1221
1222 ret = hdd_parse_send_action_frame_v1_data(command, bssid, &channel,
1223 &dwell_time, &payload,
1224 &payload_len);
1225 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001226 hdd_err("Failed to parse send action frame data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001227 } else {
1228 ret = hdd_sendactionframe(adapter, bssid, channel,
1229 dwell_time, payload_len, payload);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301230 qdf_mem_free(payload);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001231 }
1232
1233 return ret;
1234}
1235
1236/**
1237 * hdd_parse_sendactionframe_v2() - parse version 2 of the
1238 * SENDACTIONFRAME command
1239 * @adapter: Adapter upon which the command was received
1240 * @command: Command that was received, ASCII command
1241 * followed by binary data
1242 *
1243 * This function parses the v2 SENDACTIONFRAME command with the format
1244 *
1245 * SENDACTIONFRAME <android_wifi_af_params>
1246 *
1247 * Return: 0 for success non-zero for failure
1248 */
1249static int
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001250hdd_parse_sendactionframe_v2(hdd_adapter_t *adapter,
1251 const char *command, int total_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001252{
1253 struct android_wifi_af_params *params;
1254 tSirMacAddr bssid;
1255 int ret;
1256
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001257 /* The params are located after "SENDACTIONFRAME " */
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001258 total_len -= 16;
1259 params = (struct android_wifi_af_params *)(command + 16);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001260
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001261 if (params->len <= 0 || params->len > ANDROID_WIFI_ACTION_FRAME_SIZE ||
1262 (params->len > total_len)) {
1263 hdd_err("Invalid payload length: %d", params->len);
1264 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001265 }
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001266
1267 if (!mac_pton(params->bssid, (u8 *)&bssid)) {
1268 hdd_err("MAC address parsing failed");
1269 return -EINVAL;
1270 }
1271
1272 if (params->channel < 0 ||
1273 params->channel > WNI_CFG_CURRENT_CHANNEL_STAMAX) {
1274 hdd_err("Invalid channel: %d", params->channel);
1275 return -EINVAL;
1276 }
1277
1278 if (params->dwell_time < 0) {
1279 hdd_err("Invalid dwell_time: %d", params->dwell_time);
1280 return -EINVAL;
1281 }
1282
1283 ret = hdd_sendactionframe(adapter, bssid, params->channel,
1284 params->dwell_time, params->len, params->data);
1285
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001286 return ret;
1287}
1288
1289/**
1290 * hdd_parse_sendactionframe() - parse the SENDACTIONFRAME command
1291 * @adapter: Adapter upon which the command was received
1292 * @command: Command that was received
1293 *
1294 * There are two different versions of the SENDACTIONFRAME command.
1295 * Version 1 of the command contains a parameter list that is ASCII
1296 * characters whereas version 2 contains a combination of ASCII and
1297 * binary payload. Determine if a version 1 or a version 2 command is
1298 * being parsed by examining the parameters, and then dispatch the
1299 * parser that is appropriate for the version of the command.
1300 *
1301 * Return: 0 for success non-zero for failure
1302 */
1303static int
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001304hdd_parse_sendactionframe(hdd_adapter_t *adapter, const char *command,
1305 int total_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001306{
1307 int ret;
1308
1309 /*
1310 * both versions start with "SENDACTIONFRAME "
1311 * v1 has a bssid and other parameters as an ASCII string
1312 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DWELL LEN FRAME
1313 * v2 has a C struct
1314 * SENDACTIONFRAME <binary c struct>
1315 *
1316 * The first field in the v2 struct is also the bssid in ASCII.
1317 * But in the case of a v2 message the BSSID is NUL-terminated.
1318 * Hence we can peek at that offset to see if this is V1 or V2
1319 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx*
1320 * 111111111122222222223333
1321 * 0123456789012345678901234567890123
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001322 * For both the commands, a valid command must have atleast
1323 * first 34 length of data.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001324 */
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001325 if (total_len < 34) {
1326 hdd_err("Invalid command (total_len=%d)", total_len);
1327 return -EINVAL;
1328 }
1329
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001330 if (command[33]) {
1331 ret = hdd_parse_sendactionframe_v1(adapter, command);
1332 } else {
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001333 ret = hdd_parse_sendactionframe_v2(adapter, command, total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001334 }
1335
1336 return ret;
1337}
1338
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001339/**
1340 * hdd_parse_channellist() - HDD Parse channel list
1341 * @pValue: Pointer to input channel list
1342 * @ChannelList: Pointer to local output array to record
1343 * channel list
1344 * @pNumChannels: Pointer to number of roam scan channels
1345 *
1346 * This function parses the channel list passed in the format
1347 * SETROAMSCANCHANNELS<space><Number of channels><space>Channel 1<space>Channel 2<space>Channel N
1348 * if the Number of channels (N) does not match with the actual number
1349 * of channels passed then take the minimum of N and count of
1350 * (Ch1, Ch2, ...Ch M). For example, if SETROAMSCANCHANNELS 3 36 40 44 48,
1351 * only 36, 40 and 44 shall be taken. If SETROAMSCANCHANNELS 5 36 40 44 48,
1352 * ignore 5 and take 36, 40, 44 and 48. This function does not take care of
1353 * removing duplicate channels from the list
1354 *
1355 * Return: 0 for success non-zero for failure
1356 */
1357static int
1358hdd_parse_channellist(const uint8_t *pValue, uint8_t *pChannelList,
1359 uint8_t *pNumChannels)
1360{
1361 const uint8_t *inPtr = pValue;
1362 int tempInt;
1363 int j = 0;
1364 int v = 0;
1365 char buf[32];
1366
1367 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
1368 /* no argument after the command */
1369 if (NULL == inPtr) {
1370 return -EINVAL;
1371 }
1372
1373 /* no space after the command */
1374 else if (SPACE_ASCII_VALUE != *inPtr) {
1375 return -EINVAL;
1376 }
1377
1378 /* remove empty spaces */
1379 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
1380 inPtr++;
1381
1382 /* no argument followed by spaces */
1383 if ('\0' == *inPtr) {
1384 return -EINVAL;
1385 }
1386
1387 /* get the first argument ie the number of channels */
1388 v = sscanf(inPtr, "%31s ", buf);
1389 if (1 != v)
1390 return -EINVAL;
1391
1392 v = kstrtos32(buf, 10, &tempInt);
1393 if ((v < 0) ||
1394 (tempInt <= 0) || (tempInt > WNI_CFG_VALID_CHANNEL_LIST_LEN)) {
1395 return -EINVAL;
1396 }
1397
1398 *pNumChannels = tempInt;
1399
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001400 hdd_info("Number of channels are: %d", *pNumChannels);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001401
1402 for (j = 0; j < (*pNumChannels); j++) {
1403 /*
1404 * inPtr pointing to the beginning of first space after number
1405 * of channels
1406 */
1407 inPtr = strpbrk(inPtr, " ");
1408 /* no channel list after the number of channels argument */
1409 if (NULL == inPtr) {
1410 if (0 != j) {
1411 *pNumChannels = j;
1412 return 0;
1413 } else {
1414 return -EINVAL;
1415 }
1416 }
1417
1418 /* remove empty space */
1419 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
1420 inPtr++;
1421
1422 /*
1423 * no channel list after the number of channels
1424 * argument and spaces
1425 */
1426 if ('\0' == *inPtr) {
1427 if (0 != j) {
1428 *pNumChannels = j;
1429 return 0;
1430 } else {
1431 return -EINVAL;
1432 }
1433 }
1434
1435 v = sscanf(inPtr, "%31s ", buf);
1436 if (1 != v)
1437 return -EINVAL;
1438
1439 v = kstrtos32(buf, 10, &tempInt);
1440 if ((v < 0) ||
1441 (tempInt <= 0) ||
1442 (tempInt > WNI_CFG_CURRENT_CHANNEL_STAMAX)) {
1443 return -EINVAL;
1444 }
1445 pChannelList[j] = tempInt;
1446
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001447 hdd_info("Channel %d added to preferred channel list",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001448 pChannelList[j]);
1449 }
1450
1451 return 0;
1452}
1453
1454/**
1455 * hdd_parse_set_roam_scan_channels_v1() - parse version 1 of the
1456 * SETROAMSCANCHANNELS command
1457 * @adapter: Adapter upon which the command was received
1458 * @command: ASCII text command that was received
1459 *
1460 * This function parses the v1 SETROAMSCANCHANNELS command with the format
1461 *
1462 * SETROAMSCANCHANNELS N C1 C2 ... Cn
1463 *
1464 * Where "N" is the ASCII representation of the number of channels and
1465 * C1 thru Cn is the ASCII representation of the channels. For example
1466 *
1467 * SETROAMSCANCHANNELS 4 36 40 44 48
1468 *
1469 * Return: 0 for success non-zero for failure
1470 */
1471static int
1472hdd_parse_set_roam_scan_channels_v1(hdd_adapter_t *adapter,
1473 const char *command)
1474{
1475 uint8_t channel_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
1476 uint8_t num_chan = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301477 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001478 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1479 int ret;
1480
1481 ret = hdd_parse_channellist(command, channel_list, &num_chan);
1482 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001483 hdd_err("Failed to parse channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001484 goto exit;
1485 }
1486
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301487 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001488 TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL,
1489 adapter->sessionId, num_chan));
1490
1491 if (num_chan > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001492 hdd_err("number of channels (%d) supported exceeded max (%d)",
1493 num_chan, WNI_CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001494 ret = -EINVAL;
1495 goto exit;
1496 }
1497
1498 status =
1499 sme_change_roam_scan_channel_list(hdd_ctx->hHal,
1500 adapter->sessionId,
1501 channel_list, num_chan);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301502 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001503 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001504 ret = -EINVAL;
1505 goto exit;
1506 }
1507exit:
1508 return ret;
1509}
1510
1511/**
1512 * hdd_parse_set_roam_scan_channels_v2() - parse version 2 of the
1513 * SETROAMSCANCHANNELS command
1514 * @adapter: Adapter upon which the command was received
1515 * @command: Command that was received, ASCII command
1516 * followed by binary data
1517 *
1518 * This function parses the v2 SETROAMSCANCHANNELS command with the format
1519 *
1520 * SETROAMSCANCHANNELS [N][C1][C2][Cn]
1521 *
1522 * The command begins with SETROAMSCANCHANNELS followed by a space, but
1523 * what follows the space is an array of u08 parameters. For example
1524 *
1525 * SETROAMSCANCHANNELS [0x04 0x24 0x28 0x2c 0x30]
1526 *
1527 * Return: 0 for success non-zero for failure
1528 */
1529static int
1530hdd_parse_set_roam_scan_channels_v2(hdd_adapter_t *adapter,
1531 const char *command)
1532{
1533 const uint8_t *value;
1534 uint8_t channel_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
1535 uint8_t channel;
1536 uint8_t num_chan;
1537 int i;
1538 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301539 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001540 int ret = 0;
1541
1542 /* array of values begins after "SETROAMSCANCHANNELS " */
1543 value = command + 20;
1544
1545 num_chan = *value++;
1546 if (num_chan > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001547 hdd_err("number of channels (%d) supported exceeded max (%d)",
1548 num_chan, WNI_CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001549 ret = -EINVAL;
1550 goto exit;
1551 }
1552
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301553 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001554 TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL,
1555 adapter->sessionId, num_chan));
1556
1557 for (i = 0; i < num_chan; i++) {
1558 channel = *value++;
1559 if (channel > WNI_CFG_CURRENT_CHANNEL_STAMAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001560 hdd_err("index %d invalid channel %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001561 i, channel);
1562 ret = -EINVAL;
1563 goto exit;
1564 }
1565 channel_list[i] = channel;
1566 }
1567 status =
1568 sme_change_roam_scan_channel_list(hdd_ctx->hHal,
1569 adapter->sessionId,
1570 channel_list, num_chan);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301571 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001572 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001573 ret = -EINVAL;
1574 goto exit;
1575 }
1576exit:
1577 return ret;
1578}
1579
1580/**
1581 * hdd_parse_set_roam_scan_channels() - parse the
1582 * SETROAMSCANCHANNELS command
1583 * @adapter: Adapter upon which the command was received
1584 * @command: Command that was received
1585 *
1586 * There are two different versions of the SETROAMSCANCHANNELS command.
1587 * Version 1 of the command contains a parameter list that is ASCII
1588 * characters whereas version 2 contains a binary payload. Determine
1589 * if a version 1 or a version 2 command is being parsed by examining
1590 * the parameters, and then dispatch the parser that is appropriate for
1591 * the command.
1592 *
1593 * Return: 0 for success non-zero for failure
1594 */
1595static int
1596hdd_parse_set_roam_scan_channels(hdd_adapter_t *adapter, const char *command)
1597{
1598 const char *cursor;
1599 char ch;
1600 bool v1;
1601 int ret;
1602
1603 /* start after "SETROAMSCANCHANNELS " */
1604 cursor = command + 20;
1605
1606 /* assume we have a version 1 command until proven otherwise */
1607 v1 = true;
1608
1609 /* v1 params will only contain ASCII digits and space */
1610 while ((ch = *cursor++) && v1) {
1611 if (!(isdigit(ch) || isspace(ch))) {
1612 v1 = false;
1613 }
1614 }
1615 if (v1) {
1616 ret = hdd_parse_set_roam_scan_channels_v1(adapter, command);
1617 } else {
1618 ret = hdd_parse_set_roam_scan_channels_v2(adapter, command);
1619 }
1620
1621 return ret;
1622}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001623
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08001624#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001625/**
1626 * hdd_parse_plm_cmd() - HDD Parse Plm command
1627 * @pValue: Pointer to input data
1628 * @pPlmRequest:Pointer to output struct tpSirPlmReq
1629 *
1630 * This function parses the plm command passed in the format
1631 * CCXPLMREQ<space><enable><space><dialog_token><space>
1632 * <meas_token><space><num_of_bursts><space><burst_int><space>
1633 * <measu duration><space><burst_len><space><desired_tx_pwr>
1634 * <space><multcast_addr><space><number_of_channels>
1635 * <space><channel_numbers>
1636 *
1637 * Return: 0 for success non-zero for failure
1638 */
Jeff Johnsonf731b302016-10-05 16:00:55 -07001639static QDF_STATUS hdd_parse_plm_cmd(uint8_t *pValue, tSirPlmReq *pPlmRequest)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001640{
1641 uint8_t *cmdPtr = NULL;
1642 int count, content = 0, ret = 0;
1643 char buf[32];
1644
1645 /* move to argument list */
1646 cmdPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
1647 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301648 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001649
1650 /* no space after the command */
1651 if (SPACE_ASCII_VALUE != *cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301652 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001653
1654 /* remove empty spaces */
1655 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1656 cmdPtr++;
1657
1658 /* START/STOP PLM req */
1659 ret = sscanf(cmdPtr, "%31s ", buf);
1660 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301661 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001662
1663 ret = kstrtos32(buf, 10, &content);
1664 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301665 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001666
1667 pPlmRequest->enable = content;
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 /* Dialog token of radio meas req containing meas reqIE */
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->diag_token = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001687 hdd_debug("diag token %d", pPlmRequest->diag_token);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001688 cmdPtr = strpbrk(cmdPtr, " ");
1689
1690 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301691 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001692
1693 /* remove empty spaces */
1694 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1695 cmdPtr++;
1696
1697 /* measurement token of meas req IE */
1698 ret = sscanf(cmdPtr, "%31s ", buf);
1699 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301700 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001701
1702 ret = kstrtos32(buf, 10, &content);
1703 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301704 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001705
1706 pPlmRequest->meas_token = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001707 hdd_debug("meas token %d", pPlmRequest->meas_token);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001708
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001709 hdd_err("PLM req %s", pPlmRequest->enable ? "START" : "STOP");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001710 if (pPlmRequest->enable) {
1711
1712 cmdPtr = strpbrk(cmdPtr, " ");
1713
1714 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301715 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001716
1717 /* remove empty spaces */
1718 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1719 cmdPtr++;
1720
1721 /* total number of bursts after which STA stops sending */
1722 ret = sscanf(cmdPtr, "%31s ", buf);
1723 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301724 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001725
1726 ret = kstrtos32(buf, 10, &content);
1727 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301728 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001729
1730 if (content < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301731 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001732
1733 pPlmRequest->numBursts = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001734 hdd_debug("num burst %d", pPlmRequest->numBursts);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001735 cmdPtr = strpbrk(cmdPtr, " ");
1736
1737 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301738 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001739
1740 /* remove empty spaces */
1741 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1742 cmdPtr++;
1743
1744 /* burst interval in seconds */
1745 ret = sscanf(cmdPtr, "%31s ", buf);
1746 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301747 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001748
1749 ret = kstrtos32(buf, 10, &content);
1750 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301751 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001752
1753 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301754 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001755
1756 pPlmRequest->burstInt = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001757 hdd_debug("burst Int %d", pPlmRequest->burstInt);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001758 cmdPtr = strpbrk(cmdPtr, " ");
1759
1760 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301761 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001762
1763 /* remove empty spaces */
1764 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1765 cmdPtr++;
1766
1767 /* Meas dur in TU's,STA goes off-ch and transmit PLM bursts */
1768 ret = sscanf(cmdPtr, "%31s ", buf);
1769 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301770 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001771
1772 ret = kstrtos32(buf, 10, &content);
1773 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301774 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001775
1776 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301777 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001778
1779 pPlmRequest->measDuration = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001780 hdd_debug("measDur %d", pPlmRequest->measDuration);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001781 cmdPtr = strpbrk(cmdPtr, " ");
1782
1783 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301784 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001785
1786 /* remove empty spaces */
1787 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1788 cmdPtr++;
1789
1790 /* burst length of PLM bursts */
1791 ret = sscanf(cmdPtr, "%31s ", buf);
1792 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301793 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001794
1795 ret = kstrtos32(buf, 10, &content);
1796 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301797 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001798
1799 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301800 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001801
1802 pPlmRequest->burstLen = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001803 hdd_debug("burstLen %d", pPlmRequest->burstLen);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001804 cmdPtr = strpbrk(cmdPtr, " ");
1805
1806 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301807 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001808
1809 /* remove empty spaces */
1810 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1811 cmdPtr++;
1812
1813 /* desired tx power for transmission of PLM bursts */
1814 ret = sscanf(cmdPtr, "%31s ", buf);
1815 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301816 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001817
1818 ret = kstrtos32(buf, 10, &content);
1819 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301820 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001821
1822 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301823 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001824
1825 pPlmRequest->desiredTxPwr = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001826 hdd_debug("desiredTxPwr %d",
1827 pPlmRequest->desiredTxPwr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001828
Anurag Chouhan6d760662016-02-20 16:05:43 +05301829 for (count = 0; count < QDF_MAC_ADDR_SIZE; count++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001830 cmdPtr = strpbrk(cmdPtr, " ");
1831
1832 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301833 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001834
1835 /* remove empty spaces */
1836 while ((SPACE_ASCII_VALUE == *cmdPtr)
1837 && ('\0' != *cmdPtr))
1838 cmdPtr++;
1839
1840 ret = sscanf(cmdPtr, "%31s ", buf);
1841 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301842 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001843
1844 ret = kstrtos32(buf, 16, &content);
1845 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301846 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001847
Srinivas Girigowda5146dee2015-11-18 21:46:48 -08001848 pPlmRequest->mac_addr.bytes[count] = content;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001849 }
1850
Srinivas Girigowda5146dee2015-11-18 21:46:48 -08001851 hdd_debug("MC addr " MAC_ADDRESS_STR,
1852 MAC_ADDR_ARRAY(pPlmRequest->mac_addr.bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001853
1854 cmdPtr = strpbrk(cmdPtr, " ");
1855
1856 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301857 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001858
1859 /* remove empty spaces */
1860 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1861 cmdPtr++;
1862
1863 /* number of channels */
1864 ret = sscanf(cmdPtr, "%31s ", buf);
1865 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301866 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001867
1868 ret = kstrtos32(buf, 10, &content);
1869 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301870 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001871
1872 if (content < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301873 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001874
Srinivas Girigowda0fb6cc42016-08-26 14:53:59 -07001875 content = QDF_MIN(content, WNI_CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001876 pPlmRequest->plmNumCh = content;
Srinivas Girigowda0fb6cc42016-08-26 14:53:59 -07001877 hdd_debug("numch: %d", pPlmRequest->plmNumCh);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001878
1879 /* Channel numbers */
1880 for (count = 0; count < pPlmRequest->plmNumCh; count++) {
1881 cmdPtr = strpbrk(cmdPtr, " ");
1882
1883 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301884 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001885
1886 /* remove empty spaces */
1887 while ((SPACE_ASCII_VALUE == *cmdPtr)
1888 && ('\0' != *cmdPtr))
1889 cmdPtr++;
1890
1891 ret = sscanf(cmdPtr, "%31s ", buf);
1892 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301893 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001894
1895 ret = kstrtos32(buf, 10, &content);
Srinivas Girigowda0fb6cc42016-08-26 14:53:59 -07001896 if (ret < 0 || content <= 0 ||
1897 content > WNI_CFG_CURRENT_CHANNEL_STAMAX)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301898 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001899
1900 pPlmRequest->plmChList[count] = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001901 hdd_debug(" ch- %d", pPlmRequest->plmChList[count]);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001902 }
1903 }
1904 /* If PLM START */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301905 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001906}
1907#endif
1908
1909#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
1910static void wlan_hdd_ready_to_extwow(void *callbackContext, bool is_success)
1911{
1912 hdd_context_t *hdd_ctx = (hdd_context_t *) callbackContext;
1913 int rc;
1914
1915 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301916 if (rc)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001917 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001918 hdd_ctx->ext_wow_should_suspend = is_success;
1919 complete(&hdd_ctx->ready_to_extwow);
1920}
1921
1922static int hdd_enable_ext_wow(hdd_adapter_t *adapter,
1923 tpSirExtWoWParams arg_params)
1924{
1925 tSirExtWoWParams params;
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301926 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001927 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1928 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
1929 int rc;
1930
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301931 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001932
1933 INIT_COMPLETION(hdd_ctx->ready_to_extwow);
1934
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301935 qdf_ret_status = sme_configure_ext_wow(hHal, &params,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001936 &wlan_hdd_ready_to_extwow,
1937 hdd_ctx);
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301938 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001939 hdd_err("sme_configure_ext_wow returned failure %d",
1940 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001941 return -EPERM;
1942 }
1943
1944 rc = wait_for_completion_timeout(&hdd_ctx->ready_to_extwow,
1945 msecs_to_jiffies(WLAN_WAIT_TIME_READY_TO_EXTWOW));
1946 if (!rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001947 hdd_err("Failed to get ready to extwow");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001948 return -EPERM;
1949 }
1950
1951 if (hdd_ctx->ext_wow_should_suspend) {
1952 if (hdd_ctx->config->extWowGotoSuspend) {
1953 pm_message_t state;
1954
1955 state.event = PM_EVENT_SUSPEND;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001956 hdd_info("Received ready to ExtWoW. Going to suspend");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001957
1958 rc = wlan_hdd_cfg80211_suspend_wlan(hdd_ctx->wiphy, NULL);
1959 if (rc < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001960 hdd_err("wlan_hdd_cfg80211_suspend_wlan failed, error = %d",
1961 rc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001962 return rc;
1963 }
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301964 qdf_ret_status = wlan_hdd_bus_suspend(state);
1965 if (qdf_ret_status != QDF_STATUS_SUCCESS) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001966 hdd_err("wlan_hdd_suspend failed, status = %d",
1967 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001968 wlan_hdd_cfg80211_resume_wlan(hdd_ctx->wiphy);
1969 return -EPERM;
1970 }
1971 }
1972 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001973 hdd_err("Received ready to ExtWoW failure");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001974 return -EPERM;
1975 }
1976
1977 return 0;
1978}
1979
1980static int hdd_enable_ext_wow_parser(hdd_adapter_t *adapter, int vdev_id,
1981 int value)
1982{
1983 tSirExtWoWParams params;
1984 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1985 int rc;
1986
1987 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301988 if (rc)
1989 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001990
1991 if (value < EXT_WOW_TYPE_APP_TYPE1 ||
1992 value > EXT_WOW_TYPE_APP_TYPE1_2) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001993 hdd_err("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 {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002008 hdd_err("Set app params before enable it value %d",
2009 value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002010 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) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002031 hdd_err("sme_configure_app_type1_params returned failure %d",
2032 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002033 return -EPERM;
2034 }
2035
2036 return 0;
2037}
2038
2039static int hdd_set_app_type1_parser(hdd_adapter_t *adapter,
2040 char *arg, int len)
2041{
2042 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2043 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
2044 char id[20], password[20];
2045 tSirAppType1Params params;
Srinivas Girigowda04209912015-11-24 12:11:13 -08002046 int rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002047
2048 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302049 if (rc)
2050 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002051
2052 if (2 != sscanf(arg, "%8s %16s", id, password)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002053 hdd_err("Invalid Number of arguments");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002054 return -EINVAL;
2055 }
2056
2057 memset(&params, 0, sizeof(tSirAppType1Params));
2058 params.vdev_id = adapter->sessionId;
Anurag Chouhanc5548422016-02-24 18:33:27 +05302059 qdf_copy_macaddr(&params.wakee_mac_addr, &adapter->macAddressCurrent);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002060
2061 params.id_length = strlen(id);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302062 qdf_mem_copy(params.identification_id, id, params.id_length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002063 params.pass_length = strlen(password);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302064 qdf_mem_copy(params.password, password, params.pass_length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002065
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002066 hdd_info("%d %pM %.8s %u %.16s %u",
2067 params.vdev_id, params.wakee_mac_addr.bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002068 params.identification_id, params.id_length,
2069 params.password, params.pass_length);
2070
2071 return hdd_set_app_type1_params(hHal, &params);
2072}
2073
2074static int hdd_set_app_type2_params(tHalHandle hHal,
2075 tpSirAppType2Params arg_params)
2076{
2077 tSirAppType2Params params;
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05302078 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002079
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302080 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002081
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05302082 qdf_ret_status = sme_configure_app_type2_params(hHal, &params);
2083 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002084 hdd_err("sme_configure_app_type2_params returned failure %d",
2085 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002086 return -EPERM;
2087 }
2088
2089 return 0;
2090}
2091
2092static int hdd_set_app_type2_parser(hdd_adapter_t *adapter,
2093 char *arg, int len)
2094{
2095 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2096 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
2097 char mac_addr[20], rc4_key[20];
Anurag Chouhan6d760662016-02-20 16:05:43 +05302098 unsigned int gateway_mac[QDF_MAC_ADDR_SIZE];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002099 tSirAppType2Params params;
2100 int ret;
2101
2102 ret = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302103 if (ret)
2104 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002105
2106 memset(&params, 0, sizeof(tSirAppType2Params));
2107
Bhargav Shahf4fd97d2015-07-08 10:21:37 +05302108 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 -08002109 mac_addr, rc4_key, (unsigned int *)&params.ip_id,
2110 (unsigned int *)&params.ip_device_ip,
2111 (unsigned int *)&params.ip_server_ip,
2112 (unsigned int *)&params.tcp_seq,
2113 (unsigned int *)&params.tcp_ack_seq,
Bhargav Shahf4fd97d2015-07-08 10:21:37 +05302114 (uint16_t *)&params.tcp_src_port,
2115 (uint16_t *)&params.tcp_dst_port,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002116 (unsigned int *)&params.keepalive_init,
2117 (unsigned int *)&params.keepalive_min,
2118 (unsigned int *)&params.keepalive_max,
2119 (unsigned int *)&params.keepalive_inc,
2120 (unsigned int *)&params.tcp_tx_timeout_val,
2121 (unsigned int *)&params.tcp_rx_timeout_val);
2122
2123 if (ret != 15 && ret != 7) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002124 hdd_err("Invalid Number of arguments");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002125 return -EINVAL;
2126 }
2127
2128 if (6 !=
2129 sscanf(mac_addr, "%02x:%02x:%02x:%02x:%02x:%02x", &gateway_mac[0],
2130 &gateway_mac[1], &gateway_mac[2], &gateway_mac[3],
2131 &gateway_mac[4], &gateway_mac[5])) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002132 hdd_err("Invalid MacAddress Input %s", mac_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002133 return -EINVAL;
2134 }
2135
2136 if (params.tcp_src_port > WLAN_HDD_MAX_TCP_PORT ||
2137 params.tcp_dst_port > WLAN_HDD_MAX_TCP_PORT) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002138 hdd_err("Invalid TCP Port Number");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002139 return -EINVAL;
2140 }
2141
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302142 qdf_mem_copy(&params.gateway_mac.bytes, (uint8_t *) &gateway_mac,
Anurag Chouhan6d760662016-02-20 16:05:43 +05302143 QDF_MAC_ADDR_SIZE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002144
2145 params.rc4_key_len = strlen(rc4_key);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302146 qdf_mem_copy(params.rc4_key, rc4_key, params.rc4_key_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002147
2148 params.vdev_id = adapter->sessionId;
2149 params.tcp_src_port = (params.tcp_src_port != 0) ?
2150 params.tcp_src_port : hdd_ctx->config->extWowApp2TcpSrcPort;
2151 params.tcp_dst_port = (params.tcp_dst_port != 0) ?
2152 params.tcp_dst_port : hdd_ctx->config->extWowApp2TcpDstPort;
2153 params.keepalive_init = (params.keepalive_init != 0) ?
2154 params.keepalive_init : hdd_ctx->config->
2155 extWowApp2KAInitPingInterval;
2156 params.keepalive_min =
2157 (params.keepalive_min != 0) ?
2158 params.keepalive_min :
2159 hdd_ctx->config->extWowApp2KAMinPingInterval;
2160 params.keepalive_max =
2161 (params.keepalive_max != 0) ?
2162 params.keepalive_max :
2163 hdd_ctx->config->extWowApp2KAMaxPingInterval;
2164 params.keepalive_inc =
2165 (params.keepalive_inc != 0) ?
2166 params.keepalive_inc :
2167 hdd_ctx->config->extWowApp2KAIncPingInterval;
2168 params.tcp_tx_timeout_val =
2169 (params.tcp_tx_timeout_val != 0) ?
2170 params.tcp_tx_timeout_val :
2171 hdd_ctx->config->extWowApp2TcpTxTimeout;
2172 params.tcp_rx_timeout_val =
2173 (params.tcp_rx_timeout_val != 0) ?
2174 params.tcp_rx_timeout_val :
2175 hdd_ctx->config->extWowApp2TcpRxTimeout;
2176
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002177 hdd_info("%pM %.16s %u %u %u %u %u %u %u %u %u %u %u %u %u",
2178 gateway_mac, rc4_key, params.ip_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002179 params.ip_device_ip, params.ip_server_ip, params.tcp_seq,
2180 params.tcp_ack_seq, params.tcp_src_port, params.tcp_dst_port,
2181 params.keepalive_init, params.keepalive_min,
2182 params.keepalive_max, params.keepalive_inc,
2183 params.tcp_tx_timeout_val, params.tcp_rx_timeout_val);
2184
2185 return hdd_set_app_type2_params(hHal, &params);
2186}
2187#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
2188
2189/**
2190 * hdd_parse_setmaxtxpower_command() - HDD Parse MAXTXPOWER command
2191 * @pValue: Pointer to MAXTXPOWER command
2192 * @pDbm: Pointer to tx power
2193 *
2194 * This function parses the MAXTXPOWER command passed in the format
2195 * MAXTXPOWER<space>X(Tx power in dbm)
2196 *
2197 * For example input commands:
2198 * 1) MAXTXPOWER -8 -> This is translated into set max TX power to -8 dbm
2199 * 2) MAXTXPOWER -23 -> This is translated into set max TX power to -23 dbm
2200 *
2201 * Return: 0 for success non-zero for failure
2202 */
2203static int hdd_parse_setmaxtxpower_command(uint8_t *pValue, int *pTxPower)
2204{
2205 uint8_t *inPtr = pValue;
2206 int tempInt;
2207 int v = 0;
2208 *pTxPower = 0;
2209
2210 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2211 /* no argument after the command */
2212 if (NULL == inPtr) {
2213 return -EINVAL;
2214 }
2215
2216 /* no space after the command */
2217 else if (SPACE_ASCII_VALUE != *inPtr) {
2218 return -EINVAL;
2219 }
2220
2221 /* remove empty spaces */
2222 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2223 inPtr++;
2224
2225 /* no argument followed by spaces */
2226 if ('\0' == *inPtr) {
2227 return 0;
2228 }
2229
2230 v = kstrtos32(inPtr, 10, &tempInt);
2231
2232 /* Range checking for passed parameter */
2233 if ((tempInt < HDD_MIN_TX_POWER) || (tempInt > HDD_MAX_TX_POWER)) {
2234 return -EINVAL;
2235 }
2236
2237 *pTxPower = tempInt;
2238
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002239 hdd_info("SETMAXTXPOWER: %d", *pTxPower);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002240
2241 return 0;
2242} /* End of hdd_parse_setmaxtxpower_command */
2243
2244static int hdd_get_dwell_time(struct hdd_config *pCfg, uint8_t *command,
2245 char *extra, uint8_t n, uint8_t *len)
2246{
2247 int ret = 0;
2248
2249 if (!pCfg || !command || !extra || !len) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002250 hdd_err("argument passed for GETDWELLTIME is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002251 ret = -EINVAL;
2252 return ret;
2253 }
2254
2255 if (strncmp(command, "GETDWELLTIME ACTIVE MAX", 23) == 0) {
2256 *len = scnprintf(extra, n, "GETDWELLTIME ACTIVE MAX %u\n",
2257 (int)pCfg->nActiveMaxChnTime);
2258 return ret;
2259 } else if (strncmp(command, "GETDWELLTIME ACTIVE MIN", 23) == 0) {
2260 *len = scnprintf(extra, n, "GETDWELLTIME ACTIVE MIN %u\n",
2261 (int)pCfg->nActiveMinChnTime);
2262 return ret;
2263 } else if (strncmp(command, "GETDWELLTIME PASSIVE MAX", 24) == 0) {
2264 *len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MAX %u\n",
2265 (int)pCfg->nPassiveMaxChnTime);
2266 return ret;
2267 } else if (strncmp(command, "GETDWELLTIME PASSIVE MIN", 24) == 0) {
2268 *len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MIN %u\n",
2269 (int)pCfg->nPassiveMinChnTime);
2270 return ret;
2271 } else if (strncmp(command, "GETDWELLTIME", 12) == 0) {
2272 *len = scnprintf(extra, n, "GETDWELLTIME %u \n",
2273 (int)pCfg->nActiveMaxChnTime);
2274 return ret;
2275 } else {
2276 ret = -EINVAL;
2277 }
2278
2279 return ret;
2280}
2281
2282static int hdd_set_dwell_time(hdd_adapter_t *adapter, uint8_t *command)
2283{
2284 tHalHandle hHal;
2285 struct hdd_config *pCfg;
2286 uint8_t *value = command;
2287 tSmeConfigParams smeConfig;
2288 int val = 0, temp = 0;
2289
2290 pCfg = (WLAN_HDD_GET_CTX(adapter))->config;
2291 hHal = WLAN_HDD_GET_HAL_CTX(adapter);
2292 if (!pCfg || !hHal) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002293 hdd_err("argument passed for SETDWELLTIME is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002294 return -EINVAL;
2295 }
2296
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302297 qdf_mem_zero(&smeConfig, sizeof(smeConfig));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002298 sme_get_config_param(hHal, &smeConfig);
2299
2300 if (strncmp(command, "SETDWELLTIME ACTIVE MAX", 23) == 0) {
2301 value = value + 24;
2302 temp = kstrtou32(value, 10, &val);
2303 if (temp != 0 || val < CFG_ACTIVE_MAX_CHANNEL_TIME_MIN ||
2304 val > CFG_ACTIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002305 hdd_err("argument passed for SETDWELLTIME ACTIVE MAX is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002306 return -EFAULT;
2307 }
2308 pCfg->nActiveMaxChnTime = val;
2309 smeConfig.csrConfig.nActiveMaxChnTime = val;
2310 sme_update_config(hHal, &smeConfig);
2311 } else if (strncmp(command, "SETDWELLTIME ACTIVE MIN", 23) == 0) {
2312 value = value + 24;
2313 temp = kstrtou32(value, 10, &val);
2314 if (temp != 0 || val < CFG_ACTIVE_MIN_CHANNEL_TIME_MIN ||
2315 val > CFG_ACTIVE_MIN_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002316 hdd_err("argument passed for SETDWELLTIME ACTIVE MIN is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002317 return -EFAULT;
2318 }
2319 pCfg->nActiveMinChnTime = val;
2320 smeConfig.csrConfig.nActiveMinChnTime = val;
2321 sme_update_config(hHal, &smeConfig);
2322 } else if (strncmp(command, "SETDWELLTIME PASSIVE MAX", 24) == 0) {
2323 value = value + 25;
2324 temp = kstrtou32(value, 10, &val);
2325 if (temp != 0 || val < CFG_PASSIVE_MAX_CHANNEL_TIME_MIN ||
2326 val > CFG_PASSIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002327 hdd_err("argument passed for SETDWELLTIME PASSIVE MAX is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002328 return -EFAULT;
2329 }
2330 pCfg->nPassiveMaxChnTime = val;
2331 smeConfig.csrConfig.nPassiveMaxChnTime = val;
2332 sme_update_config(hHal, &smeConfig);
2333 } else if (strncmp(command, "SETDWELLTIME PASSIVE MIN", 24) == 0) {
2334 value = value + 25;
2335 temp = kstrtou32(value, 10, &val);
2336 if (temp != 0 || val < CFG_PASSIVE_MIN_CHANNEL_TIME_MIN ||
2337 val > CFG_PASSIVE_MIN_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002338 hdd_err("argument passed for SETDWELLTIME PASSIVE MIN is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002339 return -EFAULT;
2340 }
2341 pCfg->nPassiveMinChnTime = val;
2342 smeConfig.csrConfig.nPassiveMinChnTime = val;
2343 sme_update_config(hHal, &smeConfig);
2344 } else if (strncmp(command, "SETDWELLTIME", 12) == 0) {
2345 value = value + 13;
2346 temp = kstrtou32(value, 10, &val);
2347 if (temp != 0 || val < CFG_ACTIVE_MAX_CHANNEL_TIME_MIN ||
2348 val > CFG_ACTIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002349 hdd_err("argument passed for SETDWELLTIME is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002350 return -EFAULT;
2351 }
2352 pCfg->nActiveMaxChnTime = val;
2353 smeConfig.csrConfig.nActiveMaxChnTime = val;
2354 sme_update_config(hHal, &smeConfig);
2355 } else {
2356 return -EINVAL;
2357 }
2358
2359 return 0;
2360}
2361
2362static void hdd_get_link_status_cb(uint8_t status, void *context)
2363{
2364 struct statsContext *pLinkContext;
2365 hdd_adapter_t *adapter;
2366
2367 if (NULL == context) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002368 hdd_err("Bad context [%p]", context);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002369 return;
2370 }
2371
2372 pLinkContext = context;
2373 adapter = pLinkContext->pAdapter;
2374
2375 spin_lock(&hdd_context_lock);
2376
2377 if ((NULL == adapter) ||
2378 (LINK_STATUS_MAGIC != pLinkContext->magic)) {
2379 /*
2380 * the caller presumably timed out so there is
2381 * nothing we can do
2382 */
2383 spin_unlock(&hdd_context_lock);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002384 hdd_warn("Invalid context, adapter [%p] magic [%08x]",
2385 adapter, pLinkContext->magic);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002386 return;
2387 }
2388
2389 /* context is valid so caller is still waiting */
2390
2391 /* paranoia: invalidate the magic */
2392 pLinkContext->magic = 0;
2393
2394 /* copy over the status */
2395 adapter->linkStatus = status;
2396
2397 /* notify the caller */
2398 complete(&pLinkContext->completion);
2399
2400 /* serialization is complete */
2401 spin_unlock(&hdd_context_lock);
2402}
2403
2404/**
2405 * wlan_hdd_get_link_status() - get link status
2406 * @pAdapter: pointer to the adapter
2407 *
2408 * This function sends a request to query the link status and waits
2409 * on a timer to invoke the callback. if the callback is invoked then
2410 * latest link status shall be returned or otherwise cached value
2411 * will be returned.
2412 *
2413 * Return: On success, link status shall be returned.
2414 * On error or not associated, link status 0 will be returned.
2415 */
2416static int wlan_hdd_get_link_status(hdd_adapter_t *adapter)
2417{
2418
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002419 hdd_station_ctx_t *pHddStaCtx =
2420 WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Houston Hoffman59c097f2016-11-09 15:50:25 -08002421 static struct statsContext context;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302422 QDF_STATUS hstatus;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002423 unsigned long rc;
2424
Prashanth Bhatta9e143052015-12-04 11:56:47 -08002425 if (cds_is_driver_recovering()) {
2426 hdd_warn("Recovery in Progress. State: 0x%x Ignore!!!",
2427 cds_get_driver_state());
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002428 return 0;
2429 }
2430
Krunal Sonibe766b02016-03-10 13:00:44 -08002431 if ((QDF_STA_MODE != adapter->device_mode) &&
2432 (QDF_P2P_CLIENT_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002433 hdd_warn("Unsupported in mode %s(%d)",
2434 hdd_device_mode_to_string(adapter->device_mode),
2435 adapter->device_mode);
2436 return 0;
2437 }
2438
2439 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
2440 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
2441 /* If not associated, then expected link status return
2442 * value is 0
2443 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002444 hdd_info("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002445 return 0;
2446 }
2447
2448 init_completion(&context.completion);
2449 context.pAdapter = adapter;
2450 context.magic = LINK_STATUS_MAGIC;
2451 hstatus = sme_get_link_status(WLAN_HDD_GET_HAL_CTX(adapter),
2452 hdd_get_link_status_cb,
2453 &context, adapter->sessionId);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302454 if (QDF_STATUS_SUCCESS != hstatus) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002455 hdd_err("Unable to retrieve link status");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002456 /* return a cached value */
2457 } else {
2458 /* request is sent -- wait for the response */
2459 rc = wait_for_completion_timeout(&context.completion,
2460 msecs_to_jiffies(WLAN_WAIT_TIME_LINK_STATUS));
2461 if (!rc)
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002462 hdd_err("SME timed out while retrieving link status");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002463 }
2464
2465 spin_lock(&hdd_context_lock);
2466 context.magic = 0;
2467 spin_unlock(&hdd_context_lock);
2468
2469 /* either callback updated adapter stats or it has cached data */
2470 return adapter->linkStatus;
2471}
2472
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002473static void hdd_tx_fail_ind_callback(uint8_t *MacAddr, uint8_t seqNo)
2474{
2475 int payload_len;
2476 struct sk_buff *skb;
2477 struct nlmsghdr *nlh;
2478 uint8_t *data;
2479
2480 payload_len = ETH_ALEN;
2481
Ryan Hsu5e2e2052016-04-28 10:19:38 -07002482 if (0 == cesium_pid || cesium_nl_srv_sock == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002483 hdd_err("cesium process not registered");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002484 return;
2485 }
2486
2487 skb = nlmsg_new(payload_len, GFP_ATOMIC);
2488 if (skb == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002489 hdd_err("nlmsg_new() failed for msg size[%d]",
2490 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002491 return;
2492 }
2493
2494 nlh = nlmsg_put(skb, cesium_pid, seqNo, 0, payload_len, NLM_F_REQUEST);
2495
2496 if (NULL == nlh) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002497 hdd_err("nlmsg_put() failed for msg size[%d]",
2498 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002499
2500 kfree_skb(skb);
2501 return;
2502 }
2503
2504 data = nlmsg_data(nlh);
2505 memcpy(data, MacAddr, ETH_ALEN);
2506
2507 if (nlmsg_unicast(cesium_nl_srv_sock, skb, cesium_pid) < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002508 hdd_err("nlmsg_unicast() failed for msg size[%d]",
2509 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002510 }
2511
2512 return;
2513}
2514
2515
2516/**
2517 * hdd_ParseuserParams - return a pointer to the next argument
2518 * @pValue: Input argument string
2519 * @ppArg: Output pointer to the next argument
2520 *
2521 * This function parses argument stream and finds the pointer
2522 * to the next argument
2523 *
2524 * Return: 0 if the next argument found; -EINVAL otherwise
2525 */
2526static int hdd_parse_user_params(uint8_t *pValue, uint8_t **ppArg)
2527{
2528 uint8_t *pVal;
2529
2530 pVal = strnchr(pValue, strlen(pValue), ' ');
2531
2532 if (NULL == pVal) {
2533 /* no argument remains */
2534 return -EINVAL;
2535 } else if (SPACE_ASCII_VALUE != *pVal) {
2536 /* no space after the current argument */
2537 return -EINVAL;
2538 }
2539
2540 pVal++;
2541
2542 /* remove empty spaces */
2543 while ((SPACE_ASCII_VALUE == *pVal) && ('\0' != *pVal)) {
2544 pVal++;
2545 }
2546
2547 /* no argument followed by spaces */
2548 if ('\0' == *pVal) {
2549 return -EINVAL;
2550 }
2551
2552 *ppArg = pVal;
2553
2554 return 0;
2555}
2556
2557/**
2558 * hdd_parse_ibsstx_fail_event_params - Parse params
2559 * for SETIBSSTXFAILEVENT
2560 * @pValue: Input ibss tx fail event argument
2561 * @tx_fail_count: (Output parameter) Tx fail counter
2562 * @pid: (Output parameter) PID
2563 *
2564 * Return: 0 if the parsing succeeds; -EINVAL otherwise
2565 */
2566static int hdd_parse_ibsstx_fail_event_params(uint8_t *pValue,
2567 uint8_t *tx_fail_count,
2568 uint16_t *pid)
2569{
2570 uint8_t *param = NULL;
2571 int ret;
2572
2573 ret = hdd_parse_user_params(pValue, &param);
2574
2575 if (0 == ret && NULL != param) {
2576 if (1 != sscanf(param, "%hhu", tx_fail_count)) {
2577 ret = -EINVAL;
2578 goto done;
2579 }
2580 } else {
2581 goto done;
2582 }
2583
2584 if (0 == *tx_fail_count) {
2585 *pid = 0;
2586 goto done;
2587 }
2588
2589 pValue = param;
2590 pValue++;
2591
2592 ret = hdd_parse_user_params(pValue, &param);
2593
2594 if (0 == ret) {
2595 if (1 != sscanf(param, "%hu", pid)) {
2596 ret = -EINVAL;
2597 goto done;
2598 }
2599 } else {
2600 goto done;
2601 }
2602
2603done:
2604 return ret;
2605}
2606
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08002607#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002608/**
2609 * hdd_parse_ese_beacon_req() - Parse ese beacon request
2610 * @pValue: Pointer to data
2611 * @pEseBcnReq: Output pointer to store parsed ie information
2612 *
2613 * This function parses the ese beacon request passed in the format
2614 * CCXBEACONREQ<space><Number of fields><space><Measurement token>
2615 * <space>Channel 1<space>Scan Mode <space>Meas Duration<space>Channel N
2616 * <space>Scan Mode N<space>Meas Duration N
2617 *
2618 * If the Number of bcn req fields (N) does not match with the
2619 * actual number of fields passed then take N.
2620 * <Meas Token><Channel><Scan Mode> and <Meas Duration> are treated
2621 * as one pair. For example, CCXBEACONREQ 2 1 1 1 30 2 44 0 40.
2622 * This function does not take care of removing duplicate channels from the
2623 * list
2624 *
2625 * Return: 0 for success non-zero for failure
2626 */
2627static int hdd_parse_ese_beacon_req(uint8_t *pValue,
2628 tCsrEseBeaconReq *pEseBcnReq)
2629{
2630 uint8_t *inPtr = pValue;
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002631 uint8_t input = 0;
2632 uint32_t tempInt = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002633 int j = 0, i = 0, v = 0;
2634 char buf[32];
2635
2636 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2637 /* no argument after the command */
2638 if (NULL == inPtr) {
2639 return -EINVAL;
2640 }
2641 /* no space after the command */
2642 else if (SPACE_ASCII_VALUE != *inPtr) {
2643 return -EINVAL;
2644 }
2645
2646 /* remove empty spaces */
2647 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2648 inPtr++;
2649
2650 /* no argument followed by spaces */
2651 if ('\0' == *inPtr)
2652 return -EINVAL;
2653
Srinivas Girigowda476deeb2016-07-19 16:21:29 -07002654 /* Getting the first argument ie Number of IE fields */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002655 v = sscanf(inPtr, "%31s ", buf);
2656 if (1 != v)
2657 return -EINVAL;
2658
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002659 v = kstrtou8(buf, 10, &input);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002660 if (v < 0)
2661 return -EINVAL;
2662
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002663 input = QDF_MIN(input, SIR_ESE_MAX_MEAS_IE_REQS);
2664 pEseBcnReq->numBcnReqIe = input;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002665
Srinivas Girigowda476deeb2016-07-19 16:21:29 -07002666 hdd_info("Number of Bcn Req Ie fields: %d", pEseBcnReq->numBcnReqIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002667
2668 for (j = 0; j < (pEseBcnReq->numBcnReqIe); j++) {
2669 for (i = 0; i < 4; i++) {
2670 /*
2671 * inPtr pointing to the beginning of 1st space
2672 * after number of ie fields
2673 */
2674 inPtr = strpbrk(inPtr, " ");
2675 /* no ie data after the number of ie fields argument */
2676 if (NULL == inPtr)
2677 return -EINVAL;
2678
2679 /* remove empty space */
2680 while ((SPACE_ASCII_VALUE == *inPtr)
2681 && ('\0' != *inPtr))
2682 inPtr++;
2683
2684 /*
2685 * no ie data after the number of ie fields
2686 * argument and spaces
2687 */
2688 if ('\0' == *inPtr)
2689 return -EINVAL;
2690
2691 v = sscanf(inPtr, "%31s ", buf);
2692 if (1 != v)
2693 return -EINVAL;
2694
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002695 v = kstrtou32(buf, 10, &tempInt);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002696 if (v < 0)
2697 return -EINVAL;
2698
2699 switch (i) {
2700 case 0: /* Measurement token */
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002701 if (!tempInt) {
2702 hdd_err("Invalid Measurement Token: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002703 tempInt);
2704 return -EINVAL;
2705 }
2706 pEseBcnReq->bcnReq[j].measurementToken =
2707 tempInt;
2708 break;
2709
2710 case 1: /* Channel number */
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002711 if (!tempInt ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002712 (tempInt >
2713 WNI_CFG_CURRENT_CHANNEL_STAMAX)) {
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002714 hdd_err("Invalid Channel Number: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002715 tempInt);
2716 return -EINVAL;
2717 }
2718 pEseBcnReq->bcnReq[j].channel = tempInt;
2719 break;
2720
2721 case 2: /* Scan mode */
2722 if ((tempInt < eSIR_PASSIVE_SCAN)
2723 || (tempInt > eSIR_BEACON_TABLE)) {
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002724 hdd_err("Invalid Scan Mode: %u Expected{0|1|2}",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002725 tempInt);
2726 return -EINVAL;
2727 }
2728 pEseBcnReq->bcnReq[j].scanMode = tempInt;
2729 break;
2730
2731 case 3: /* Measurement duration */
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002732 if ((!tempInt
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002733 && (pEseBcnReq->bcnReq[j].scanMode !=
2734 eSIR_BEACON_TABLE)) ||
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002735 (pEseBcnReq->bcnReq[j].scanMode ==
2736 eSIR_BEACON_TABLE)) {
2737 hdd_err("Invalid Measurement Duration: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002738 tempInt);
2739 return -EINVAL;
2740 }
2741 pEseBcnReq->bcnReq[j].measurementDuration =
2742 tempInt;
2743 break;
2744 }
2745 }
2746 }
2747
2748 for (j = 0; j < pEseBcnReq->numBcnReqIe; j++) {
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002749 hdd_info("Index: %d Measurement Token: %u Channel: %u Scan Mode: %u Measurement Duration: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002750 j,
2751 pEseBcnReq->bcnReq[j].measurementToken,
2752 pEseBcnReq->bcnReq[j].channel,
2753 pEseBcnReq->bcnReq[j].scanMode,
2754 pEseBcnReq->bcnReq[j].measurementDuration);
2755 }
2756
2757 return 0;
2758}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002759
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002760/**
2761 * hdd_parse_get_cckm_ie() - HDD Parse and fetch the CCKM IE
2762 * @pValue: Pointer to input data
2763 * @pCckmIe: Pointer to output cckm Ie
2764 * @pCckmIeLen: Pointer to output cckm ie length
2765 *
2766 * This function parses the SETCCKM IE command
2767 * SETCCKMIE<space><ie data>
2768 *
2769 * Return: 0 for success non-zero for failure
2770 */
2771static int hdd_parse_get_cckm_ie(uint8_t *pValue, uint8_t **pCckmIe,
2772 uint8_t *pCckmIeLen)
2773{
2774 uint8_t *inPtr = pValue;
2775 uint8_t *dataEnd;
2776 int j = 0;
2777 int i = 0;
2778 uint8_t tempByte = 0;
2779 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2780 /* no argument after the command */
2781 if (NULL == inPtr) {
2782 return -EINVAL;
2783 }
2784 /* no space after the command */
2785 else if (SPACE_ASCII_VALUE != *inPtr) {
2786 return -EINVAL;
2787 }
2788 /* remove empty spaces */
2789 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2790 inPtr++;
2791 /* no argument followed by spaces */
2792 if ('\0' == *inPtr) {
2793 return -EINVAL;
2794 }
2795 /* find the length of data */
2796 dataEnd = inPtr;
2797 while (('\0' != *dataEnd)) {
2798 dataEnd++;
2799 ++(*pCckmIeLen);
2800 }
2801 if (*pCckmIeLen <= 0)
2802 return -EINVAL;
2803 /*
2804 * Allocate the number of bytes based on the number of input characters
2805 * whether it is even or odd.
2806 * if the number of input characters are even, then we need N / 2 byte.
2807 * if the number of input characters are odd, then we need do
2808 * (N + 1) / 2 to compensate rounding off.
2809 * For example, if N = 18, then (18 + 1) / 2 = 9 bytes are enough.
2810 * If N = 19, then we need 10 bytes, hence (19 + 1) / 2 = 10 bytes
2811 */
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302812 *pCckmIe = qdf_mem_malloc((*pCckmIeLen + 1) / 2);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002813 if (NULL == *pCckmIe) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002814 hdd_err("qdf_mem_malloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002815 return -ENOMEM;
2816 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002817 /*
2818 * the buffer received from the upper layer is character buffer,
2819 * we need to prepare the buffer taking 2 characters in to a U8 hex
2820 * decimal number for example 7f0000f0...form a buffer to contain
2821 * 7f in 0th location, 00 in 1st and f0 in 3rd location
2822 */
2823 for (i = 0, j = 0; j < *pCckmIeLen; j += 2) {
2824 tempByte = (hex_to_bin(inPtr[j]) << 4) |
2825 (hex_to_bin(inPtr[j + 1]));
2826 (*pCckmIe)[i++] = tempByte;
2827 }
2828 *pCckmIeLen = i;
2829 return 0;
2830}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08002831#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002832
2833int wlan_hdd_set_mc_rate(hdd_adapter_t *pAdapter, int targetRate)
2834{
2835 tSirRateUpdateInd rateUpdate = {0};
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302836 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002837 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
2838 struct hdd_config *pConfig = NULL;
2839
2840 if (pHddCtx == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002841 hdd_err("HDD context is null");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002842 return -EINVAL;
2843 }
Krunal Sonibe766b02016-03-10 13:00:44 -08002844 if ((QDF_IBSS_MODE != pAdapter->device_mode) &&
2845 (QDF_SAP_MODE != pAdapter->device_mode) &&
2846 (QDF_STA_MODE != pAdapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002847 hdd_err("Received SETMCRATE cmd in invalid mode %s(%d)",
2848 hdd_device_mode_to_string(pAdapter->device_mode),
2849 pAdapter->device_mode);
2850 hdd_err("SETMCRATE cmd is allowed only in STA, IBSS or SOFTAP mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002851 return -EINVAL;
2852 }
2853 pConfig = pHddCtx->config;
2854 rateUpdate.nss = (pConfig->enable2x2 == 0) ? 0 : 1;
2855 rateUpdate.dev_mode = pAdapter->device_mode;
2856 rateUpdate.mcastDataRate24GHz = targetRate;
2857 rateUpdate.mcastDataRate24GHzTxFlag = 1;
2858 rateUpdate.mcastDataRate5GHz = targetRate;
2859 rateUpdate.bcastDataRate = -1;
Anurag Chouhanc5548422016-02-24 18:33:27 +05302860 qdf_copy_macaddr(&rateUpdate.bssid, &pAdapter->macAddressCurrent);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002861 hdd_info("MC Target rate %d, mac = %pM, dev_mode %s(%d)",
2862 rateUpdate.mcastDataRate24GHz, rateUpdate.bssid.bytes,
2863 hdd_device_mode_to_string(pAdapter->device_mode),
2864 pAdapter->device_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002865 status = sme_send_rate_update_ind(pHddCtx->hHal, &rateUpdate);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302866 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002867 hdd_err("SETMCRATE failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002868 return -EFAULT;
2869 }
2870 return 0;
2871}
2872
2873static int drv_cmd_p2p_dev_addr(hdd_adapter_t *adapter,
2874 hdd_context_t *hdd_ctx,
2875 uint8_t *command,
2876 uint8_t command_len,
2877 hdd_priv_data_t *priv_data)
2878{
2879 int ret = 0;
2880
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302881 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002882 TRACE_CODE_HDD_P2P_DEV_ADDR_IOCTL,
2883 adapter->sessionId,
2884 (unsigned)(*(hdd_ctx->p2pDeviceAddress.bytes + 2)
2885 << 24 | *(hdd_ctx->p2pDeviceAddress.bytes
2886 + 3) << 16 | *(hdd_ctx->
2887 p2pDeviceAddress.bytes + 4) << 8 |
2888 *(hdd_ctx->p2pDeviceAddress.bytes +
2889 5))));
2890
2891 if (copy_to_user(priv_data->buf, hdd_ctx->p2pDeviceAddress.bytes,
2892 sizeof(tSirMacAddr))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002893 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002894 ret = -EFAULT;
2895 }
2896
2897 return ret;
2898}
2899
2900/**
2901 * drv_cmd_p2p_set_noa() - Handler for P2P_SET_NOA driver command
2902 * @adapter: Adapter on which the command was received
2903 * @hdd_ctx: HDD global context
2904 * @command: Entire driver command received from userspace
2905 * @command_len: Length of @command
2906 * @priv_data: Pointer to ioctl private data structure
2907 *
2908 * This is a trivial command hander function which simply forwards the
2909 * command to the actual command processor within the P2P module.
2910 *
2911 * Return: 0 on success, non-zero on failure
2912 */
2913static int drv_cmd_p2p_set_noa(hdd_adapter_t *adapter,
2914 hdd_context_t *hdd_ctx,
2915 uint8_t *command,
2916 uint8_t command_len,
2917 hdd_priv_data_t *priv_data)
2918{
2919 return hdd_set_p2p_noa(adapter->dev, command);
2920}
2921
2922/**
2923 * drv_cmd_p2p_set_ps() - Handler for P2P_SET_PS driver command
2924 * @adapter: Adapter on which the command was received
2925 * @hdd_ctx: HDD global context
2926 * @command: Entire driver command received from userspace
2927 * @command_len: Length of @command
2928 * @priv_data: Pointer to ioctl private data structure
2929 *
2930 * This is a trivial command hander function which simply forwards the
2931 * command to the actual command processor within the P2P module.
2932 *
2933 * Return: 0 on success, non-zero on failure
2934 */
2935static int drv_cmd_p2p_set_ps(hdd_adapter_t *adapter,
2936 hdd_context_t *hdd_ctx,
2937 uint8_t *command,
2938 uint8_t command_len,
2939 hdd_priv_data_t *priv_data)
2940{
2941 return hdd_set_p2p_opps(adapter->dev, command);
2942}
2943
2944static int drv_cmd_set_band(hdd_adapter_t *adapter,
2945 hdd_context_t *hdd_ctx,
2946 uint8_t *command,
2947 uint8_t command_len,
2948 hdd_priv_data_t *priv_data)
2949{
2950 int ret = 0;
2951
2952 uint8_t *ptr = command;
2953
2954 /* Change band request received */
2955
2956 /*
2957 * First 8 bytes will have "SETBAND " and
2958 * 9 byte will have band setting value
2959 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002960 hdd_info("SetBandCommand Info comm %s UL %d, TL %d",
2961 command, priv_data->used_len,
2962 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002963
2964 /* Change band request received */
2965 ret = hdd_set_band_helper(adapter->dev, ptr);
2966
2967 return ret;
2968}
2969
2970static int drv_cmd_set_wmmps(hdd_adapter_t *adapter,
2971 hdd_context_t *hdd_ctx,
2972 uint8_t *command,
2973 uint8_t command_len,
2974 hdd_priv_data_t *priv_data)
2975{
2976 return hdd_wmmps_helper(adapter, command);
2977}
2978
2979static int drv_cmd_country(hdd_adapter_t *adapter,
2980 hdd_context_t *hdd_ctx,
2981 uint8_t *command,
2982 uint8_t command_len,
2983 hdd_priv_data_t *priv_data)
2984{
2985 int ret = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302986 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002987 unsigned long rc;
2988 char *country_code;
2989
2990 country_code = command + 8;
2991
2992 INIT_COMPLETION(adapter->change_country_code);
2993
2994 status = sme_change_country_code(hdd_ctx->hHal,
2995 wlan_hdd_change_country_code_callback,
2996 country_code,
2997 adapter,
2998 hdd_ctx->pcds_context,
2999 eSIR_TRUE,
3000 eSIR_TRUE);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303001 if (status == QDF_STATUS_SUCCESS) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003002 rc = wait_for_completion_timeout(
3003 &adapter->change_country_code,
3004 msecs_to_jiffies(WLAN_WAIT_TIME_COUNTRY));
3005 if (!rc)
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003006 hdd_err("SME while setting country code timed out");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003007 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003008 hdd_err("SME Change Country code fail, status %d",
3009 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003010 ret = -EINVAL;
3011 }
3012
3013 return ret;
3014}
3015
3016static int drv_cmd_set_roam_trigger(hdd_adapter_t *adapter,
3017 hdd_context_t *hdd_ctx,
3018 uint8_t *command,
3019 uint8_t command_len,
3020 hdd_priv_data_t *priv_data)
3021{
3022 int ret = 0;
3023 uint8_t *value = command;
3024 int8_t rssi = 0;
3025 uint8_t lookUpThreshold = CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_DEFAULT;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303026 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003027
3028 /* Move pointer to ahead of SETROAMTRIGGER<delimiter> */
3029 value = value + command_len + 1;
3030
3031 /* Convert the value from ascii to integer */
3032 ret = kstrtos8(value, 10, &rssi);
3033 if (ret < 0) {
3034 /*
3035 * If the input value is greater than max value of datatype,
3036 * then also kstrtou8 fails
3037 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003038 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
3039 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN,
3040 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003041 ret = -EINVAL;
3042 goto exit;
3043 }
3044
3045 lookUpThreshold = abs(rssi);
3046
3047 if ((lookUpThreshold < CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN)
3048 || (lookUpThreshold > CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003049 hdd_err("Neighbor lookup threshold value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003050 lookUpThreshold,
3051 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN,
3052 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX);
3053 ret = -EINVAL;
3054 goto exit;
3055 }
3056
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303057 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003058 TRACE_CODE_HDD_SETROAMTRIGGER_IOCTL,
3059 adapter->sessionId, lookUpThreshold));
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003060 hdd_info("Received Command to Set Roam trigger (Neighbor lookup threshold) = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003061 lookUpThreshold);
3062
3063 hdd_ctx->config->nNeighborLookupRssiThreshold = lookUpThreshold;
3064 status = sme_set_neighbor_lookup_rssi_threshold(hdd_ctx->hHal,
3065 adapter->sessionId,
3066 lookUpThreshold);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303067 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003068 hdd_err("Failed to set roam trigger, try again");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003069 ret = -EPERM;
3070 goto exit;
3071 }
3072
3073exit:
3074 return ret;
3075}
3076
3077static int drv_cmd_get_roam_trigger(hdd_adapter_t *adapter,
3078 hdd_context_t *hdd_ctx,
3079 uint8_t *command,
3080 uint8_t command_len,
3081 hdd_priv_data_t *priv_data)
3082{
3083 int ret = 0;
3084 uint8_t lookUpThreshold =
3085 sme_get_neighbor_lookup_rssi_threshold(hdd_ctx->hHal);
3086 int rssi = (-1) * lookUpThreshold;
3087 char extra[32];
3088 uint8_t len = 0;
3089
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303090 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003091 TRACE_CODE_HDD_GETROAMTRIGGER_IOCTL,
3092 adapter->sessionId, lookUpThreshold));
3093
3094 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303095 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003096 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003097 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003098 ret = -EFAULT;
3099 }
3100
3101 return ret;
3102}
3103
3104static int drv_cmd_set_roam_scan_period(hdd_adapter_t *adapter,
3105 hdd_context_t *hdd_ctx,
3106 uint8_t *command,
3107 uint8_t command_len,
3108 hdd_priv_data_t *priv_data)
3109{
3110 int ret = 0;
3111 uint8_t *value = command;
3112 uint8_t roamScanPeriod = 0;
3113 uint16_t neighborEmptyScanRefreshPeriod =
3114 CFG_EMPTY_SCAN_REFRESH_PERIOD_DEFAULT;
3115
3116 /* input refresh period is in terms of seconds */
3117
3118 /* Move pointer to ahead of SETROAMSCANPERIOD<delimiter> */
3119 value = value + command_len + 1;
3120
3121 /* Convert the value from ascii to integer */
3122 ret = kstrtou8(value, 10, &roamScanPeriod);
3123 if (ret < 0) {
3124 /*
3125 * If the input value is greater than max value of datatype,
3126 * then also kstrtou8 fails
3127 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003128 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
3129 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000),
3130 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003131 ret = -EINVAL;
3132 goto exit;
3133 }
3134
3135 if ((roamScanPeriod < (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000))
3136 || (roamScanPeriod > (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003137 hdd_err("Roam scan period value %d is out of range (Min: %d Max: %d)",
3138 roamScanPeriod,
3139 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000),
3140 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003141 ret = -EINVAL;
3142 goto exit;
3143 }
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303144 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003145 TRACE_CODE_HDD_SETROAMSCANPERIOD_IOCTL,
3146 adapter->sessionId, roamScanPeriod));
3147 neighborEmptyScanRefreshPeriod = roamScanPeriod * 1000;
3148
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003149 hdd_info("Received Command to Set roam scan period (Empty Scan refresh period) = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003150 roamScanPeriod);
3151
3152 hdd_ctx->config->nEmptyScanRefreshPeriod =
3153 neighborEmptyScanRefreshPeriod;
3154 sme_update_empty_scan_refresh_period(hdd_ctx->hHal,
3155 adapter->sessionId,
3156 neighborEmptyScanRefreshPeriod);
3157
3158exit:
3159 return ret;
3160}
3161
3162static int drv_cmd_get_roam_scan_period(hdd_adapter_t *adapter,
3163 hdd_context_t *hdd_ctx,
3164 uint8_t *command,
3165 uint8_t command_len,
3166 hdd_priv_data_t *priv_data)
3167{
3168 int ret = 0;
3169 uint16_t nEmptyScanRefreshPeriod =
3170 sme_get_empty_scan_refresh_period(hdd_ctx->hHal);
3171 char extra[32];
3172 uint8_t len = 0;
3173
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303174 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003175 TRACE_CODE_HDD_GETROAMSCANPERIOD_IOCTL,
3176 adapter->sessionId,
3177 nEmptyScanRefreshPeriod));
3178 len = scnprintf(extra, sizeof(extra), "%s %d",
3179 "GETROAMSCANPERIOD",
3180 (nEmptyScanRefreshPeriod / 1000));
3181 /* Returned value is in units of seconds */
Anurag Chouhan6d760662016-02-20 16:05:43 +05303182 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003183 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003184 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003185 ret = -EFAULT;
3186 }
3187
3188 return ret;
3189}
3190
3191static int drv_cmd_set_roam_scan_refresh_period(hdd_adapter_t *adapter,
3192 hdd_context_t *hdd_ctx,
3193 uint8_t *command,
3194 uint8_t command_len,
3195 hdd_priv_data_t *priv_data)
3196{
3197 int ret = 0;
3198 uint8_t *value = command;
3199 uint8_t roamScanRefreshPeriod = 0;
3200 uint16_t neighborScanRefreshPeriod =
3201 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_DEFAULT;
3202
3203 /* input refresh period is in terms of seconds */
3204 /* Move pointer to ahead of SETROAMSCANREFRESHPERIOD<delimiter> */
3205 value = value + command_len + 1;
3206
3207 /* Convert the value from ascii to integer */
3208 ret = kstrtou8(value, 10, &roamScanRefreshPeriod);
3209 if (ret < 0) {
3210 /*
3211 * If the input value is greater than max value of datatype,
3212 * then also kstrtou8 fails
3213 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003214 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
3215 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN / 1000,
3216 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX / 1000);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003217 ret = -EINVAL;
3218 goto exit;
3219 }
3220
3221 if ((roamScanRefreshPeriod <
3222 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN / 1000))
3223 || (roamScanRefreshPeriod >
3224 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX / 1000))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003225 hdd_err("Neighbor scan results refresh period value %d is out of range (Min: %d Max: %d)",
3226 roamScanRefreshPeriod,
3227 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN
3228 / 1000),
3229 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX
3230 / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003231 ret = -EINVAL;
3232 goto exit;
3233 }
3234 neighborScanRefreshPeriod = roamScanRefreshPeriod * 1000;
3235
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003236 hdd_info("Received Command to Set roam scan refresh period (Scan refresh period) = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003237 roamScanRefreshPeriod);
3238
3239 hdd_ctx->config->nNeighborResultsRefreshPeriod =
3240 neighborScanRefreshPeriod;
3241 sme_set_neighbor_scan_refresh_period(hdd_ctx->hHal,
3242 adapter->sessionId,
3243 neighborScanRefreshPeriod);
3244
3245exit:
3246 return ret;
3247}
3248
3249static int drv_cmd_get_roam_scan_refresh_period(hdd_adapter_t *adapter,
3250 hdd_context_t *hdd_ctx,
3251 uint8_t *command,
3252 uint8_t command_len,
3253 hdd_priv_data_t *priv_data)
3254{
3255 int ret = 0;
3256 uint16_t value =
3257 sme_get_neighbor_scan_refresh_period(hdd_ctx->hHal);
3258 char extra[32];
3259 uint8_t len = 0;
3260
3261 len = scnprintf(extra, sizeof(extra), "%s %d",
3262 "GETROAMSCANREFRESHPERIOD",
3263 (value / 1000));
3264 /* Returned value is in units of seconds */
Anurag Chouhan6d760662016-02-20 16:05:43 +05303265 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003266 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003267 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003268 ret = -EFAULT;
3269 }
3270
3271 return ret;
3272}
3273
3274static int drv_cmd_set_roam_mode(hdd_adapter_t *adapter,
3275 hdd_context_t *hdd_ctx,
3276 uint8_t *command,
3277 uint8_t command_len,
3278 hdd_priv_data_t *priv_data)
3279{
3280 int ret = 0;
3281 uint8_t *value = command;
3282 uint8_t roamMode = CFG_LFR_FEATURE_ENABLED_DEFAULT;
3283
3284 /* Move pointer to ahead of SETROAMMODE<delimiter> */
3285 value = value + SIZE_OF_SETROAMMODE + 1;
3286
3287 /* Convert the value from ascii to integer */
3288 ret = kstrtou8(value, SIZE_OF_SETROAMMODE, &roamMode);
3289 if (ret < 0) {
3290 /*
3291 * If the input value is greater than max value of datatype,
3292 * then also kstrtou8 fails
3293 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003294 hdd_err("kstrtou8 failed range [%d - %d]",
3295 CFG_LFR_FEATURE_ENABLED_MIN,
3296 CFG_LFR_FEATURE_ENABLED_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003297 ret = -EINVAL;
3298 goto exit;
3299 }
3300 if ((roamMode < CFG_LFR_FEATURE_ENABLED_MIN) ||
3301 (roamMode > CFG_LFR_FEATURE_ENABLED_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003302 hdd_err("Roam Mode value %d is out of range (Min: %d Max: %d)",
3303 roamMode,
3304 CFG_LFR_FEATURE_ENABLED_MIN,
3305 CFG_LFR_FEATURE_ENABLED_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003306 ret = -EINVAL;
3307 goto exit;
3308 }
3309
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003310 hdd_debug("Received Command to Set Roam Mode = %d",
3311 roamMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003312 /*
3313 * Note that
3314 * SETROAMMODE 0 is to enable LFR while
3315 * SETROAMMODE 1 is to disable LFR, but
3316 * notify_is_fast_roam_ini_feature_enabled 0/1 is to
3317 * enable/disable. So, we have to invert the value
3318 * to call sme_update_is_fast_roam_ini_feature_enabled.
3319 */
3320 if (CFG_LFR_FEATURE_ENABLED_MIN == roamMode)
3321 roamMode = CFG_LFR_FEATURE_ENABLED_MAX; /* Roam enable */
3322 else
3323 roamMode = CFG_LFR_FEATURE_ENABLED_MIN; /* Roam disable */
3324
3325 hdd_ctx->config->isFastRoamIniFeatureEnabled = roamMode;
3326 if (roamMode) {
3327 hdd_ctx->config->isRoamOffloadScanEnabled = roamMode;
3328 sme_update_roam_scan_offload_enabled(
3329 (tHalHandle)(hdd_ctx->hHal),
3330 hdd_ctx->config->isRoamOffloadScanEnabled);
3331 sme_update_is_fast_roam_ini_feature_enabled(
3332 hdd_ctx->hHal,
3333 adapter->sessionId,
3334 roamMode);
3335 } else {
3336 sme_update_is_fast_roam_ini_feature_enabled(
3337 hdd_ctx->hHal,
3338 adapter->sessionId,
3339 roamMode);
3340 hdd_ctx->config->isRoamOffloadScanEnabled = roamMode;
3341 sme_update_roam_scan_offload_enabled(
3342 (tHalHandle)(hdd_ctx->hHal),
3343 hdd_ctx->config->isRoamOffloadScanEnabled);
3344 }
3345
3346
3347exit:
3348 return ret;
3349}
3350
3351static int drv_cmd_get_roam_mode(hdd_adapter_t *adapter,
3352 hdd_context_t *hdd_ctx,
3353 uint8_t *command,
3354 uint8_t command_len,
3355 hdd_priv_data_t *priv_data)
3356{
3357 int ret = 0;
3358 bool roamMode = sme_get_is_lfr_feature_enabled(hdd_ctx->hHal);
3359 char extra[32];
3360 uint8_t len = 0;
3361
3362 /*
3363 * roamMode value shall be inverted because the sementics is different.
3364 */
3365 if (CFG_LFR_FEATURE_ENABLED_MIN == roamMode)
3366 roamMode = CFG_LFR_FEATURE_ENABLED_MAX;
3367 else
3368 roamMode = CFG_LFR_FEATURE_ENABLED_MIN;
3369
3370 len = scnprintf(extra, sizeof(extra), "%s %d", command, roamMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303371 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003372 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003373 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003374 ret = -EFAULT;
3375 }
3376
3377 return ret;
3378}
3379
3380static int drv_cmd_set_roam_delta(hdd_adapter_t *adapter,
3381 hdd_context_t *hdd_ctx,
3382 uint8_t *command,
3383 uint8_t command_len,
3384 hdd_priv_data_t *priv_data)
3385{
3386 int ret = 0;
3387 uint8_t *value = command;
3388 uint8_t roamRssiDiff = CFG_ROAM_RSSI_DIFF_DEFAULT;
3389
3390 /* Move pointer to ahead of SETROAMDELTA<delimiter> */
3391 value = value + command_len + 1;
3392
3393 /* Convert the value from ascii to integer */
3394 ret = kstrtou8(value, 10, &roamRssiDiff);
3395 if (ret < 0) {
3396 /*
3397 * If the input value is greater than max value of datatype,
3398 * then also kstrtou8 fails
3399 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003400 hdd_err("kstrtou8 failed range [%d - %d]",
3401 CFG_ROAM_RSSI_DIFF_MIN,
3402 CFG_ROAM_RSSI_DIFF_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003403 ret = -EINVAL;
3404 goto exit;
3405 }
3406
3407 if ((roamRssiDiff < CFG_ROAM_RSSI_DIFF_MIN) ||
3408 (roamRssiDiff > CFG_ROAM_RSSI_DIFF_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003409 hdd_err("Roam rssi diff value %d is out of range (Min: %d Max: %d)",
3410 roamRssiDiff,
3411 CFG_ROAM_RSSI_DIFF_MIN,
3412 CFG_ROAM_RSSI_DIFF_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003413 ret = -EINVAL;
3414 goto exit;
3415 }
3416
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003417 hdd_info("Received Command to Set roam rssi diff = %d",
3418 roamRssiDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003419
3420 hdd_ctx->config->RoamRssiDiff = roamRssiDiff;
3421 sme_update_roam_rssi_diff(hdd_ctx->hHal,
3422 adapter->sessionId,
3423 roamRssiDiff);
3424
3425exit:
3426 return ret;
3427}
3428
3429static int drv_cmd_get_roam_delta(hdd_adapter_t *adapter,
3430 hdd_context_t *hdd_ctx,
3431 uint8_t *command,
3432 uint8_t command_len,
3433 hdd_priv_data_t *priv_data)
3434{
3435 int ret = 0;
3436 uint8_t roamRssiDiff =
3437 sme_get_roam_rssi_diff(hdd_ctx->hHal);
3438 char extra[32];
3439 uint8_t len = 0;
3440
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303441 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003442 TRACE_CODE_HDD_GETROAMDELTA_IOCTL,
3443 adapter->sessionId, roamRssiDiff));
3444
3445 len = scnprintf(extra, sizeof(extra), "%s %d",
3446 command, roamRssiDiff);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303447 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003448
3449 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003450 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003451 ret = -EFAULT;
3452 }
3453
3454 return ret;
3455}
3456
3457static int drv_cmd_get_band(hdd_adapter_t *adapter,
3458 hdd_context_t *hdd_ctx,
3459 uint8_t *command,
3460 uint8_t command_len,
3461 hdd_priv_data_t *priv_data)
3462{
3463 int ret = 0;
3464 int band = -1;
3465 char extra[32];
3466 uint8_t len = 0;
3467
3468 hdd_get_band_helper(hdd_ctx, &band);
3469
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303470 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003471 TRACE_CODE_HDD_GETBAND_IOCTL,
3472 adapter->sessionId, band));
3473
3474 len = scnprintf(extra, sizeof(extra), "%s %d", command, band);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303475 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003476
3477 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003478 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003479 ret = -EFAULT;
3480 }
3481
3482 return ret;
3483}
3484
3485static int drv_cmd_set_roam_scan_channels(hdd_adapter_t *adapter,
3486 hdd_context_t *hdd_ctx,
3487 uint8_t *command,
3488 uint8_t command_len,
3489 hdd_priv_data_t *priv_data)
3490{
3491 return hdd_parse_set_roam_scan_channels(adapter, command);
3492}
3493
3494static int drv_cmd_get_roam_scan_channels(hdd_adapter_t *adapter,
3495 hdd_context_t *hdd_ctx,
3496 uint8_t *command,
3497 uint8_t command_len,
3498 hdd_priv_data_t *priv_data)
3499{
3500 int ret = 0;
3501 uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
3502 uint8_t numChannels = 0;
3503 uint8_t j = 0;
3504 char extra[128] = { 0 };
3505 int len;
3506
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303507 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003508 sme_get_roam_scan_channel_list(hdd_ctx->hHal,
3509 ChannelList,
3510 &numChannels,
3511 adapter->sessionId)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003512 hdd_alert("failed to get roam scan channel list");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003513 ret = -EFAULT;
3514 goto exit;
3515 }
3516
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303517 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003518 TRACE_CODE_HDD_GETROAMSCANCHANNELS_IOCTL,
3519 adapter->sessionId, numChannels));
3520 /*
3521 * output channel list is of the format
3522 * [Number of roam scan channels][Channel1][Channel2]...
3523 * copy the number of channels in the 0th index
3524 */
3525 len = scnprintf(extra, sizeof(extra), "%s %d", command,
3526 numChannels);
Selvaraj, Sridhar5cc4af42016-10-19 10:41:59 +05303527 for (j = 0; (j < numChannels) && len <= sizeof(extra); j++)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003528 len += scnprintf(extra + len, sizeof(extra) - len,
3529 " %d", ChannelList[j]);
3530
Anurag Chouhan6d760662016-02-20 16:05:43 +05303531 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003532 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003533 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003534 ret = -EFAULT;
3535 goto exit;
3536 }
3537
3538exit:
3539 return ret;
3540}
3541
3542static int drv_cmd_get_ccx_mode(hdd_adapter_t *adapter,
3543 hdd_context_t *hdd_ctx,
3544 uint8_t *command,
3545 uint8_t command_len,
3546 hdd_priv_data_t *priv_data)
3547{
3548 int ret = 0;
3549 bool eseMode = sme_get_is_ese_feature_enabled(hdd_ctx->hHal);
3550 char extra[32];
3551 uint8_t len = 0;
3552
3553 /*
3554 * Check if the features OKC/ESE/11R are supported simultaneously,
3555 * then this operation is not permitted (return FAILURE)
3556 */
3557 if (eseMode &&
3558 hdd_is_okc_mode_enabled(hdd_ctx) &&
3559 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003560 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003561 ret = -EPERM;
3562 goto exit;
3563 }
3564
3565 len = scnprintf(extra, sizeof(extra), "%s %d",
3566 "GETCCXMODE", eseMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303567 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003568 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003569 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003570 ret = -EFAULT;
3571 goto exit;
3572 }
3573
3574exit:
3575 return ret;
3576}
3577
3578static int drv_cmd_get_okc_mode(hdd_adapter_t *adapter,
3579 hdd_context_t *hdd_ctx,
3580 uint8_t *command,
3581 uint8_t command_len,
3582 hdd_priv_data_t *priv_data)
3583{
3584 int ret = 0;
3585 bool okcMode = hdd_is_okc_mode_enabled(hdd_ctx);
3586 char extra[32];
3587 uint8_t len = 0;
3588
3589 /*
3590 * Check if the features OKC/ESE/11R are supported simultaneously,
3591 * then this operation is not permitted (return FAILURE)
3592 */
3593 if (okcMode &&
3594 sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
3595 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003596 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003597 ret = -EPERM;
3598 goto exit;
3599 }
3600
3601 len = scnprintf(extra, sizeof(extra), "%s %d",
3602 "GETOKCMODE", okcMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303603 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003604
3605 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003606 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003607 ret = -EFAULT;
3608 goto exit;
3609 }
3610
3611exit:
3612 return ret;
3613}
3614
3615static int drv_cmd_get_fast_roam(hdd_adapter_t *adapter,
3616 hdd_context_t *hdd_ctx,
3617 uint8_t *command,
3618 uint8_t command_len,
3619 hdd_priv_data_t *priv_data)
3620{
3621 int ret = 0;
3622 bool lfrMode = sme_get_is_lfr_feature_enabled(hdd_ctx->hHal);
3623 char extra[32];
3624 uint8_t len = 0;
3625
3626 len = scnprintf(extra, sizeof(extra), "%s %d",
3627 "GETFASTROAM", lfrMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303628 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003629
3630 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003631 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003632 ret = -EFAULT;
3633 }
3634
3635 return ret;
3636}
3637
3638static int drv_cmd_get_fast_transition(hdd_adapter_t *adapter,
3639 hdd_context_t *hdd_ctx,
3640 uint8_t *command,
3641 uint8_t command_len,
3642 hdd_priv_data_t *priv_data)
3643{
3644 int ret = 0;
3645 bool ft = sme_get_is_ft_feature_enabled(hdd_ctx->hHal);
3646 char extra[32];
3647 uint8_t len = 0;
3648
3649 len = scnprintf(extra, sizeof(extra), "%s %d",
3650 "GETFASTTRANSITION", ft);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303651 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003652
3653 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003654 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003655 ret = -EFAULT;
3656 }
3657
3658 return ret;
3659}
3660
3661static int drv_cmd_set_roam_scan_channel_min_time(hdd_adapter_t *adapter,
3662 hdd_context_t *hdd_ctx,
3663 uint8_t *command,
3664 uint8_t command_len,
3665 hdd_priv_data_t *priv_data)
3666{
3667 int ret = 0;
3668 uint8_t *value = command;
3669 uint8_t minTime = CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_DEFAULT;
3670
3671 /* Move pointer to ahead of SETROAMSCANCHANNELMINTIME<delimiter> */
3672 value = value + command_len + 1;
3673
3674 /* Convert the value from ascii to integer */
3675 ret = kstrtou8(value, 10, &minTime);
3676 if (ret < 0) {
3677 /*
3678 * If the input value is greater than max value of datatype,
3679 * then also kstrtou8 fails
3680 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003681 hdd_err("kstrtou8 failed range [%d - %d]",
3682 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN,
3683 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003684 ret = -EINVAL;
3685 goto exit;
3686 }
3687
3688 if ((minTime < CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN) ||
3689 (minTime > CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003690 hdd_err("scan min channel time value %d is out of range (Min: %d Max: %d)",
3691 minTime,
3692 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN,
3693 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003694 ret = -EINVAL;
3695 goto exit;
3696 }
3697
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303698 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003699 TRACE_CODE_HDD_SETROAMSCANCHANNELMINTIME_IOCTL,
3700 adapter->sessionId, minTime));
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003701 hdd_info("Received Command to change channel min time = %d",
3702 minTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003703
3704 hdd_ctx->config->nNeighborScanMinChanTime = minTime;
3705 sme_set_neighbor_scan_min_chan_time(hdd_ctx->hHal,
3706 minTime,
3707 adapter->sessionId);
3708
3709exit:
3710 return ret;
3711}
3712
3713static int drv_cmd_send_action_frame(hdd_adapter_t *adapter,
3714 hdd_context_t *hdd_ctx,
3715 uint8_t *command,
3716 uint8_t command_len,
3717 hdd_priv_data_t *priv_data)
3718{
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07003719 return hdd_parse_sendactionframe(adapter, command,
3720 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003721}
3722
3723static int drv_cmd_get_roam_scan_channel_min_time(hdd_adapter_t *adapter,
3724 hdd_context_t *hdd_ctx,
3725 uint8_t *command,
3726 uint8_t command_len,
3727 hdd_priv_data_t *priv_data)
3728{
3729 int ret = 0;
3730 uint16_t val = sme_get_neighbor_scan_min_chan_time(hdd_ctx->hHal,
3731 adapter->sessionId);
3732 char extra[32];
3733 uint8_t len = 0;
3734
3735 /* value is interms of msec */
3736 len = scnprintf(extra, sizeof(extra), "%s %d",
3737 "GETROAMSCANCHANNELMINTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303738 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003739
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303740 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003741 TRACE_CODE_HDD_GETROAMSCANCHANNELMINTIME_IOCTL,
3742 adapter->sessionId, val));
3743
3744 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003745 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003746 ret = -EFAULT;
3747 }
3748
3749 return ret;
3750}
3751
3752static int drv_cmd_set_scan_channel_time(hdd_adapter_t *adapter,
3753 hdd_context_t *hdd_ctx,
3754 uint8_t *command,
3755 uint8_t command_len,
3756 hdd_priv_data_t *priv_data)
3757{
3758 int ret = 0;
3759 uint8_t *value = command;
3760 uint16_t maxTime = CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_DEFAULT;
3761
3762 /* Move pointer to ahead of SETSCANCHANNELTIME<delimiter> */
3763 value = value + command_len + 1;
3764
3765 /* Convert the value from ascii to integer */
3766 ret = kstrtou16(value, 10, &maxTime);
3767 if (ret < 0) {
3768 /*
3769 * If the input value is greater than max value of datatype,
3770 * then also kstrtou8 fails
3771 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003772 hdd_err("kstrtou16 failed range [%d - %d]",
3773 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN,
3774 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003775 ret = -EINVAL;
3776 goto exit;
3777 }
3778
3779 if ((maxTime < CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN) ||
3780 (maxTime > CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003781 hdd_err("lfr mode value %d is out of range (Min: %d Max: %d)",
3782 maxTime,
3783 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN,
3784 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003785 ret = -EINVAL;
3786 goto exit;
3787 }
3788
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003789 hdd_info("Received Command to change channel max time = %d",
3790 maxTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003791
3792 hdd_ctx->config->nNeighborScanMaxChanTime = maxTime;
3793 sme_set_neighbor_scan_max_chan_time(hdd_ctx->hHal,
3794 adapter->sessionId,
3795 maxTime);
3796
3797exit:
3798 return ret;
3799}
3800
3801static int drv_cmd_get_scan_channel_time(hdd_adapter_t *adapter,
3802 hdd_context_t *hdd_ctx,
3803 uint8_t *command,
3804 uint8_t command_len,
3805 hdd_priv_data_t *priv_data)
3806{
3807 int ret = 0;
3808 uint16_t val = sme_get_neighbor_scan_max_chan_time(hdd_ctx->hHal,
3809 adapter->sessionId);
3810 char extra[32];
3811 uint8_t len = 0;
3812
3813 /* value is interms of msec */
3814 len = scnprintf(extra, sizeof(extra), "%s %d",
3815 "GETSCANCHANNELTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303816 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003817
3818 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003819 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003820 ret = -EFAULT;
3821 }
3822
3823 return ret;
3824}
3825
3826static int drv_cmd_set_scan_home_time(hdd_adapter_t *adapter,
3827 hdd_context_t *hdd_ctx,
3828 uint8_t *command,
3829 uint8_t command_len,
3830 hdd_priv_data_t *priv_data)
3831{
3832 int ret = 0;
3833 uint8_t *value = command;
3834 uint16_t val = CFG_NEIGHBOR_SCAN_TIMER_PERIOD_DEFAULT;
3835
3836 /* Move pointer to ahead of SETSCANHOMETIME<delimiter> */
3837 value = value + command_len + 1;
3838
3839 /* Convert the value from ascii to integer */
3840 ret = kstrtou16(value, 10, &val);
3841 if (ret < 0) {
3842 /*
3843 * If the input value is greater than max value of datatype,
3844 * then also kstrtou8 fails
3845 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003846 hdd_err("kstrtou16 failed range [%d - %d]",
3847 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN,
3848 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003849 ret = -EINVAL;
3850 goto exit;
3851 }
3852
3853 if ((val < CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN) ||
3854 (val > CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003855 hdd_err("scan home time value %d is out of range (Min: %d Max: %d)",
3856 val,
3857 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN,
3858 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003859 ret = -EINVAL;
3860 goto exit;
3861 }
3862
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003863 hdd_info("Received Command to change scan home time = %d",
3864 val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003865
3866 hdd_ctx->config->nNeighborScanPeriod = val;
3867 sme_set_neighbor_scan_period(hdd_ctx->hHal,
3868 adapter->sessionId, val);
3869
3870exit:
3871 return ret;
3872}
3873
3874static int drv_cmd_get_scan_home_time(hdd_adapter_t *adapter,
3875 hdd_context_t *hdd_ctx,
3876 uint8_t *command,
3877 uint8_t command_len,
3878 hdd_priv_data_t *priv_data)
3879{
3880 int ret = 0;
3881 uint16_t val = sme_get_neighbor_scan_period(hdd_ctx->hHal,
3882 adapter->
3883 sessionId);
3884 char extra[32];
3885 uint8_t len = 0;
3886
3887 /* value is interms of msec */
3888 len = scnprintf(extra, sizeof(extra), "%s %d",
3889 "GETSCANHOMETIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303890 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003891
3892 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003893 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003894 ret = -EFAULT;
3895 }
3896
3897 return ret;
3898}
3899
3900static int drv_cmd_set_roam_intra_band(hdd_adapter_t *adapter,
3901 hdd_context_t *hdd_ctx,
3902 uint8_t *command,
3903 uint8_t command_len,
3904 hdd_priv_data_t *priv_data)
3905{
3906 int ret = 0;
3907 uint8_t *value = command;
3908 uint8_t val = CFG_ROAM_INTRA_BAND_DEFAULT;
3909
3910 /* Move pointer to ahead of SETROAMINTRABAND<delimiter> */
3911 value = value + command_len + 1;
3912
3913 /* Convert the value from ascii to integer */
3914 ret = kstrtou8(value, 10, &val);
3915 if (ret < 0) {
3916 /*
3917 * If the input value is greater than max value of datatype,
3918 * then also kstrtou8 fails
3919 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003920 hdd_err("kstrtou8 failed range [%d - %d]",
3921 CFG_ROAM_INTRA_BAND_MIN,
3922 CFG_ROAM_INTRA_BAND_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003923 ret = -EINVAL;
3924 goto exit;
3925 }
3926
3927 if ((val < CFG_ROAM_INTRA_BAND_MIN) ||
3928 (val > CFG_ROAM_INTRA_BAND_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003929 hdd_err("intra band mode value %d is out of range (Min: %d Max: %d)",
3930 val,
3931 CFG_ROAM_INTRA_BAND_MIN,
3932 CFG_ROAM_INTRA_BAND_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003933 ret = -EINVAL;
3934 goto exit;
3935 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003936 hdd_info("Received Command to change intra band = %d",
3937 val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003938
3939 hdd_ctx->config->nRoamIntraBand = val;
3940 sme_set_roam_intra_band(hdd_ctx->hHal, val);
3941
3942exit:
3943 return ret;
3944}
3945
3946static int drv_cmd_get_roam_intra_band(hdd_adapter_t *adapter,
3947 hdd_context_t *hdd_ctx,
3948 uint8_t *command,
3949 uint8_t command_len,
3950 hdd_priv_data_t *priv_data)
3951{
3952 int ret = 0;
3953 uint16_t val = sme_get_roam_intra_band(hdd_ctx->hHal);
3954 char extra[32];
3955 uint8_t len = 0;
3956
3957 /* value is interms of msec */
3958 len = scnprintf(extra, sizeof(extra), "%s %d",
3959 "GETROAMINTRABAND", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303960 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003961 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003962 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003963 ret = -EFAULT;
3964 }
3965
3966 return ret;
3967}
3968
3969static int drv_cmd_set_scan_n_probes(hdd_adapter_t *adapter,
3970 hdd_context_t *hdd_ctx,
3971 uint8_t *command,
3972 uint8_t command_len,
3973 hdd_priv_data_t *priv_data)
3974{
3975 int ret = 0;
3976 uint8_t *value = command;
3977 uint8_t nProbes = CFG_ROAM_SCAN_N_PROBES_DEFAULT;
3978
3979 /* Move pointer to ahead of SETSCANNPROBES<delimiter> */
3980 value = value + command_len + 1;
3981
3982 /* Convert the value from ascii to integer */
3983 ret = kstrtou8(value, 10, &nProbes);
3984 if (ret < 0) {
3985 /*
3986 * If the input value is greater than max value of datatype,
3987 * then also kstrtou8 fails
3988 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003989 hdd_err("kstrtou8 failed range [%d - %d]",
3990 CFG_ROAM_SCAN_N_PROBES_MIN,
3991 CFG_ROAM_SCAN_N_PROBES_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003992 ret = -EINVAL;
3993 goto exit;
3994 }
3995
3996 if ((nProbes < CFG_ROAM_SCAN_N_PROBES_MIN) ||
3997 (nProbes > CFG_ROAM_SCAN_N_PROBES_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003998 hdd_err("NProbes value %d is out of range (Min: %d Max: %d)",
3999 nProbes,
4000 CFG_ROAM_SCAN_N_PROBES_MIN,
4001 CFG_ROAM_SCAN_N_PROBES_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004002 ret = -EINVAL;
4003 goto exit;
4004 }
4005
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004006 hdd_info("Received Command to Set nProbes = %d",
4007 nProbes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004008
4009 hdd_ctx->config->nProbes = nProbes;
4010 sme_update_roam_scan_n_probes(hdd_ctx->hHal,
4011 adapter->sessionId, nProbes);
4012
4013exit:
4014 return ret;
4015}
4016
4017static int drv_cmd_get_scan_n_probes(hdd_adapter_t *adapter,
4018 hdd_context_t *hdd_ctx,
4019 uint8_t *command,
4020 uint8_t command_len,
4021 hdd_priv_data_t *priv_data)
4022{
4023 int ret = 0;
4024 uint8_t val = sme_get_roam_scan_n_probes(hdd_ctx->hHal);
4025 char extra[32];
4026 uint8_t len = 0;
4027
4028 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304029 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004030 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004031 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004032 ret = -EFAULT;
4033 }
4034
4035 return ret;
4036}
4037
4038static int drv_cmd_set_scan_home_away_time(hdd_adapter_t *adapter,
4039 hdd_context_t *hdd_ctx,
4040 uint8_t *command,
4041 uint8_t command_len,
4042 hdd_priv_data_t *priv_data)
4043{
4044 int ret = 0;
4045 uint8_t *value = command;
4046 uint16_t homeAwayTime = CFG_ROAM_SCAN_HOME_AWAY_TIME_DEFAULT;
4047
4048 /* input value is in units of msec */
4049
4050 /* Move pointer to ahead of SETSCANHOMEAWAYTIME<delimiter> */
4051 value = value + command_len + 1;
4052
4053 /* Convert the value from ascii to integer */
4054 ret = kstrtou16(value, 10, &homeAwayTime);
4055 if (ret < 0) {
4056 /*
4057 * If the input value is greater than max value of datatype,
4058 * then also kstrtou8 fails
4059 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004060 hdd_err("kstrtou8 failed range [%d - %d]",
4061 CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN,
4062 CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004063 ret = -EINVAL;
4064 goto exit;
4065 }
4066
4067 if ((homeAwayTime < CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN) ||
4068 (homeAwayTime > CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004069 hdd_err("homeAwayTime value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004070 homeAwayTime,
4071 CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN,
4072 CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX);
4073 ret = -EINVAL;
4074 goto exit;
4075 }
4076
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004077 hdd_info("Received Command to Set scan away time = %d",
4078 homeAwayTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004079
4080 if (hdd_ctx->config->nRoamScanHomeAwayTime !=
4081 homeAwayTime) {
4082 hdd_ctx->config->nRoamScanHomeAwayTime = homeAwayTime;
4083 sme_update_roam_scan_home_away_time(hdd_ctx->hHal,
4084 adapter->sessionId,
4085 homeAwayTime,
4086 true);
4087 }
4088
4089exit:
4090 return ret;
4091}
4092
4093static int drv_cmd_get_scan_home_away_time(hdd_adapter_t *adapter,
4094 hdd_context_t *hdd_ctx,
4095 uint8_t *command,
4096 uint8_t command_len,
4097 hdd_priv_data_t *priv_data)
4098{
4099 int ret = 0;
4100 uint16_t val = sme_get_roam_scan_home_away_time(hdd_ctx->hHal);
4101 char extra[32];
4102 uint8_t len = 0;
4103
4104 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304105 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004106
4107 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004108 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004109 ret = -EFAULT;
4110 }
4111
4112 return ret;
4113}
4114
4115static int drv_cmd_reassoc(hdd_adapter_t *adapter,
4116 hdd_context_t *hdd_ctx,
4117 uint8_t *command,
4118 uint8_t command_len,
4119 hdd_priv_data_t *priv_data)
4120{
4121 return hdd_parse_reassoc(adapter, command);
4122}
4123
4124static int drv_cmd_set_wes_mode(hdd_adapter_t *adapter,
4125 hdd_context_t *hdd_ctx,
4126 uint8_t *command,
4127 uint8_t command_len,
4128 hdd_priv_data_t *priv_data)
4129{
4130 int ret = 0;
4131 uint8_t *value = command;
4132 uint8_t wesMode = CFG_ENABLE_WES_MODE_NAME_DEFAULT;
4133
4134 /* Move pointer to ahead of SETWESMODE<delimiter> */
4135 value = value + command_len + 1;
4136
4137 /* Convert the value from ascii to integer */
4138 ret = kstrtou8(value, 10, &wesMode);
4139 if (ret < 0) {
4140 /*
4141 * If the input value is greater than max value of datatype,
4142 * then also kstrtou8 fails
4143 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004144 hdd_err("kstrtou8 failed range [%d - %d]",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004145 CFG_ENABLE_WES_MODE_NAME_MIN,
4146 CFG_ENABLE_WES_MODE_NAME_MAX);
4147 ret = -EINVAL;
4148 goto exit;
4149 }
4150
4151 if ((wesMode < CFG_ENABLE_WES_MODE_NAME_MIN) ||
4152 (wesMode > CFG_ENABLE_WES_MODE_NAME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004153 hdd_err("WES Mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004154 wesMode,
4155 CFG_ENABLE_WES_MODE_NAME_MIN,
4156 CFG_ENABLE_WES_MODE_NAME_MAX);
4157 ret = -EINVAL;
4158 goto exit;
4159 }
4160
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004161 hdd_info("Received Command to Set WES Mode rssi diff = %d",
4162 wesMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004163
4164 hdd_ctx->config->isWESModeEnabled = wesMode;
4165 sme_update_wes_mode(hdd_ctx->hHal, wesMode, adapter->sessionId);
4166
4167exit:
4168 return ret;
4169}
4170
4171static int drv_cmd_get_wes_mode(hdd_adapter_t *adapter,
4172 hdd_context_t *hdd_ctx,
4173 uint8_t *command,
4174 uint8_t command_len,
4175 hdd_priv_data_t *priv_data)
4176{
4177 int ret = 0;
4178 bool wesMode = sme_get_wes_mode(hdd_ctx->hHal);
4179 char extra[32];
4180 uint8_t len = 0;
4181
4182 len = scnprintf(extra, sizeof(extra), "%s %d", command, wesMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304183 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004184 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004185 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004186 ret = -EFAULT;
4187 }
4188
4189 return ret;
4190}
4191
4192static int drv_cmd_set_opportunistic_rssi_diff(hdd_adapter_t *adapter,
4193 hdd_context_t *hdd_ctx,
4194 uint8_t *command,
4195 uint8_t command_len,
4196 hdd_priv_data_t *priv_data)
4197{
4198 int ret = 0;
4199 uint8_t *value = command;
4200 uint8_t nOpportunisticThresholdDiff =
4201 CFG_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF_DEFAULT;
4202
4203 /* Move pointer to ahead of SETOPPORTUNISTICRSSIDIFF<delimiter> */
4204 value = value + command_len + 1;
4205
4206 /* Convert the value from ascii to integer */
4207 ret = kstrtou8(value, 10, &nOpportunisticThresholdDiff);
4208 if (ret < 0) {
4209 /*
4210 * If the input value is greater than max value of datatype,
4211 * then also kstrtou8 fails
4212 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004213 hdd_err("kstrtou8 failed.");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004214 ret = -EINVAL;
4215 goto exit;
4216 }
4217
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004218 hdd_info("Received Command to Set Opportunistic Threshold diff = %d",
4219 nOpportunisticThresholdDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004220
4221 sme_set_roam_opportunistic_scan_threshold_diff(hdd_ctx->hHal,
4222 adapter->sessionId,
4223 nOpportunisticThresholdDiff);
4224
4225exit:
4226 return ret;
4227}
4228
4229static int drv_cmd_get_opportunistic_rssi_diff(hdd_adapter_t *adapter,
4230 hdd_context_t *hdd_ctx,
4231 uint8_t *command,
4232 uint8_t command_len,
4233 hdd_priv_data_t *priv_data)
4234{
4235 int ret = 0;
4236 int8_t val = sme_get_roam_opportunistic_scan_threshold_diff(
4237 hdd_ctx->hHal);
4238 char extra[32];
4239 uint8_t len = 0;
4240
4241 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304242 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004243 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004244 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004245 ret = -EFAULT;
4246 }
4247
4248 return ret;
4249}
4250
4251static int drv_cmd_set_roam_rescan_rssi_diff(hdd_adapter_t *adapter,
4252 hdd_context_t *hdd_ctx,
4253 uint8_t *command,
4254 uint8_t command_len,
4255 hdd_priv_data_t *priv_data)
4256{
4257 int ret = 0;
4258 uint8_t *value = command;
4259 uint8_t nRoamRescanRssiDiff = CFG_ROAM_RESCAN_RSSI_DIFF_DEFAULT;
4260
4261 /* Move pointer to ahead of SETROAMRESCANRSSIDIFF<delimiter> */
4262 value = value + command_len + 1;
4263
4264 /* Convert the value from ascii to integer */
4265 ret = kstrtou8(value, 10, &nRoamRescanRssiDiff);
4266 if (ret < 0) {
4267 /*
4268 * If the input value is greater than max value of datatype,
4269 * then also kstrtou8 fails
4270 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004271 hdd_err("kstrtou8 failed.");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004272 ret = -EINVAL;
4273 goto exit;
4274 }
4275
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004276 hdd_info("Received Command to Set Roam Rescan RSSI Diff = %d",
4277 nRoamRescanRssiDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004278
4279 sme_set_roam_rescan_rssi_diff(hdd_ctx->hHal,
4280 adapter->sessionId,
4281 nRoamRescanRssiDiff);
4282
4283exit:
4284 return ret;
4285}
4286
4287static int drv_cmd_get_roam_rescan_rssi_diff(hdd_adapter_t *adapter,
4288 hdd_context_t *hdd_ctx,
4289 uint8_t *command,
4290 uint8_t command_len,
4291 hdd_priv_data_t *priv_data)
4292{
4293 int ret = 0;
4294 uint8_t val = sme_get_roam_rescan_rssi_diff(hdd_ctx->hHal);
4295 char extra[32];
4296 uint8_t len = 0;
4297
4298 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304299 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004300 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004301 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004302 ret = -EFAULT;
4303 }
4304
4305 return ret;
4306}
4307
4308static int drv_cmd_set_fast_roam(hdd_adapter_t *adapter,
4309 hdd_context_t *hdd_ctx,
4310 uint8_t *command,
4311 uint8_t command_len,
4312 hdd_priv_data_t *priv_data)
4313{
4314 int ret = 0;
4315 uint8_t *value = command;
4316 uint8_t lfrMode = CFG_LFR_FEATURE_ENABLED_DEFAULT;
4317
4318 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4319 value = value + command_len + 1;
4320
4321 /* Convert the value from ascii to integer */
4322 ret = kstrtou8(value, 10, &lfrMode);
4323 if (ret < 0) {
4324 /*
4325 * If the input value is greater than max value of datatype,
4326 * then also kstrtou8 fails
4327 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004328 hdd_err("kstrtou8 failed range [%d - %d]",
4329 CFG_LFR_FEATURE_ENABLED_MIN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004330 CFG_LFR_FEATURE_ENABLED_MAX);
4331 ret = -EINVAL;
4332 goto exit;
4333 }
4334
4335 if ((lfrMode < CFG_LFR_FEATURE_ENABLED_MIN) ||
4336 (lfrMode > CFG_LFR_FEATURE_ENABLED_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004337 hdd_err("lfr mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004338 lfrMode,
4339 CFG_LFR_FEATURE_ENABLED_MIN,
4340 CFG_LFR_FEATURE_ENABLED_MAX);
4341 ret = -EINVAL;
4342 goto exit;
4343 }
4344
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004345 hdd_info("Received Command to change lfr mode = %d",
4346 lfrMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004347
4348 hdd_ctx->config->isFastRoamIniFeatureEnabled = lfrMode;
4349 sme_update_is_fast_roam_ini_feature_enabled(hdd_ctx->hHal,
4350 adapter->
4351 sessionId,
4352 lfrMode);
4353
4354exit:
4355 return ret;
4356}
4357
4358static int drv_cmd_set_fast_transition(hdd_adapter_t *adapter,
4359 hdd_context_t *hdd_ctx,
4360 uint8_t *command,
4361 uint8_t command_len,
4362 hdd_priv_data_t *priv_data)
4363{
4364 int ret = 0;
4365 uint8_t *value = command;
4366 uint8_t ft = CFG_FAST_TRANSITION_ENABLED_NAME_DEFAULT;
4367
4368 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4369 value = value + command_len + 1;
4370
4371 /* Convert the value from ascii to integer */
4372 ret = kstrtou8(value, 10, &ft);
4373 if (ret < 0) {
4374 /*
4375 * If the input value is greater than max value of datatype,
4376 * then also kstrtou8 fails
4377 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004378 hdd_err("kstrtou8 failed range [%d - %d]",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004379 CFG_FAST_TRANSITION_ENABLED_NAME_MIN,
4380 CFG_FAST_TRANSITION_ENABLED_NAME_MAX);
4381 ret = -EINVAL;
4382 goto exit;
4383 }
4384
4385 if ((ft < CFG_FAST_TRANSITION_ENABLED_NAME_MIN) ||
4386 (ft > CFG_FAST_TRANSITION_ENABLED_NAME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004387 hdd_err("ft mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004388 ft,
4389 CFG_FAST_TRANSITION_ENABLED_NAME_MIN,
4390 CFG_FAST_TRANSITION_ENABLED_NAME_MAX);
4391 ret = -EINVAL;
4392 goto exit;
4393 }
4394
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004395 hdd_info("Received Command to change ft mode = %d", ft);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004396
4397 hdd_ctx->config->isFastTransitionEnabled = ft;
4398 sme_update_fast_transition_enabled(hdd_ctx->hHal, ft);
4399
4400exit:
4401 return ret;
4402}
4403
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004404static int drv_cmd_fast_reassoc(hdd_adapter_t *adapter,
4405 hdd_context_t *hdd_ctx,
4406 uint8_t *command,
4407 uint8_t command_len,
4408 hdd_priv_data_t *priv_data)
4409{
4410 int ret = 0;
4411 uint8_t *value = command;
4412 uint8_t channel = 0;
4413 tSirMacAddr targetApBssid;
4414 uint32_t roamId = 0;
4415 tCsrRoamModifyProfileFields modProfileFields;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004416 tCsrHandoffRequest handoffInfo;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004417 hdd_station_ctx_t *pHddStaCtx;
4418
Krunal Sonibe766b02016-03-10 13:00:44 -08004419 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004420 hdd_warn("Unsupported in mode %s(%d)",
4421 hdd_device_mode_to_string(adapter->device_mode),
4422 adapter->device_mode);
4423 return -EINVAL;
4424 }
4425
4426 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
4427
4428 /* if not associated, no need to proceed with reassoc */
4429 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004430 hdd_info("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004431 ret = -EINVAL;
4432 goto exit;
4433 }
4434
4435 ret = hdd_parse_reassoc_command_v1_data(value, targetApBssid,
4436 &channel);
4437 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004438 hdd_err("Failed to parse reassoc command data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004439 goto exit;
4440 }
4441
4442 /*
4443 * if the target bssid is same as currently associated AP,
4444 * issue reassoc to same AP
4445 */
Ankit Guptaa5076012016-09-14 11:32:19 -07004446 if (!qdf_mem_cmp(targetApBssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004447 pHddStaCtx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05304448 QDF_MAC_ADDR_SIZE)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004449 hdd_info("Reassoc BSSID is same as currently associated AP bssid");
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304450 if (roaming_offload_enabled(hdd_ctx)) {
4451 hdd_wma_send_fastreassoc_cmd((int)adapter->sessionId,
Padma, Santhosh Kumaraf9f08c2016-10-21 21:26:29 +05304452 targetApBssid,
4453 pHddStaCtx->conn_info.operationChannel);
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304454 } else {
4455 sme_get_modify_profile_fields(hdd_ctx->hHal,
4456 adapter->sessionId,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004457 &modProfileFields);
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304458 sme_roam_reassoc(hdd_ctx->hHal, adapter->sessionId,
4459 NULL, modProfileFields, &roamId, 1);
4460 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004461 return 0;
4462 }
4463
Padma, Santhosh Kumaraf9f08c2016-10-21 21:26:29 +05304464 /* Check channel number is a valid channel number */
4465 if (QDF_STATUS_SUCCESS !=
4466 wlan_hdd_validate_operation_channel(adapter, channel)) {
4467 hdd_err("Invalid Channel [%d]", channel);
4468 return -EINVAL;
4469 }
4470
Varun Reddy Yeturud351a6c2016-03-16 14:01:00 -07004471 if (roaming_offload_enabled(hdd_ctx)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004472 hdd_wma_send_fastreassoc_cmd((int)adapter->sessionId,
4473 targetApBssid, (int)channel);
4474 goto exit;
4475 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004476 /* Proceed with reassoc */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004477 handoffInfo.channel = channel;
4478 handoffInfo.src = FASTREASSOC;
Varun Reddy Yeturua66f9c52016-02-17 09:58:40 -08004479 qdf_mem_copy(handoffInfo.bssid.bytes, targetApBssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004480 sizeof(tSirMacAddr));
4481 sme_handoff_request(hdd_ctx->hHal, adapter->sessionId,
4482 &handoffInfo);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004483exit:
4484 return ret;
4485}
4486
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004487static int drv_cmd_set_roam_scan_control(hdd_adapter_t *adapter,
4488 hdd_context_t *hdd_ctx,
4489 uint8_t *command,
4490 uint8_t command_len,
4491 hdd_priv_data_t *priv_data)
4492{
4493 int ret = 0;
4494 uint8_t *value = command;
4495 uint8_t roamScanControl = 0;
4496
4497 /* Move pointer to ahead of SETROAMSCANCONTROL<delimiter> */
4498 value = value + command_len + 1;
4499
4500 /* Convert the value from ascii to integer */
4501 ret = kstrtou8(value, 10, &roamScanControl);
4502 if (ret < 0) {
4503 /*
4504 * If the input value is greater than max value of datatype,
4505 * then also kstrtou8 fails
4506 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004507 hdd_err("kstrtou8 failed ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004508 ret = -EINVAL;
4509 goto exit;
4510 }
4511
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004512 hdd_info("Received Command to Set roam scan control = %d",
4513 roamScanControl);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004514
4515 if (0 != roamScanControl) {
4516 ret = 0; /* return success but ignore param value "true" */
4517 goto exit;
4518 }
4519
4520 sme_set_roam_scan_control(hdd_ctx->hHal,
4521 adapter->sessionId,
4522 roamScanControl);
4523
4524exit:
4525 return ret;
4526}
4527
4528static int drv_cmd_set_okc_mode(hdd_adapter_t *adapter,
4529 hdd_context_t *hdd_ctx,
4530 uint8_t *command,
4531 uint8_t command_len,
4532 hdd_priv_data_t *priv_data)
4533{
4534 int ret = 0;
4535 uint8_t *value = command;
4536 uint8_t okcMode = CFG_OKC_FEATURE_ENABLED_DEFAULT;
4537
4538 /*
4539 * Check if the features OKC/ESE/11R are supported simultaneously,
4540 * then this operation is not permitted (return FAILURE)
4541 */
4542 if (sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
4543 hdd_is_okc_mode_enabled(hdd_ctx) &&
4544 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004545 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004546 ret = -EPERM;
4547 goto exit;
4548 }
4549
4550 /* Move pointer to ahead of SETOKCMODE<delimiter> */
4551 value = value + command_len + 1;
4552
4553 /* Convert the value from ascii to integer */
4554 ret = kstrtou8(value, 10, &okcMode);
4555 if (ret < 0) {
4556 /*
4557 * If the input value is greater than max value of datatype,
4558 * then also kstrtou8 fails
4559 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004560 hdd_err("kstrtou8 failed range [%d - %d]",
4561 CFG_OKC_FEATURE_ENABLED_MIN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004562 CFG_OKC_FEATURE_ENABLED_MAX);
4563 ret = -EINVAL;
4564 goto exit;
4565 }
4566
4567 if ((okcMode < CFG_OKC_FEATURE_ENABLED_MIN) ||
4568 (okcMode > CFG_OKC_FEATURE_ENABLED_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004569 hdd_err("Okc mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004570 okcMode,
4571 CFG_OKC_FEATURE_ENABLED_MIN,
4572 CFG_OKC_FEATURE_ENABLED_MAX);
4573 ret = -EINVAL;
4574 goto exit;
4575 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004576 hdd_info("Received Command to change okc mode = %d",
4577 okcMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004578
4579 hdd_ctx->config->isOkcIniFeatureEnabled = okcMode;
4580
4581exit:
4582 return ret;
4583}
4584
4585static int drv_cmd_get_roam_scan_control(hdd_adapter_t *adapter,
4586 hdd_context_t *hdd_ctx,
4587 uint8_t *command,
4588 uint8_t command_len,
4589 hdd_priv_data_t *priv_data)
4590{
4591 int ret = 0;
4592 bool roamScanControl = sme_get_roam_scan_control(hdd_ctx->hHal);
4593 char extra[32];
4594 uint8_t len = 0;
4595
4596 len = scnprintf(extra, sizeof(extra), "%s %d",
4597 command, roamScanControl);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304598 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004599 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004600 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004601 ret = -EFAULT;
4602 }
4603
4604 return ret;
4605}
4606
4607static int drv_cmd_bt_coex_mode(hdd_adapter_t *adapter,
4608 hdd_context_t *hdd_ctx,
4609 uint8_t *command,
4610 uint8_t command_len,
4611 hdd_priv_data_t *priv_data)
4612{
4613 int ret = 0;
4614 char *bcMode;
4615
4616 bcMode = command + 11;
4617 if ('1' == *bcMode) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004618 hdd_debug("BTCOEXMODE %d", *bcMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004619 hdd_ctx->btCoexModeSet = true;
4620 ret = wlan_hdd_scan_abort(adapter);
4621 if (ret < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004622 hdd_err("Failed to abort existing scan status: %d",
4623 ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004624 }
4625 } else if ('2' == *bcMode) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004626 hdd_debug("BTCOEXMODE %d", *bcMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004627 hdd_ctx->btCoexModeSet = false;
4628 }
4629
4630 return ret;
4631}
4632
4633static int drv_cmd_scan_active(hdd_adapter_t *adapter,
4634 hdd_context_t *hdd_ctx,
4635 uint8_t *command,
4636 uint8_t command_len,
4637 hdd_priv_data_t *priv_data)
4638{
4639 hdd_ctx->ioctl_scan_mode = eSIR_ACTIVE_SCAN;
4640 return 0;
4641}
4642
4643static int drv_cmd_scan_passive(hdd_adapter_t *adapter,
4644 hdd_context_t *hdd_ctx,
4645 uint8_t *command,
4646 uint8_t command_len,
4647 hdd_priv_data_t *priv_data)
4648{
4649 hdd_ctx->ioctl_scan_mode = eSIR_PASSIVE_SCAN;
4650 return 0;
4651}
4652
4653static int drv_cmd_get_dwell_time(hdd_adapter_t *adapter,
4654 hdd_context_t *hdd_ctx,
4655 uint8_t *command,
4656 uint8_t command_len,
4657 hdd_priv_data_t *priv_data)
4658{
4659 int ret = 0;
4660 struct hdd_config *pCfg =
4661 (WLAN_HDD_GET_CTX(adapter))->config;
4662 char extra[32];
4663 uint8_t len = 0;
4664
4665 memset(extra, 0, sizeof(extra));
4666 ret = hdd_get_dwell_time(pCfg, command, extra, sizeof(extra), &len);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304667 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004668 if (ret != 0 || copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004669 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004670 ret = -EFAULT;
4671 goto exit;
4672 }
4673 ret = len;
4674exit:
4675 return ret;
4676}
4677
4678static int drv_cmd_set_dwell_time(hdd_adapter_t *adapter,
4679 hdd_context_t *hdd_ctx,
4680 uint8_t *command,
4681 uint8_t command_len,
4682 hdd_priv_data_t *priv_data)
4683{
4684 return hdd_set_dwell_time(adapter, command);
4685}
4686
4687static int drv_cmd_miracast(hdd_adapter_t *adapter,
4688 hdd_context_t *hdd_ctx,
4689 uint8_t *command,
4690 uint8_t command_len,
4691 hdd_priv_data_t *priv_data)
4692{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304693 QDF_STATUS ret_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004694 int ret = 0;
4695 tHalHandle hHal;
4696 uint8_t filterType = 0;
4697 hdd_context_t *pHddCtx = NULL;
4698 uint8_t *value;
4699
4700 pHddCtx = WLAN_HDD_GET_CTX(adapter);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05304701 if (wlan_hdd_validate_context(pHddCtx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004702 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004703
4704 hHal = pHddCtx->hHal;
4705 value = command + 9;
4706
4707 /* Convert the value from ascii to integer */
4708 ret = kstrtou8(value, 10, &filterType);
4709 if (ret < 0) {
4710 /*
4711 * If the input value is greater than max value of datatype,
4712 * then also kstrtou8 fails
4713 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004714 hdd_err("kstrtou8 failed range ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004715 ret = -EINVAL;
4716 goto exit;
4717 }
4718 if ((filterType < WLAN_HDD_DRIVER_MIRACAST_CFG_MIN_VAL)
4719 || (filterType >
4720 WLAN_HDD_DRIVER_MIRACAST_CFG_MAX_VAL)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004721 hdd_err("Accepted Values are 0 to 2. 0-Disabled, 1-Source, 2-Sink ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004722 ret = -EINVAL;
4723 goto exit;
4724 }
4725 /* Filtertype value should be either 0-Disabled, 1-Source, 2-sink */
4726 pHddCtx->miracast_value = filterType;
4727
4728 ret_status = sme_set_miracast(hHal, filterType);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304729 if (QDF_STATUS_SUCCESS != ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004730 hdd_err("Failed to set miracast");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004731 return -EBUSY;
4732 }
4733
Tushnim Bhattacharyyaca50b322015-12-28 17:14:36 -08004734 if (cds_is_mcc_in_24G())
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004735 return cds_set_mas(adapter, filterType);
4736
4737exit:
4738 return ret;
4739}
4740
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004741/* Function header is left blank intentionally */
4742static int hdd_parse_set_ibss_oui_data_command(uint8_t *command, uint8_t *ie,
4743 int32_t *oui_length, int32_t limit)
4744{
4745 uint8_t len;
4746 uint8_t data;
4747
4748 while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) {
4749 command++;
4750 limit--;
4751 }
4752
4753 len = 2;
4754
4755 while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) &&
4756 (limit > 1)) {
4757 sscanf(command, "%02x", (unsigned int *)&data);
4758 ie[len++] = data;
4759 command += 2;
4760 limit -= 2;
4761 }
4762
4763 *oui_length = len - 2;
4764
4765 while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) {
4766 command++;
4767 limit--;
4768 }
4769
4770 while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) &&
4771 (limit > 1)) {
4772 sscanf(command, "%02x", (unsigned int *)&data);
4773 ie[len++] = data;
4774 command += 2;
4775 limit -= 2;
4776 }
4777
4778 ie[0] = IE_EID_VENDOR;
4779 ie[1] = len - 2;
4780
4781 return len;
4782}
4783
4784/**
4785 * drv_cmd_set_ibss_beacon_oui_data() - set ibss oui data command
4786 * @adapter: Pointer to adapter
4787 * @hdd_ctx: Pointer to HDD context
4788 * @command: Pointer to command string
4789 * @command_len : Command length
4790 * @priv_data : Pointer to priv data
4791 *
4792 * Return:
4793 * int status code
4794 */
4795static int drv_cmd_set_ibss_beacon_oui_data(hdd_adapter_t *adapter,
4796 hdd_context_t *hdd_ctx,
4797 uint8_t *command,
4798 uint8_t command_len,
4799 hdd_priv_data_t *priv_data)
4800{
4801 int i = 0;
4802 int status;
4803 int ret = 0;
4804 uint8_t *ibss_ie;
4805 int32_t oui_length = 0;
4806 uint32_t ibss_ie_length;
4807 uint8_t *value = command;
4808 tSirModifyIE ibssModifyIE;
4809 tCsrRoamProfile *pRoamProfile;
4810 hdd_wext_state_t *pWextState;
4811
4812
Krunal Sonibe766b02016-03-10 13:00:44 -08004813 if (QDF_IBSS_MODE != adapter->device_mode) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004814 hdd_info("Device_mode %s(%d) not IBSS",
4815 hdd_device_mode_to_string(adapter->device_mode),
4816 adapter->device_mode);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004817 return ret;
4818 }
4819
4820 pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(adapter);
4821
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004822 hdd_info("received command %s", ((char *)value));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004823
4824
4825 /* validate argument of command */
4826 if (strlen(value) <= command_len) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004827 hdd_err("No arguments in command length %zu",
4828 strlen(value));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004829 ret = -EFAULT;
4830 goto exit;
4831 }
4832
4833 /* moving to arguments of commands */
4834 value = value + command_len;
4835 command_len = strlen(value);
4836
4837 /* oui_data can't be less than 3 bytes */
4838 if (command_len < (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004839 hdd_err("Invalid SETIBSSBEACONOUIDATA command length %d",
4840 command_len);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004841 ret = -EFAULT;
4842 goto exit;
4843 }
4844
4845 ibss_ie = qdf_mem_malloc(command_len);
4846 if (!ibss_ie) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004847 hdd_err("Could not allocate memory for command length %d",
4848 command_len);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004849 ret = -ENOMEM;
4850 goto exit;
4851 }
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004852
4853 ibss_ie_length = hdd_parse_set_ibss_oui_data_command(value, ibss_ie,
4854 &oui_length,
4855 command_len);
4856 if (ibss_ie_length <= (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004857 hdd_err("Could not parse command %s return length %d",
4858 value, ibss_ie_length);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004859 ret = -EFAULT;
4860 qdf_mem_free(ibss_ie);
4861 goto exit;
4862 }
4863
4864 pRoamProfile = &pWextState->roamProfile;
4865
4866 qdf_copy_macaddr(&ibssModifyIE.bssid,
4867 pRoamProfile->BSSIDs.bssid);
4868
4869 ibssModifyIE.smeSessionId = adapter->sessionId;
4870 ibssModifyIE.notify = true;
4871 ibssModifyIE.ieID = IE_EID_VENDOR;
4872 ibssModifyIE.ieIDLen = ibss_ie_length;
4873 ibssModifyIE.ieBufferlength = ibss_ie_length;
4874 ibssModifyIE.pIEBuffer = ibss_ie;
4875 ibssModifyIE.oui_length = oui_length;
4876
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004877 hdd_warn("ibss_ie length %d oui_length %d ibss_ie:",
4878 ibss_ie_length, oui_length);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004879 while (i < ibssModifyIE.ieBufferlength)
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004880 hdd_warn("0x%x", ibss_ie[i++]);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004881
4882 /* Probe Bcn modification */
4883 sme_modify_add_ie(WLAN_HDD_GET_HAL_CTX(adapter),
4884 &ibssModifyIE, eUPDATE_IE_PROBE_BCN);
4885
4886 /* Populating probe resp frame */
4887 sme_modify_add_ie(WLAN_HDD_GET_HAL_CTX(adapter),
4888 &ibssModifyIE, eUPDATE_IE_PROBE_RESP);
4889
4890 qdf_mem_free(ibss_ie);
4891
4892 status = sme_send_cesium_enable_ind((tHalHandle)(hdd_ctx->hHal),
4893 adapter->sessionId);
4894 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004895 hdd_err("Could not send cesium enable indication %d",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004896 status);
4897 ret = -EINVAL;
4898 goto exit;
4899 }
4900
4901exit:
4902 return ret;
4903}
4904
4905static int drv_cmd_set_rmc_enable(hdd_adapter_t *adapter,
4906 hdd_context_t *hdd_ctx,
4907 uint8_t *command,
4908 uint8_t command_len,
4909 hdd_priv_data_t *priv_data)
4910{
4911 int ret = 0;
4912 uint8_t *value = command;
4913 uint8_t ucRmcEnable = 0;
4914 int status;
4915
Krunal Sonibe766b02016-03-10 13:00:44 -08004916 if ((QDF_IBSS_MODE != adapter->device_mode) &&
4917 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004918 hdd_err("Received SETRMCENABLE cmd in invalid mode %s(%d)",
4919 hdd_device_mode_to_string(adapter->device_mode),
4920 adapter->device_mode);
4921 hdd_err("SETRMCENABLE cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004922 ret = -EINVAL;
4923 goto exit;
4924 }
4925
4926 status = hdd_parse_setrmcenable_command(value, &ucRmcEnable);
4927 if (status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004928 hdd_err("Invalid SETRMCENABLE command ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004929 ret = -EINVAL;
4930 goto exit;
4931 }
4932
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004933 hdd_info("ucRmcEnable %d ", ucRmcEnable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004934
4935 if (true == ucRmcEnable) {
4936 status = sme_enable_rmc((tHalHandle)
4937 (hdd_ctx->hHal),
4938 adapter->sessionId);
4939 } else if (false == ucRmcEnable) {
4940 status = sme_disable_rmc((tHalHandle)
4941 (hdd_ctx->hHal),
4942 adapter->sessionId);
4943 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004944 hdd_err("Invalid SETRMCENABLE command %d",
4945 ucRmcEnable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004946 ret = -EINVAL;
4947 goto exit;
4948 }
4949
4950 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004951 hdd_err("SETRMC %d failed status %d",
4952 ucRmcEnable, status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004953 ret = -EINVAL;
4954 goto exit;
4955 }
4956
4957exit:
4958 return ret;
4959}
4960
4961static int drv_cmd_set_rmc_action_period(hdd_adapter_t *adapter,
4962 hdd_context_t *hdd_ctx,
4963 uint8_t *command,
4964 uint8_t command_len,
4965 hdd_priv_data_t *priv_data)
4966{
4967 int ret = 0;
4968 uint8_t *value = command;
4969 uint32_t uActionPeriod = 0;
4970 int status;
4971
Krunal Sonibe766b02016-03-10 13:00:44 -08004972 if ((QDF_IBSS_MODE != adapter->device_mode) &&
4973 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004974 hdd_err("Received SETRMC cmd in invalid mode %s(%d)",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004975 hdd_device_mode_to_string(adapter->device_mode),
4976 adapter->device_mode);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004977 hdd_err("SETRMC cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004978 ret = -EINVAL;
4979 goto exit;
4980 }
4981
4982 status = hdd_parse_setrmcactionperiod_command(value, &uActionPeriod);
4983 if (status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004984 hdd_err("Invalid SETRMCACTIONPERIOD command ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004985 ret = -EINVAL;
4986 goto exit;
4987 }
4988
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004989 hdd_info("uActionPeriod %d ",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004990 uActionPeriod);
4991
4992 if (sme_cfg_set_int(hdd_ctx->hHal,
4993 WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY,
4994 uActionPeriod)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004995 hdd_err("Could not set SETRMCACTIONPERIOD %d",
4996 uActionPeriod);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004997 ret = -EINVAL;
4998 goto exit;
4999 }
5000
5001 status = sme_send_rmc_action_period((tHalHandle)(hdd_ctx->hHal),
5002 adapter->sessionId);
5003 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005004 hdd_err("Could not send cesium enable indication %d",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005005 status);
5006 ret = -EINVAL;
5007 goto exit;
5008 }
5009
5010exit:
5011 return ret;
5012}
5013
5014static int drv_cmd_get_ibss_peer_info_all(hdd_adapter_t *adapter,
5015 hdd_context_t *hdd_ctx,
5016 uint8_t *command,
5017 uint8_t command_len,
5018 hdd_priv_data_t *priv_data)
5019{
5020 int ret = 0;
5021 int status = QDF_STATUS_SUCCESS;
5022 hdd_station_ctx_t *pHddStaCtx = NULL;
5023 char *extra = NULL;
5024 int idx = 0;
5025 int length = 0;
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005026 uint8_t mac_addr[QDF_MAC_ADDR_SIZE];
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005027 uint32_t numOfBytestoPrint = 0;
5028
Krunal Sonibe766b02016-03-10 13:00:44 -08005029 if (QDF_IBSS_MODE != adapter->device_mode) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005030 hdd_warn("Unsupported in mode %s(%d)",
5031 hdd_device_mode_to_string(adapter->device_mode),
5032 adapter->device_mode);
5033 return -EINVAL;
5034 }
5035
5036 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005037 hdd_info("Received GETIBSSPEERINFOALL Command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005038
5039 /* Handle the command */
5040 status = hdd_cfg80211_get_ibss_peer_info_all(adapter);
5041 if (QDF_STATUS_SUCCESS == status) {
5042 /*
5043 * The variable extra needed to be allocated on the heap since
5044 * amount of memory required to copy the data for 32 devices
5045 * exceeds the size of 1024 bytes of default stack size. On
5046 * 64 bit devices, the default max stack size of 2048 bytes
5047 */
5048 extra = kmalloc(WLAN_MAX_BUF_SIZE, GFP_KERNEL);
5049
5050 if (NULL == extra) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005051 hdd_err("kmalloc failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005052 ret = -EINVAL;
5053 goto exit;
5054 }
5055
5056 /* Copy number of stations */
5057 length = scnprintf(extra, WLAN_MAX_BUF_SIZE, "%d ",
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005058 pHddStaCtx->ibss_peer_info.numPeers);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005059 numOfBytestoPrint = length;
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005060 for (idx = 0; idx < pHddStaCtx->ibss_peer_info.numPeers;
5061 idx++) {
5062 int8_t rssi;
5063 uint32_t tx_rate;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005064
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005065 qdf_mem_copy(mac_addr,
5066 pHddStaCtx->ibss_peer_info.peerInfoParams[idx].
5067 mac_addr, sizeof(mac_addr));
5068
5069 tx_rate =
5070 pHddStaCtx->ibss_peer_info.peerInfoParams[idx].
5071 txRate;
Sriram Madhvapathi85df7c72016-09-30 11:35:28 +05305072 /*
5073 * Only lower 3 bytes are rate info. Mask of the MSByte
5074 */
5075 tx_rate &= 0x00FFFFFF;
5076
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005077 rssi = pHddStaCtx->ibss_peer_info.peerInfoParams[idx].
5078 rssi;
5079
5080 length += scnprintf((extra + length),
5081 WLAN_MAX_BUF_SIZE - length,
5082 "%02x:%02x:%02x:%02x:%02x:%02x %d %d ",
5083 mac_addr[0], mac_addr[1], mac_addr[2],
5084 mac_addr[3], mac_addr[4], mac_addr[5],
5085 tx_rate, rssi);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005086 /*
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005087 * cdf_trace_msg has limitation of 512 bytes for the
5088 * print buffer. Hence printing the data in two chunks.
5089 * The first chunk will have the data for 16 devices
5090 * and the second chunk will have the rest.
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005091 */
5092 if (idx < NUM_OF_STA_DATA_TO_PRINT)
5093 numOfBytestoPrint = length;
5094 }
5095
5096 /*
5097 * Copy the data back into buffer, if the data to copy is
5098 * more than 512 bytes than we will split the data and do
5099 * it in two shots
5100 */
5101 if (copy_to_user(priv_data->buf, extra, numOfBytestoPrint)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005102 hdd_err("Copy into user data buffer failed ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005103 ret = -EFAULT;
5104 goto exit;
5105 }
5106
5107 priv_data->buf[numOfBytestoPrint] = '\0';
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005108 hdd_debug("%s", priv_data->buf);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005109
5110 if (length > numOfBytestoPrint) {
5111 if (copy_to_user
5112 (priv_data->buf + numOfBytestoPrint,
5113 extra + numOfBytestoPrint,
5114 length - numOfBytestoPrint + 1)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005115 hdd_err("Copy into user data buffer failed ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005116 ret = -EFAULT;
5117 goto exit;
5118 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005119 hdd_debug("%s", &priv_data->buf[numOfBytestoPrint]);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005120 }
5121
5122 /* Free temporary buffer */
5123 kfree(extra);
5124 } else {
5125 /* Command failed, log error */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005126 hdd_err("GETIBSSPEERINFOALL command failed with status code %d",
5127 status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005128 ret = -EINVAL;
5129 goto exit;
5130 }
5131 ret = 0;
5132
5133exit:
5134 return ret;
5135}
5136
5137/* Peer Info <Peer Addr> command */
5138static int drv_cmd_get_ibss_peer_info(hdd_adapter_t *adapter,
5139 hdd_context_t *hdd_ctx,
5140 uint8_t *command,
5141 uint8_t command_len,
5142 hdd_priv_data_t *priv_data)
5143{
5144 int ret = 0;
5145 uint8_t *value = command;
5146 QDF_STATUS status;
5147 hdd_station_ctx_t *pHddStaCtx = NULL;
5148 char extra[128] = { 0 };
5149 uint32_t length = 0;
5150 uint8_t staIdx = 0;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005151 struct qdf_mac_addr peerMacAddr;
5152
Krunal Sonibe766b02016-03-10 13:00:44 -08005153 if (QDF_IBSS_MODE != adapter->device_mode) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005154 hdd_warn("Unsupported in mode %s(%d)",
5155 hdd_device_mode_to_string(adapter->device_mode),
5156 adapter->device_mode);
5157 return -EINVAL;
5158 }
5159
5160 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5161
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005162 hdd_info("Received GETIBSSPEERINFO Command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005163
5164 /* if there are no peers, no need to continue with the command */
5165 if (eConnectionState_IbssConnected !=
5166 pHddStaCtx->conn_info.connState) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005167 hdd_info("No IBSS Peers coalesced");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005168 ret = -EINVAL;
5169 goto exit;
5170 }
5171
5172 /* Parse the incoming command buffer */
5173 status = hdd_parse_get_ibss_peer_info(value, &peerMacAddr);
5174 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005175 hdd_err("Invalid GETIBSSPEERINFO command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005176 ret = -EINVAL;
5177 goto exit;
5178 }
5179
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005180 /* Get station index for the peer mac address and sanitize it */
Deepak Dhamdhere5872c8c2016-06-02 15:51:47 -07005181 hdd_get_peer_sta_id(pHddStaCtx, &peerMacAddr, &staIdx);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005182
Naveen Rawatc45d1622016-07-05 12:20:09 -07005183 if (staIdx > MAX_PEERS) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005184 hdd_err("Invalid StaIdx %d returned", staIdx);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005185 ret = -EINVAL;
5186 goto exit;
5187 }
5188
5189 /* Handle the command */
5190 status = hdd_cfg80211_get_ibss_peer_info(adapter, staIdx);
5191 if (QDF_STATUS_SUCCESS == status) {
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005192 uint32_t txRate =
5193 pHddStaCtx->ibss_peer_info.peerInfoParams[0].txRate;
Sriram Madhvapathi85df7c72016-09-30 11:35:28 +05305194 /* Only lower 3 bytes are rate info. Mask of the MSByte */
5195 txRate &= 0x00FFFFFF;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005196
5197 length = scnprintf(extra, sizeof(extra), "%d %d",
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005198 (int)txRate,
5199 (int)pHddStaCtx->ibss_peer_info.
5200 peerInfoParams[0].rssi);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005201
5202 /* Copy the data back into buffer */
5203 if (copy_to_user(priv_data->buf, &extra, length + 1)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005204 hdd_err("copy data to user buffer failed GETIBSSPEERINFO command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005205 ret = -EFAULT;
5206 goto exit;
5207 }
5208 } else {
5209 /* Command failed, log error */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005210 hdd_err("GETIBSSPEERINFO command failed with status code %d",
5211 status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005212 ret = -EINVAL;
5213 goto exit;
5214 }
5215
5216 /* Success ! */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005217 hdd_debug("%s", priv_data->buf);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005218 ret = 0;
5219
5220exit:
5221 return ret;
5222}
5223
5224static int drv_cmd_set_rmc_tx_rate(hdd_adapter_t *adapter,
5225 hdd_context_t *hdd_ctx,
5226 uint8_t *command,
5227 uint8_t command_len,
5228 hdd_priv_data_t *priv_data)
5229{
5230 int ret = 0;
5231 uint8_t *value = command;
5232 uint32_t uRate = 0;
5233 tTxrateinfoflags txFlags = 0;
5234 tSirRateUpdateInd rateUpdateParams = {0};
5235 int status;
5236 struct hdd_config *pConfig = hdd_ctx->config;
5237
Krunal Sonibe766b02016-03-10 13:00:44 -08005238 if ((QDF_IBSS_MODE != adapter->device_mode) &&
5239 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005240 hdd_err("Received SETRMCTXRATE cmd in invalid mode %s(%d)",
5241 hdd_device_mode_to_string(adapter->device_mode),
5242 adapter->device_mode);
5243 hdd_err("SETRMCTXRATE cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005244 ret = -EINVAL;
5245 goto exit;
5246 }
5247
5248 status = hdd_parse_setrmcrate_command(value, &uRate, &txFlags);
5249 if (status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005250 hdd_err("Invalid SETRMCTXRATE command ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005251 ret = -EINVAL;
5252 goto exit;
5253 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005254 hdd_info("uRate %d ", uRate);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005255 /* -1 implies ignore this param */
5256 rateUpdateParams.ucastDataRate = -1;
5257
5258 /*
5259 * Fill the user specifieed RMC rate param
5260 * and the derived tx flags.
5261 */
5262 rateUpdateParams.nss = (pConfig->enable2x2 == 0) ? 0 : 1;
5263 rateUpdateParams.reliableMcastDataRate = uRate;
5264 rateUpdateParams.reliableMcastDataRateTxFlag = txFlags;
5265 rateUpdateParams.dev_mode = adapter->device_mode;
5266 rateUpdateParams.bcastDataRate = -1;
5267 memcpy(rateUpdateParams.bssid.bytes,
5268 adapter->macAddressCurrent.bytes,
5269 sizeof(rateUpdateParams.bssid));
5270 status = sme_send_rate_update_ind((tHalHandle) (hdd_ctx->hHal),
5271 &rateUpdateParams);
5272
5273exit:
5274 return ret;
5275}
5276
5277static int drv_cmd_set_ibss_tx_fail_event(hdd_adapter_t *adapter,
5278 hdd_context_t *hdd_ctx,
5279 uint8_t *command,
5280 uint8_t command_len,
5281 hdd_priv_data_t *priv_data)
5282{
5283 int ret = 0;
5284 char *value;
5285 uint8_t tx_fail_count = 0;
5286 uint16_t pid = 0;
5287
5288 value = command;
5289
5290 ret = hdd_parse_ibsstx_fail_event_params(value, &tx_fail_count, &pid);
5291
5292 if (0 != ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005293 hdd_info("Failed to parse SETIBSSTXFAILEVENT arguments");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005294 goto exit;
5295 }
5296
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005297 hdd_info("tx_fail_cnt=%hhu, pid=%hu", tx_fail_count, pid);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005298
5299 if (0 == tx_fail_count) {
5300 /* Disable TX Fail Indication */
5301 if (QDF_STATUS_SUCCESS ==
5302 sme_tx_fail_monitor_start_stop_ind(hdd_ctx->hHal,
5303 tx_fail_count,
5304 NULL)) {
5305 cesium_pid = 0;
5306 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005307 hdd_err("failed to disable TX Fail Event ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005308 ret = -EINVAL;
5309 }
5310 } else {
5311 if (QDF_STATUS_SUCCESS ==
5312 sme_tx_fail_monitor_start_stop_ind(hdd_ctx->hHal,
5313 tx_fail_count,
5314 (void *)hdd_tx_fail_ind_callback)) {
5315 cesium_pid = pid;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005316 hdd_info("Registered Cesium pid %u",
5317 cesium_pid);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005318 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005319 hdd_err("Failed to enable TX Fail Monitoring");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005320 ret = -EINVAL;
5321 }
5322 }
5323
5324exit:
5325 return ret;
5326}
5327
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08005328#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005329static int drv_cmd_set_ccx_roam_scan_channels(hdd_adapter_t *adapter,
5330 hdd_context_t *hdd_ctx,
5331 uint8_t *command,
5332 uint8_t command_len,
5333 hdd_priv_data_t *priv_data)
5334{
5335 int ret = 0;
5336 uint8_t *value = command;
5337 uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
5338 uint8_t numChannels = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305339 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005340
5341 ret = hdd_parse_channellist(value, ChannelList, &numChannels);
5342 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005343 hdd_err("Failed to parse channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005344 goto exit;
5345 }
5346 if (numChannels > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005347 hdd_err("number of channels (%d) supported exceeded max (%d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005348 numChannels,
5349 WNI_CFG_VALID_CHANNEL_LIST_LEN);
5350 ret = -EINVAL;
5351 goto exit;
5352 }
5353 status = sme_set_ese_roam_scan_channel_list(hdd_ctx->hHal,
5354 adapter->sessionId,
5355 ChannelList,
5356 numChannels);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305357 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005358 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005359 ret = -EINVAL;
5360 goto exit;
5361 }
5362
5363exit:
5364 return ret;
5365}
5366
5367static int drv_cmd_get_tsm_stats(hdd_adapter_t *adapter,
5368 hdd_context_t *hdd_ctx,
5369 uint8_t *command,
5370 uint8_t command_len,
5371 hdd_priv_data_t *priv_data)
5372{
5373 int ret = 0;
5374 uint8_t *value = command;
5375 char extra[128] = { 0 };
5376 int len = 0;
5377 uint8_t tid = 0;
5378 hdd_station_ctx_t *pHddStaCtx;
5379 tAniTrafStrmMetrics tsm_metrics;
5380
Krunal Sonibe766b02016-03-10 13:00:44 -08005381 if ((QDF_STA_MODE != adapter->device_mode) &&
5382 (QDF_P2P_CLIENT_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005383 hdd_warn("Unsupported in mode %s(%d)",
5384 hdd_device_mode_to_string(adapter->device_mode),
5385 adapter->device_mode);
5386 return -EINVAL;
5387 }
5388
5389 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5390
5391 /* if not associated, return error */
5392 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005393 hdd_err("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005394 ret = -EINVAL;
5395 goto exit;
5396 }
5397
5398 /* Move pointer to ahead of GETTSMSTATS<delimiter> */
5399 value = value + command_len + 1;
5400
5401 /* Convert the value from ascii to integer */
5402 ret = kstrtou8(value, 10, &tid);
5403 if (ret < 0) {
5404 /*
5405 * If the input value is greater than max value of datatype,
5406 * then also kstrtou8 fails
5407 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005408 hdd_err("kstrtou8 failed range [%d - %d]",
5409 TID_MIN_VALUE,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005410 TID_MAX_VALUE);
5411 ret = -EINVAL;
5412 goto exit;
5413 }
5414 if ((tid < TID_MIN_VALUE) || (tid > TID_MAX_VALUE)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005415 hdd_err("tid value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005416 tid, TID_MIN_VALUE, TID_MAX_VALUE);
5417 ret = -EINVAL;
5418 goto exit;
5419 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005420 hdd_info("Received Command to get tsm stats tid = %d",
5421 tid);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305422 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005423 hdd_get_tsm_stats(adapter, tid, &tsm_metrics)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005424 hdd_err("failed to get tsm stats");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005425 ret = -EFAULT;
5426 goto exit;
5427 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005428 hdd_info(
5429 "UplinkPktQueueDly(%d) UplinkPktQueueDlyHist[0](%d) UplinkPktQueueDlyHist[1](%d) UplinkPktQueueDlyHist[2](%d) UplinkPktQueueDlyHist[3](%d) UplinkPktTxDly(%u) UplinkPktLoss(%d) UplinkPktCount(%d) RoamingCount(%d) RoamingDly(%d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005430 tsm_metrics.UplinkPktQueueDly,
5431 tsm_metrics.UplinkPktQueueDlyHist[0],
5432 tsm_metrics.UplinkPktQueueDlyHist[1],
5433 tsm_metrics.UplinkPktQueueDlyHist[2],
5434 tsm_metrics.UplinkPktQueueDlyHist[3],
5435 tsm_metrics.UplinkPktTxDly,
5436 tsm_metrics.UplinkPktLoss,
5437 tsm_metrics.UplinkPktCount,
5438 tsm_metrics.RoamingCount,
5439 tsm_metrics.RoamingDly);
5440 /*
5441 * Output TSM stats is of the format
5442 * GETTSMSTATS [PktQueueDly]
5443 * [PktQueueDlyHist[0]]:[PktQueueDlyHist[1]] ...[RoamingDly]
5444 * eg., GETTSMSTATS 10 1:0:0:161 20 1 17 8 39800
5445 */
5446 len = scnprintf(extra,
5447 sizeof(extra),
5448 "%s %d %d:%d:%d:%d %u %d %d %d %d",
5449 command,
5450 tsm_metrics.UplinkPktQueueDly,
5451 tsm_metrics.UplinkPktQueueDlyHist[0],
5452 tsm_metrics.UplinkPktQueueDlyHist[1],
5453 tsm_metrics.UplinkPktQueueDlyHist[2],
5454 tsm_metrics.UplinkPktQueueDlyHist[3],
5455 tsm_metrics.UplinkPktTxDly,
5456 tsm_metrics.UplinkPktLoss,
5457 tsm_metrics.UplinkPktCount,
5458 tsm_metrics.RoamingCount,
5459 tsm_metrics.RoamingDly);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305460 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005461 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005462 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005463 ret = -EFAULT;
5464 goto exit;
5465 }
5466
5467exit:
5468 return ret;
5469}
5470
5471static int drv_cmd_set_cckm_ie(hdd_adapter_t *adapter,
5472 hdd_context_t *hdd_ctx,
5473 uint8_t *command,
5474 uint8_t command_len,
5475 hdd_priv_data_t *priv_data)
5476{
5477 int ret;
5478 uint8_t *value = command;
5479 uint8_t *cckmIe = NULL;
5480 uint8_t cckmIeLen = 0;
5481
5482 ret = hdd_parse_get_cckm_ie(value, &cckmIe, &cckmIeLen);
5483 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005484 hdd_err("Failed to parse cckm ie data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005485 goto exit;
5486 }
5487
5488 if (cckmIeLen > DOT11F_IE_RSN_MAX_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005489 hdd_err("CCKM Ie input length is more than max[%d]",
5490 DOT11F_IE_RSN_MAX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005491 if (NULL != cckmIe) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305492 qdf_mem_free(cckmIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005493 cckmIe = NULL;
5494 }
5495 ret = -EINVAL;
5496 goto exit;
5497 }
5498
5499 sme_set_cckm_ie(hdd_ctx->hHal, adapter->sessionId,
5500 cckmIe, cckmIeLen);
5501 if (NULL != cckmIe) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305502 qdf_mem_free(cckmIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005503 cckmIe = NULL;
5504 }
5505
5506exit:
5507 return ret;
5508}
5509
5510static int drv_cmd_ccx_beacon_req(hdd_adapter_t *adapter,
5511 hdd_context_t *hdd_ctx,
5512 uint8_t *command,
5513 uint8_t command_len,
5514 hdd_priv_data_t *priv_data)
5515{
5516 int ret;
5517 uint8_t *value = command;
5518 tCsrEseBeaconReq eseBcnReq;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305519 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005520
Krunal Sonibe766b02016-03-10 13:00:44 -08005521 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005522 hdd_warn("Unsupported in mode %s(%d)",
5523 hdd_device_mode_to_string(adapter->device_mode),
5524 adapter->device_mode);
5525 return -EINVAL;
5526 }
5527
5528 ret = hdd_parse_ese_beacon_req(value, &eseBcnReq);
5529 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005530 hdd_err("Failed to parse ese beacon req");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005531 goto exit;
5532 }
5533
5534 if (!hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005535 hdd_info("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005536 hdd_indicate_ese_bcn_report_no_results(adapter,
5537 eseBcnReq.bcnReq[0].measurementToken,
5538 0x02, /* BIT(1) set for measurement done */
5539 0); /* no BSS */
5540 goto exit;
5541 }
5542
5543 status = sme_set_ese_beacon_request(hdd_ctx->hHal,
5544 adapter->sessionId,
5545 &eseBcnReq);
5546
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305547 if (QDF_STATUS_E_RESOURCES == status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005548 hdd_info("sme_set_ese_beacon_request failed (%d), a request already in progress",
5549 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005550 ret = -EBUSY;
5551 goto exit;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305552 } else if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005553 hdd_err("sme_set_ese_beacon_request failed (%d)",
5554 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005555 ret = -EINVAL;
5556 goto exit;
5557 }
5558
5559exit:
5560 return ret;
5561}
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005562
5563/**
5564 * drv_cmd_ccx_plm_req() - Set ESE PLM request
5565 * @adapter: Pointer to the HDD adapter
5566 * @hdd_ctx: Pointer to the HDD context
5567 * @command: Driver command string
5568 * @command_len: Driver command string length
5569 * @priv_data: Private data coming with the driver command. Unused here
5570 *
5571 * This function handles driver command that sets the ESE PLM request
5572 *
5573 * Return: 0 on success; negative errno otherwise
5574 */
5575static int drv_cmd_ccx_plm_req(hdd_adapter_t *adapter,
5576 hdd_context_t *hdd_ctx,
5577 uint8_t *command,
5578 uint8_t command_len,
5579 hdd_priv_data_t *priv_data)
5580{
5581 int ret = 0;
5582 uint8_t *value = command;
5583 QDF_STATUS status = QDF_STATUS_SUCCESS;
5584 tpSirPlmReq pPlmRequest = NULL;
5585
5586 pPlmRequest = qdf_mem_malloc(sizeof(tSirPlmReq));
5587 if (NULL == pPlmRequest) {
5588 ret = -ENOMEM;
5589 goto exit;
5590 }
5591
5592 status = hdd_parse_plm_cmd(value, pPlmRequest);
5593 if (QDF_STATUS_SUCCESS != status) {
5594 qdf_mem_free(pPlmRequest);
5595 pPlmRequest = NULL;
5596 ret = -EINVAL;
5597 goto exit;
5598 }
5599 pPlmRequest->sessionId = adapter->sessionId;
5600
5601 status = sme_set_plm_request(hdd_ctx->hHal, pPlmRequest);
5602 if (QDF_STATUS_SUCCESS != status) {
5603 qdf_mem_free(pPlmRequest);
5604 pPlmRequest = NULL;
5605 ret = -EINVAL;
5606 goto exit;
5607 }
5608
5609exit:
5610 return ret;
5611}
5612
5613/**
5614 * drv_cmd_set_ccx_mode() - Set ESE mode
5615 * @adapter: Pointer to the HDD adapter
5616 * @hdd_ctx: Pointer to the HDD context
5617 * @command: Driver command string
5618 * @command_len: Driver command string length
5619 * @priv_data: Private data coming with the driver command. Unused here
5620 *
5621 * This function handles driver command that sets ESE mode
5622 *
5623 * Return: 0 on success; negative errno otherwise
5624 */
5625static int drv_cmd_set_ccx_mode(hdd_adapter_t *adapter,
5626 hdd_context_t *hdd_ctx,
5627 uint8_t *command,
5628 uint8_t command_len,
5629 hdd_priv_data_t *priv_data)
5630{
5631 int ret = 0;
5632 uint8_t *value = command;
5633 uint8_t eseMode = CFG_ESE_FEATURE_ENABLED_DEFAULT;
5634
5635 /*
5636 * Check if the features OKC/ESE/11R are supported simultaneously,
5637 * then this operation is not permitted (return FAILURE)
5638 */
5639 if (sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
5640 hdd_is_okc_mode_enabled(hdd_ctx) &&
5641 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
5642 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
5643 ret = -EPERM;
5644 goto exit;
5645 }
5646
5647 /* Move pointer to ahead of SETCCXMODE<delimiter> */
5648 value = value + command_len + 1;
5649
5650 /* Convert the value from ascii to integer */
5651 ret = kstrtou8(value, 10, &eseMode);
5652 if (ret < 0) {
5653 /*
5654 * If the input value is greater than max value of datatype,
5655 * then also kstrtou8 fails
5656 */
5657 hdd_err("kstrtou8 failed range [%d - %d]",
5658 CFG_ESE_FEATURE_ENABLED_MIN,
5659 CFG_ESE_FEATURE_ENABLED_MAX);
5660 ret = -EINVAL;
5661 goto exit;
5662 }
5663
5664 if ((eseMode < CFG_ESE_FEATURE_ENABLED_MIN) ||
5665 (eseMode > CFG_ESE_FEATURE_ENABLED_MAX)) {
5666 hdd_err("Ese mode value %d is out of range (Min: %d Max: %d)",
5667 eseMode,
5668 CFG_ESE_FEATURE_ENABLED_MIN,
5669 CFG_ESE_FEATURE_ENABLED_MAX);
5670 ret = -EINVAL;
5671 goto exit;
5672 }
5673 hdd_info("Received Command to change ese mode = %d", eseMode);
5674
5675 hdd_ctx->config->isEseIniFeatureEnabled = eseMode;
5676 sme_update_is_ese_feature_enabled(hdd_ctx->hHal,
5677 adapter->sessionId,
5678 eseMode);
5679
5680exit:
5681 return ret;
5682}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08005683#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005684
5685static int drv_cmd_set_mc_rate(hdd_adapter_t *adapter,
5686 hdd_context_t *hdd_ctx,
5687 uint8_t *command,
5688 uint8_t command_len,
5689 hdd_priv_data_t *priv_data)
5690{
5691 int ret = 0;
5692 uint8_t *value = command;
5693 int targetRate;
5694
5695 /* input value is in units of hundred kbps */
5696
5697 /* Move pointer to ahead of SETMCRATE<delimiter> */
5698 value = value + command_len + 1;
5699
5700 /* Convert the value from ascii to integer, decimal base */
5701 ret = kstrtouint(value, 10, &targetRate);
5702
5703 ret = wlan_hdd_set_mc_rate(adapter, targetRate);
5704 return ret;
5705}
5706
5707static int drv_cmd_max_tx_power(hdd_adapter_t *adapter,
5708 hdd_context_t *hdd_ctx,
5709 uint8_t *command,
5710 uint8_t command_len,
5711 hdd_priv_data_t *priv_data)
5712{
5713 int ret = 0;
5714 int status;
5715 int txPower;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305716 QDF_STATUS qdf_status;
5717 QDF_STATUS smeStatus;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005718 uint8_t *value = command;
Anurag Chouhan6d760662016-02-20 16:05:43 +05305719 struct qdf_mac_addr bssid = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
5720 struct qdf_mac_addr selfMac = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005721 hdd_adapter_list_node_t *pAdapterNode = NULL;
5722 hdd_adapter_list_node_t *pNext = NULL;
5723
5724 status = hdd_parse_setmaxtxpower_command(value, &txPower);
5725 if (status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005726 hdd_err("Invalid MAXTXPOWER command ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005727 ret = -EINVAL;
5728 goto exit;
5729 }
5730
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305731 qdf_status = hdd_get_front_adapter(hdd_ctx, &pAdapterNode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005732 while (NULL != pAdapterNode
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305733 && QDF_STATUS_SUCCESS == qdf_status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005734 adapter = pAdapterNode->pAdapter;
5735 /* Assign correct self MAC address */
Anurag Chouhanc5548422016-02-24 18:33:27 +05305736 qdf_copy_macaddr(&bssid,
Srinivas Girigowda97215232015-09-24 12:26:28 -07005737 &adapter->macAddressCurrent);
Anurag Chouhanc5548422016-02-24 18:33:27 +05305738 qdf_copy_macaddr(&selfMac,
Srinivas Girigowda97215232015-09-24 12:26:28 -07005739 &adapter->macAddressCurrent);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005740
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005741 hdd_info("Device mode %d max tx power %d selfMac: "
5742 MAC_ADDRESS_STR " bssId: " MAC_ADDRESS_STR " ",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005743 adapter->device_mode, txPower,
Srinivas Girigowda97215232015-09-24 12:26:28 -07005744 MAC_ADDR_ARRAY(selfMac.bytes),
5745 MAC_ADDR_ARRAY(bssid.bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005746
Srinivas Girigowda97215232015-09-24 12:26:28 -07005747 smeStatus = sme_set_max_tx_power(hdd_ctx->hHal,
5748 bssid, selfMac, txPower);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305749 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005750 hdd_err("Set max tx power failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005751 ret = -EINVAL;
5752 goto exit;
5753 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005754 hdd_info("Set max tx power success");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305755 qdf_status = hdd_get_next_adapter(hdd_ctx, pAdapterNode,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005756 &pNext);
5757 pAdapterNode = pNext;
5758 }
5759
5760exit:
5761 return ret;
5762}
5763
5764static int drv_cmd_set_dfs_scan_mode(hdd_adapter_t *adapter,
5765 hdd_context_t *hdd_ctx,
5766 uint8_t *command,
5767 uint8_t command_len,
5768 hdd_priv_data_t *priv_data)
5769{
5770 int ret = 0;
5771 uint8_t *value = command;
5772 uint8_t dfsScanMode = CFG_ROAMING_DFS_CHANNEL_DEFAULT;
5773
5774 /* Move pointer to ahead of SETDFSSCANMODE<delimiter> */
5775 value = value + command_len + 1;
5776
5777 /* Convert the value from ascii to integer */
5778 ret = kstrtou8(value, 10, &dfsScanMode);
5779 if (ret < 0) {
5780 /*
5781 * If the input value is greater than max value of datatype,
5782 * then also kstrtou8 fails
5783 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005784 hdd_err("kstrtou8 failed range [%d - %d]",
5785 CFG_ROAMING_DFS_CHANNEL_MIN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005786 CFG_ROAMING_DFS_CHANNEL_MAX);
5787 ret = -EINVAL;
5788 goto exit;
5789 }
5790
5791 if ((dfsScanMode < CFG_ROAMING_DFS_CHANNEL_MIN) ||
5792 (dfsScanMode > CFG_ROAMING_DFS_CHANNEL_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005793 hdd_err("dfsScanMode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005794 dfsScanMode,
5795 CFG_ROAMING_DFS_CHANNEL_MIN,
5796 CFG_ROAMING_DFS_CHANNEL_MAX);
5797 ret = -EINVAL;
5798 goto exit;
5799 }
5800
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005801 hdd_info("Received Command to Set DFS Scan Mode = %d",
5802 dfsScanMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005803
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005804 /* When DFS scanning is disabled, the DFS channels need to be
5805 * removed from the operation of device.
5806 */
5807 ret = wlan_hdd_disable_dfs_chan_scan(hdd_ctx, adapter,
5808 (dfsScanMode == CFG_ROAMING_DFS_CHANNEL_DISABLED));
5809 if (ret < 0) {
5810 /* Some conditions prevented it from disabling DFS channels */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005811 hdd_err("disable/enable DFS channel request was denied");
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005812 goto exit;
5813 }
5814
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005815 hdd_ctx->config->allowDFSChannelRoam = dfsScanMode;
5816 sme_update_dfs_scan_mode(hdd_ctx->hHal, adapter->sessionId,
5817 dfsScanMode);
5818
5819exit:
5820 return ret;
5821}
5822
5823static int drv_cmd_get_dfs_scan_mode(hdd_adapter_t *adapter,
5824 hdd_context_t *hdd_ctx,
5825 uint8_t *command,
5826 uint8_t command_len,
5827 hdd_priv_data_t *priv_data)
5828{
5829 int ret = 0;
5830 uint8_t dfsScanMode = sme_get_dfs_scan_mode(hdd_ctx->hHal);
5831 char extra[32];
5832 uint8_t len = 0;
5833
5834 len = scnprintf(extra, sizeof(extra), "%s %d", command, dfsScanMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305835 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005836 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005837 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005838 ret = -EFAULT;
5839 }
5840
5841 return ret;
5842}
5843
5844static int drv_cmd_get_link_status(hdd_adapter_t *adapter,
5845 hdd_context_t *hdd_ctx,
5846 uint8_t *command,
5847 uint8_t command_len,
5848 hdd_priv_data_t *priv_data)
5849{
5850 int ret = 0;
5851 int value = wlan_hdd_get_link_status(adapter);
5852 char extra[32];
5853 uint8_t len;
5854
5855 len = scnprintf(extra, sizeof(extra), "%s %d", command, value);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305856 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005857 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005858 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005859 ret = -EFAULT;
5860 }
5861
5862 return ret;
5863}
5864
5865#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
5866static int drv_cmd_enable_ext_wow(hdd_adapter_t *adapter,
5867 hdd_context_t *hdd_ctx,
5868 uint8_t *command,
5869 uint8_t command_len,
5870 hdd_priv_data_t *priv_data)
5871{
5872 uint8_t *value = command;
5873 int set_value;
5874
5875 /* Move pointer to ahead of ENABLEEXTWOW */
5876 value = value + command_len;
5877
Anurag Chouhan43e0c752016-09-03 16:17:02 +05305878 if (!(sscanf(value, "%d", &set_value))) {
5879 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
5880 ("No input identified"));
5881 return -EINVAL;
5882 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005883
5884 return hdd_enable_ext_wow_parser(adapter,
5885 adapter->sessionId,
5886 set_value);
5887}
5888
5889static int drv_cmd_set_app1_params(hdd_adapter_t *adapter,
5890 hdd_context_t *hdd_ctx,
5891 uint8_t *command,
5892 uint8_t command_len,
5893 hdd_priv_data_t *priv_data)
5894{
5895 int ret;
5896 uint8_t *value = command;
5897
5898 /* Move pointer to ahead of SETAPP1PARAMS */
5899 value = value + command_len;
5900
5901 ret = hdd_set_app_type1_parser(adapter,
5902 value, strlen(value));
5903 if (ret >= 0)
5904 hdd_ctx->is_extwow_app_type1_param_set = true;
5905
5906 return ret;
5907}
5908
5909static int drv_cmd_set_app2_params(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
5918 /* Move pointer to ahead of SETAPP2PARAMS */
5919 value = value + command_len;
5920
5921 ret = hdd_set_app_type2_parser(adapter, value, strlen(value));
5922 if (ret >= 0)
5923 hdd_ctx->is_extwow_app_type2_param_set = true;
5924
5925 return ret;
5926}
5927#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
5928
5929#ifdef FEATURE_WLAN_TDLS
5930/**
5931 * drv_cmd_tdls_secondary_channel_offset() - secondary tdls off channel offset
5932 * @adapter: Pointer to the HDD adapter
5933 * @hdd_ctx: Pointer to the HDD context
5934 * @command: Driver command string
5935 * @command_len: Driver command string length
5936 * @priv_data: Private data coming with the driver command. Unused here
5937 *
5938 * This function handles driver command that sets the secondary tdls off channel
5939 * offset
5940 *
5941 * Return: 0 on success; negative errno otherwise
5942 */
5943static int drv_cmd_tdls_secondary_channel_offset(hdd_adapter_t *adapter,
5944 hdd_context_t *hdd_ctx,
5945 uint8_t *command,
5946 uint8_t command_len,
5947 hdd_priv_data_t *priv_data)
5948{
5949 int ret;
5950 uint8_t *value = command;
5951 int set_value;
5952
5953 /* Move pointer to point the string */
5954 value += command_len;
5955
5956 ret = sscanf(value, "%d", &set_value);
5957 if (ret != 1)
5958 return -EINVAL;
5959
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005960 hdd_info("Tdls offchannel offset:%d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005961
5962 ret = hdd_set_tdls_secoffchanneloffset(hdd_ctx, set_value);
5963
5964 return ret;
5965}
5966
5967/**
5968 * drv_cmd_tdls_off_channel_mode() - set tdls off channel mode
5969 * @adapter: Pointer to the HDD adapter
5970 * @hdd_ctx: Pointer to the HDD context
5971 * @command: Driver command string
5972 * @command_len: Driver command string length
5973 * @priv_data: Private data coming with the driver command. Unused here
5974 *
5975 * This function handles driver command that sets tdls off channel mode
5976 *
5977 * Return: 0 on success; negative errno otherwise
5978 */
5979static int drv_cmd_tdls_off_channel_mode(hdd_adapter_t *adapter,
5980 hdd_context_t *hdd_ctx,
5981 uint8_t *command,
5982 uint8_t command_len,
5983 hdd_priv_data_t *priv_data)
5984{
5985 int ret;
5986 uint8_t *value = command;
5987 int set_value;
5988
5989 /* Move pointer to point the string */
5990 value += command_len;
5991
5992 ret = sscanf(value, "%d", &set_value);
5993 if (ret != 1)
5994 return -EINVAL;
5995
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005996 hdd_info("Tdls offchannel mode:%d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005997
5998 ret = hdd_set_tdls_offchannelmode(adapter, set_value);
5999
6000 return ret;
6001}
6002
6003/**
6004 * drv_cmd_tdls_off_channel() - set tdls off channel number
6005 * @adapter: Pointer to the HDD adapter
6006 * @hdd_ctx: Pointer to the HDD context
6007 * @command: Driver command string
6008 * @command_len: Driver command string length
6009 * @priv_data: Private data coming with the driver command. Unused here
6010 *
6011 * This function handles driver command that sets tdls off channel number
6012 *
6013 * Return: 0 on success; negative errno otherwise
6014 */
6015static int drv_cmd_tdls_off_channel(hdd_adapter_t *adapter,
6016 hdd_context_t *hdd_ctx,
6017 uint8_t *command,
6018 uint8_t command_len,
6019 hdd_priv_data_t *priv_data)
6020{
6021 int ret;
6022 uint8_t *value = command;
6023 int set_value;
6024
6025 /* Move pointer to point the string */
6026 value += command_len;
6027
6028 ret = sscanf(value, "%d", &set_value);
6029 if (ret != 1)
6030 return -EINVAL;
6031
Krishna Kumaar Natarajan4d090352015-10-26 18:30:53 -07006032 if (CDS_IS_DFS_CH(set_value)) {
6033 hdd_err("DFS channel %d is passed for hdd_set_tdls_offchannel",
6034 set_value);
6035 return -EINVAL;
6036 }
6037
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006038 hdd_info("Tdls offchannel num: %d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006039
6040 ret = hdd_set_tdls_offchannel(hdd_ctx, set_value);
6041
6042 return ret;
6043}
6044
6045/**
6046 * drv_cmd_tdls_scan() - set tdls scan type
6047 * @adapter: Pointer to the HDD adapter
6048 * @hdd_ctx: Pointer to the HDD context
6049 * @command: Driver command string
6050 * @command_len: Driver command string length
6051 * @priv_data: Private data coming with the driver command. Unused here
6052 *
6053 * This function handles driver command that sets tdls scan type
6054 *
6055 * Return: 0 on success; negative errno otherwise
6056 */
6057static int drv_cmd_tdls_scan(hdd_adapter_t *adapter,
6058 hdd_context_t *hdd_ctx,
6059 uint8_t *command,
6060 uint8_t command_len,
6061 hdd_priv_data_t *priv_data)
6062{
6063 int ret;
6064 uint8_t *value = command;
6065 int set_value;
6066
6067 /* Move pointer to point the string */
6068 value += command_len;
6069
6070 ret = sscanf(value, "%d", &set_value);
6071 if (ret != 1)
6072 return -EINVAL;
6073
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006074 hdd_info("Tdls scan type val: %d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006075
6076 ret = hdd_set_tdls_scan_type(hdd_ctx, set_value);
6077
6078 return ret;
6079}
6080#endif
6081
6082static int drv_cmd_get_rssi(hdd_adapter_t *adapter,
6083 hdd_context_t *hdd_ctx,
6084 uint8_t *command,
6085 uint8_t command_len,
6086 hdd_priv_data_t *priv_data)
6087{
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006088 int ret = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006089 int8_t rssi = 0;
6090 char extra[32];
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006091
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006092 uint8_t len = 0;
6093
6094 wlan_hdd_get_rssi(adapter, &rssi);
6095
6096 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
Anurag Chouhan6d760662016-02-20 16:05:43 +05306097 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006098
6099 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006100 hdd_err("Failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006101 ret = -EFAULT;
6102 }
6103
6104 return ret;
6105}
6106
6107static int drv_cmd_get_linkspeed(hdd_adapter_t *adapter,
6108 hdd_context_t *hdd_ctx,
6109 uint8_t *command,
6110 uint8_t command_len,
6111 hdd_priv_data_t *priv_data)
6112{
6113 int ret;
6114 uint32_t link_speed = 0;
6115 char extra[32];
6116 uint8_t len = 0;
6117
6118 ret = wlan_hdd_get_link_speed(adapter, &link_speed);
6119 if (0 != ret)
6120 return ret;
6121
6122 len = scnprintf(extra, sizeof(extra), "%s %d", command, link_speed);
Anurag Chouhan6d760662016-02-20 16:05:43 +05306123 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006124 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006125 hdd_err("Failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006126 ret = -EFAULT;
6127 }
6128
6129 return ret;
6130}
6131
6132#ifdef FEATURE_NAPI
6133/**
6134 * hdd_parse_napi() - helper functions to drv_cmd_napi
6135 * @str : source string to parse
6136 * @cmd : pointer to cmd part after parsing
6137 * @sub : pointer to subcmd part after parsing
6138 * @aux : pointer to optional aux part after parsing
6139 *
6140 * Example:
6141 * NAPI SCALE <n> +-- IN str
6142 * | | +------ OUT aux
6143 * | +------------ OUT subcmd
6144 * +----------------- OUT cmd
6145 *
6146 * Return: ==0: success; !=0: failure
6147 */
6148static int hdd_parse_napi(char **str, char **cmd, char **sub, char **aux)
6149{
6150 int rc;
6151 char *token, *lcmd = NULL, *lsub = NULL, *laux = NULL;
6152
6153 NAPI_DEBUG("-->\n");
6154
6155 token = strsep(str, " \t");
6156 if (NULL == token) {
6157 hdd_err("cannot parse cmd");
6158 goto parse_end;
6159 }
6160 lcmd = token;
6161
6162 token = strsep(str, " \t");
6163 if (NULL == token) {
6164 hdd_err("cannot parse subcmd");
6165 goto parse_end;
6166 }
6167 lsub = token;
6168
6169 token = strsep(str, " \t");
6170 if (NULL == token)
6171 hdd_warn("cannot parse aux\n");
6172 else
6173 laux = token;
6174
6175parse_end:
6176 if ((NULL == lcmd) || (NULL == lsub))
6177 rc = -EINVAL;
6178 else {
6179 rc = 0;
6180 *cmd = lcmd;
6181 *sub = lsub;
6182 if (NULL != aux)
6183 *aux = laux;
6184 }
6185 NAPI_DEBUG("<--[rc=%d]\n", rc);
6186 return rc;
6187}
6188
6189
6190/**
6191 * hdd_parse_stats() - print NAPI stats into a buffer
6192 * @buf : buffer to write stats into
6193 * @max : "size of buffer"
6194 * @idp : NULL: all stats, otherwise, ptr to the NAPI instance
6195 * @napid: binary structure to retrieve the stats from
6196 *
6197 * Return: number of bytes written into the buffer
6198 */
6199int hdd_napi_stats(char *buf,
6200 int max,
6201 char *indp,
6202 struct qca_napi_data *napid)
6203{
6204 int n = 0;
6205 int i, j, k; /* NAPI, CPU, bucket indices */
6206 int from, to;
6207 struct qca_napi_info *napii;
6208 struct qca_napi_stat *napis;
6209
6210 NAPI_DEBUG("-->\n");
6211
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006212 if (NULL == napid)
6213 return n;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006214 if (NULL == indp) {
6215 from = 0;
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006216 to = CE_COUNT_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006217 } else {
6218 if (0 > kstrtoint(indp, 10, &to)) {
6219 from = 0;
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006220 to = CE_COUNT_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006221 } else
6222 from = to;
6223 }
6224
6225 for (i = from; i < to; i++)
6226 if (napid->ce_map & (0x01 << i)) {
6227 napii = &(napid->napis[i]);
6228 for (j = 0; j < NR_CPUS; j++) {
6229 napis = &(napii->stats[j]);
6230 n += scnprintf(buf + n, max - n,
6231 "STATS: NAPI[%d] CPU: %d scheds: %d polls: %d completes: %d done: %d ",
6232 i, j,
6233 napis->napi_schedules,
6234 napis->napi_polls,
6235 napis->napi_completes,
6236 napis->napi_workdone);
6237
6238 for (k = 0; k < QCA_NAPI_NUM_BUCKETS; k++) {
6239 n += scnprintf(
6240 buf + n, max - n,
6241 " %d",
6242 napis->napi_budget_uses[k]);
6243 }
6244 n += scnprintf(buf+n, max - n, "\n");
6245 }
6246 }
6247
6248 NAPI_DEBUG("<--[n=%d]\n", n);
6249 return n;
6250}
6251
6252/**
6253 * napi_set_scale() - sets the scale attribute in all NAPI entries
6254 * @sc : scale to set
6255 *
6256 * Return: void
6257 */
6258static void napi_set_scale(uint8_t sc)
6259{
6260 uint32_t i;
6261 struct qca_napi_data *napi_data;
6262
6263 napi_data = hdd_napi_get_all();
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006264 if (likely(NULL != napi_data))
6265 for (i = 0; i < CE_COUNT_MAX; i++)
6266 if (napi_data->ce_map & (0x01 << i))
6267 napi_data->napis[i].scale = sc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006268
6269 return;
6270}
6271/**
6272 * drv_cmd_napi() - processes NAPI commands
6273 * @adapter : net_device
6274 * @hdd_ctx : HDD context
6275 * @command : command string from user command (including "NAPI")
6276 * @command_len: length of command
6277 * @priv_data : ifr_data
6278 *
6279 * Commands supported:
6280 * NAPI ENABLE : enables NAPI administratively. Note that this may not
6281 * enable NAPI functionally, as some other conditions
6282 * may not have been satisfied yet
6283 * NAPI DISABLE : reverse operation of "enable"
6284 * NAPI STATUS : get global status of NAPI instances
6285 * NAPI STATS [<n>] : get the stats for a given NAPI instance
6286 * NAPI SCALE <n> : set the scale factor
6287 *
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006288 * Return: 0: success; !0: failure
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006289 */
6290static int drv_cmd_napi(hdd_adapter_t *adapter,
6291 hdd_context_t *hdd_ctx,
6292 uint8_t *command,
6293 uint8_t command_len,
6294 hdd_priv_data_t *priv_data)
6295{
6296 int rc = 0;
6297 int n, l;
6298 char *cmd = NULL, *subcmd = NULL, *aux = NULL;
6299 char *synopsis = "NAPI ENABLE\n"
6300 "NAPI DISABLE\n"
6301 "NAPI STATUS\n"
6302 "NAPI STATS [<n>] -- if no <n> then all\n"
6303 "NAPI SCALE <n> -- set the scale\n";
6304 char *reply = NULL;
6305
6306 /* make a local copy, as strsep modifies the str in place */
6307 char *str = NULL;
6308
6309 NAPI_DEBUG("-->\n");
6310
6311 /**
6312 * NOTE TO MAINTAINER: from this point to the end of the function,
6313 * please do not return anywhere in the code except the very end
6314 * to avoid memory leakage (goto end_drv_napi instead)
6315 * or make sure that reply+str is freed
6316 */
6317 reply = kmalloc(MAX_USER_COMMAND_SIZE, GFP_KERNEL);
6318 if (NULL == reply) {
6319 hdd_err("could not allocate reply buffer");
6320 rc = -ENOMEM;
6321 goto end_drv_napi;
6322 }
6323
6324 str = kmalloc(strlen(command) + 1, GFP_KERNEL);
6325 if (NULL == str) {
6326 hdd_err("could not allocate copy of input buffer");
6327 rc = -ENOMEM;
6328 goto end_drv_napi;
6329 }
6330
6331 strlcpy(str, command, strlen(command) + 1);
6332 hdd_debug("parsing command into cmd=0x%p sub=0x%p aux=0x%p\n",
6333 cmd, subcmd, aux);
6334
6335
6336 rc = hdd_parse_napi(&str, &cmd, &subcmd, &aux);
6337
6338 if (0 != rc) {
6339 const char *msg = "unknown or badly formatted cmd\n%s";
Anurag Chouhan6d760662016-02-20 16:05:43 +05306340 l = QDF_MIN(MAX_USER_COMMAND_SIZE,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006341 strlen(msg)+strlen(synopsis));
6342 n = scnprintf(reply, l, msg, synopsis);
6343
6344 if (copy_to_user(priv_data->buf, reply,
Anurag Chouhan6d760662016-02-20 16:05:43 +05306345 QDF_MIN(priv_data->total_len, l)))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006346 hdd_err("failed to copy data to user buffer");
6347 hdd_debug("reply: %s", reply);
6348
6349 rc = -EINVAL;
6350 } else {
6351 hdd_debug("cmd=(%s) subcmd=(%s) aux=(%s)\n",
6352 cmd, subcmd, aux);
6353 if (!strcmp(subcmd, "ENABLE"))
6354 hdd_napi_event(NAPI_EVT_CMD_STATE, (void *)1);
6355 else if (!strcmp(subcmd, "DISABLE"))
6356 hdd_napi_event(NAPI_EVT_CMD_STATE, (void *)0);
6357 else if (!strcmp(subcmd, "STATUS")) {
6358 int n = 0;
6359 uint32_t i;
6360 struct qca_napi_data *napi_data;
6361
6362 napi_data = hdd_napi_get_all();
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006363 if (unlikely(NULL == napi_data))
6364 goto status_end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006365 n += scnprintf(reply+n, MAX_USER_COMMAND_SIZE - n,
6366 "NAPI state: 0x%08x map: 0x%08x\n",
6367 napi_data->state,
6368 napi_data->ce_map);
6369
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006370 for (i = 0; i < CE_COUNT_MAX; i++)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006371 if (napi_data->ce_map & (0x01 << i)) {
6372 n += scnprintf(
6373 reply + n,
6374 MAX_USER_COMMAND_SIZE - n,
6375 "#%d: id: %d, scale=%d\n",
6376 i,
6377 napi_data->napis[i].id,
6378 napi_data->napis[i].scale);
6379 }
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006380 status_end:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006381 hdd_info("wlan: STATUS DATA:\n%s", reply);
6382 if (copy_to_user(priv_data->buf, reply,
Anurag Chouhan6d760662016-02-20 16:05:43 +05306383 QDF_MIN(n, priv_data->total_len)))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006384 rc = -EINVAL;
6385 } else if (!strcmp(subcmd, "STATS")) {
6386 int n = 0;
6387 struct qca_napi_data *napi_data;
6388
6389 napi_data = hdd_napi_get_all();
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006390 if (NULL != napi_data) {
6391 n = hdd_napi_stats(reply, MAX_USER_COMMAND_SIZE,
6392 aux, napi_data);
6393 NAPI_DEBUG("STATS: returns %d\n", n);
6394 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006395 if (n > 0) {
6396 if (copy_to_user(priv_data->buf, reply,
Anurag Chouhan6d760662016-02-20 16:05:43 +05306397 QDF_MIN(priv_data->total_len,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006398 n)))
6399 rc = -EINVAL;
6400 hdd_info("wlan: STATS_DATA\n%s\n", reply);
6401 } else
6402 rc = -EINVAL;
6403 } else if (!strcmp(subcmd, "SCALE")) {
6404 if (NULL == aux) {
6405 rc = -EINVAL;
6406 hdd_err("wlan: SCALE cmd requires <n>");
6407 } else {
6408 uint8_t sc;
6409 rc = kstrtou8(aux, 10, &sc);
6410 if (rc) {
6411 hdd_err("wlan: bad scale (%s)", aux);
6412 rc = -EINVAL;
6413 } else
6414 napi_set_scale(sc);
6415 }
6416 } /* SCALE */
6417 }
6418end_drv_napi:
6419 if (NULL != str)
6420 kfree(str);
6421 if (NULL != reply)
6422 kfree(reply);
6423
6424 NAPI_DEBUG("<--[rc=%d]\n", rc);
6425 return rc;
6426}
6427#endif /* FEATURE_NAPI */
6428
6429/**
6430 * hdd_set_rx_filter() - set RX filter
6431 * @adapter: Pointer to adapter
6432 * @action: Filter action
6433 * @pattern: Address pattern
6434 *
6435 * Address pattern is most significant byte of address for example
6436 * 0x01 for IPV4 multicast address
6437 * 0x33 for IPV6 multicast address
6438 * 0xFF for broadcast address
6439 *
6440 * Return: 0 for success, non-zero for failure
6441 */
6442static int hdd_set_rx_filter(hdd_adapter_t *adapter, bool action,
6443 uint8_t pattern)
6444{
6445 int ret;
Frank Liuf95e8132016-09-29 19:01:30 +08006446 uint8_t i, j;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006447 tHalHandle handle;
6448 tSirRcvFltMcAddrList *filter;
6449 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
6450
6451 ret = wlan_hdd_validate_context(hdd_ctx);
6452 if (0 != ret)
6453 return ret;
6454
6455 handle = hdd_ctx->hHal;
6456
6457 if (NULL == handle) {
6458 hdd_err("HAL Handle is NULL");
6459 return -EINVAL;
6460 }
6461
6462 /*
6463 * If action is false it means start dropping packets
6464 * Set addr_filter_pattern which will be used when sending
6465 * MC/BC address list to target
6466 */
6467 if (!action)
6468 adapter->addr_filter_pattern = pattern;
6469 else
6470 adapter->addr_filter_pattern = 0;
6471
Krunal Sonibe766b02016-03-10 13:00:44 -08006472 if (((adapter->device_mode == QDF_STA_MODE) ||
6473 (adapter->device_mode == QDF_P2P_CLIENT_MODE)) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006474 adapter->mc_addr_list.mc_cnt &&
6475 hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
6476
6477
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306478 filter = qdf_mem_malloc(sizeof(*filter));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006479 if (NULL == filter) {
6480 hdd_err("Could not allocate Memory");
6481 return -ENOMEM;
6482 }
6483 filter->action = action;
Frank Liuf95e8132016-09-29 19:01:30 +08006484 for (i = 0, j = 0; i < adapter->mc_addr_list.mc_cnt; i++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006485 if (!memcmp(adapter->mc_addr_list.addr[i],
6486 &pattern, 1)) {
Frank Liuf95e8132016-09-29 19:01:30 +08006487 memcpy(filter->multicastAddr[j].bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006488 adapter->mc_addr_list.addr[i],
6489 sizeof(adapter->mc_addr_list.addr[i]));
Frank Liuf95e8132016-09-29 19:01:30 +08006490
Srinivas Girigowdaf2599dd2015-11-16 18:20:46 -08006491 hdd_info("%s RX filter : addr ="
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006492 MAC_ADDRESS_STR,
6493 action ? "setting" : "clearing",
Frank Liuf95e8132016-09-29 19:01:30 +08006494 MAC_ADDR_ARRAY(filter->multicastAddr[j].bytes));
6495 j++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006496 }
6497 }
Frank Liuf95e8132016-09-29 19:01:30 +08006498 filter->ulMulticastAddrCnt = j;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006499 /* Set rx filter */
6500 sme_8023_multicast_list(handle, adapter->sessionId, filter);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306501 qdf_mem_free(filter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006502 } else {
Srinivas Girigowdaf2599dd2015-11-16 18:20:46 -08006503 hdd_info("mode %d mc_cnt %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006504 adapter->device_mode, adapter->mc_addr_list.mc_cnt);
6505 }
6506
6507 return 0;
6508}
6509
6510/**
6511 * hdd_driver_rxfilter_comand_handler() - RXFILTER driver command handler
6512 * @command: Pointer to input string driver command
6513 * @adapter: Pointer to adapter
6514 * @action: Action to enable/disable filtering
6515 *
6516 * If action == false
6517 * Start filtering out data packets based on type
6518 * RXFILTER-REMOVE 0 -> Start filtering out unicast data packets
6519 * RXFILTER-REMOVE 1 -> Start filtering out broadcast data packets
6520 * RXFILTER-REMOVE 2 -> Start filtering out IPV4 mcast data packets
6521 * RXFILTER-REMOVE 3 -> Start filtering out IPV6 mcast data packets
6522 *
6523 * if action == true
6524 * Stop filtering data packets based on type
6525 * RXFILTER-ADD 0 -> Stop filtering unicast data packets
6526 * RXFILTER-ADD 1 -> Stop filtering broadcast data packets
6527 * RXFILTER-ADD 2 -> Stop filtering IPV4 mcast data packets
6528 * RXFILTER-ADD 3 -> Stop filtering IPV6 mcast data packets
6529 *
6530 * Current implementation only supports IPV4 address filtering by
6531 * selectively allowing IPV4 multicast data packest based on
6532 * address list received in .ndo_set_rx_mode
6533 *
6534 * Return: 0 for success, non-zero for failure
6535 */
6536static int hdd_driver_rxfilter_comand_handler(uint8_t *command,
6537 hdd_adapter_t *adapter,
6538 bool action)
6539{
6540 int ret = 0;
6541 uint8_t *value;
6542 uint8_t type;
6543
6544 value = command;
6545 /* Skip space after RXFILTER-REMOVE OR RXFILTER-ADD based on action */
6546 if (!action)
6547 value = command + 16;
6548 else
6549 value = command + 13;
6550 ret = kstrtou8(value, 10, &type);
6551 if (ret < 0) {
6552 hdd_err("kstrtou8 failed invalid input value %d", type);
6553 return -EINVAL;
6554 }
6555
6556 switch (type) {
6557 case 2:
6558 /* Set rx filter for IPV4 multicast data packets */
6559 ret = hdd_set_rx_filter(adapter, action, 0x01);
6560 break;
6561 default:
6562 hdd_info("Unsupported RXFILTER type %d", type);
6563 break;
6564 }
6565
6566 return ret;
6567}
6568
6569/**
6570 * drv_cmd_rx_filter_remove() - RXFILTER REMOVE driver command handler
6571 * @adapter: Pointer to network adapter
6572 * @hdd_ctx: Pointer to hdd context
6573 * @command: Pointer to input command
6574 * @command_len: Command length
6575 * @priv_data: Pointer to private data in command
6576 */
6577static int drv_cmd_rx_filter_remove(hdd_adapter_t *adapter,
6578 hdd_context_t *hdd_ctx,
6579 uint8_t *command,
6580 uint8_t command_len,
6581 hdd_priv_data_t *priv_data)
6582{
6583 return hdd_driver_rxfilter_comand_handler(command, adapter, false);
6584}
6585
6586/**
6587 * drv_cmd_rx_filter_add() - RXFILTER ADD driver command handler
6588 * @adapter: Pointer to network adapter
6589 * @hdd_ctx: Pointer to hdd context
6590 * @command: Pointer to input command
6591 * @command_len: Command length
6592 * @priv_data: Pointer to private data in command
6593 */
6594static int drv_cmd_rx_filter_add(hdd_adapter_t *adapter,
6595 hdd_context_t *hdd_ctx,
6596 uint8_t *command,
6597 uint8_t command_len,
6598 hdd_priv_data_t *priv_data)
6599{
6600 return hdd_driver_rxfilter_comand_handler(command, adapter, true);
6601}
6602
Archana Ramachandran393f3792015-11-13 17:13:21 -08006603/**
6604 * hdd_parse_setantennamode_command() - HDD Parse SETANTENNAMODE
6605 * command
6606 * @value: Pointer to SETANTENNAMODE command
6607 * @mode: Pointer to antenna mode
6608 * @reason: Pointer to reason for set antenna mode
6609 *
6610 * This function parses the SETANTENNAMODE command passed in the format
6611 * SETANTENNAMODE<space>mode
6612 *
6613 * Return: 0 for success non-zero for failure
6614 */
6615static int hdd_parse_setantennamode_command(const uint8_t *value)
6616{
6617 const uint8_t *in_ptr = value;
6618 int tmp, v;
6619 char arg1[32];
6620
6621 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
6622
6623 /* no argument after the command */
6624 if (NULL == in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006625 hdd_err("No argument after the command");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006626 return -EINVAL;
6627 }
6628
6629 /* no space after the command */
6630 if (SPACE_ASCII_VALUE != *in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006631 hdd_err("No space after the command");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006632 return -EINVAL;
6633 }
6634
6635 /* remove empty spaces */
6636 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
6637 in_ptr++;
6638
6639 /* no argument followed by spaces */
6640 if ('\0' == *in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006641 hdd_err("No argument followed by spaces");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006642 return -EINVAL;
6643 }
6644
6645 /* get the argument i.e. antenna mode */
6646 v = sscanf(in_ptr, "%31s ", arg1);
6647 if (1 != v) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006648 hdd_err("argument retrieval from cmd string failed");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006649 return -EINVAL;
6650 }
6651
6652 v = kstrtos32(arg1, 10, &tmp);
6653 if (v < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006654 hdd_err("argument string to int conversion failed");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006655 return -EINVAL;
6656 }
6657
6658 return tmp;
6659}
6660
6661/**
6662 * hdd_is_supported_chain_mask_2x2() - Verify if supported chain
6663 * mask is 2x2 mode
6664 * @hdd_ctx: Pointer to hdd contex
6665 *
6666 * Return: true if supported chain mask 2x2 else false
6667 */
6668static bool hdd_is_supported_chain_mask_2x2(hdd_context_t *hdd_ctx)
6669{
6670 /*
6671 * Revisit and the update logic to determine the number
6672 * of TX/RX chains supported in the system when
6673 * antenna sharing per band chain mask support is
6674 * brought in
6675 */
6676 return (hdd_ctx->config->enable2x2 == 0x01) ? true : false;
6677}
6678
6679/**
6680 * hdd_is_supported_chain_mask_1x1() - Verify if the supported
6681 * chain mask is 1x1
6682 * @hdd_ctx: Pointer to hdd contex
6683 *
6684 * Return: true if supported chain mask 1x1 else false
6685 */
6686static bool hdd_is_supported_chain_mask_1x1(hdd_context_t *hdd_ctx)
6687{
6688 /*
6689 * Revisit and update the logic to determine the number
6690 * of TX/RX chains supported in the system when
6691 * antenna sharing per band chain mask support is
6692 * brought in
6693 */
6694 return (!hdd_ctx->config->enable2x2) ? true : false;
6695}
6696
6697/**
6698 * drv_cmd_set_antenna_mode() - SET ANTENNA MODE driver command
6699 * handler
6700 * @adapter: Pointer to network adapter
6701 * @hdd_ctx: Pointer to hdd context
6702 * @command: Pointer to input command
6703 * @command_len: Command length
6704 * @priv_data: Pointer to private data in command
6705 */
6706static int drv_cmd_set_antenna_mode(hdd_adapter_t *adapter,
6707 hdd_context_t *hdd_ctx,
6708 uint8_t *command,
6709 uint8_t command_len,
6710 hdd_priv_data_t *priv_data)
6711{
6712 struct sir_antenna_mode_param params;
6713 QDF_STATUS status;
6714 int ret = 0;
6715 int mode;
6716 uint8_t *value = command;
6717 uint8_t smps_mode;
6718 uint8_t smps_enable;
6719
6720 if (((1 << QDF_STA_MODE) != hdd_ctx->concurrency_mode) ||
6721 (hdd_ctx->no_of_active_sessions[QDF_STA_MODE] > 1)) {
6722 hdd_err("Operation invalid in non sta or concurrent mode");
6723 ret = -EPERM;
6724 goto exit;
6725 }
6726
6727 mode = hdd_parse_setantennamode_command(value);
6728 if (mode < 0) {
6729 hdd_err("Invalid SETANTENNA command");
6730 ret = mode;
6731 goto exit;
6732 }
6733
6734 hdd_info("Processing antenna mode switch to: %d", mode);
6735
6736 if (hdd_ctx->current_antenna_mode == mode) {
6737 hdd_err("System already in the requested mode");
6738 ret = 0;
6739 goto exit;
6740 }
6741
6742 if ((HDD_ANTENNA_MODE_2X2 == mode) &&
6743 (!hdd_is_supported_chain_mask_2x2(hdd_ctx))) {
6744 hdd_err("System does not support 2x2 mode");
6745 ret = -EPERM;
6746 goto exit;
6747 }
6748
6749 if ((HDD_ANTENNA_MODE_1X1 == mode) &&
6750 hdd_is_supported_chain_mask_1x1(hdd_ctx)) {
6751 hdd_err("System only supports 1x1 mode");
6752 ret = 0;
6753 goto exit;
6754 }
6755
6756 switch (mode) {
6757 case HDD_ANTENNA_MODE_1X1:
6758 params.num_rx_chains = 1;
6759 params.num_tx_chains = 1;
6760 break;
6761 case HDD_ANTENNA_MODE_2X2:
6762 params.num_rx_chains = 2;
6763 params.num_tx_chains = 2;
6764 break;
6765 default:
6766 hdd_err("unsupported antenna mode");
6767 ret = -EINVAL;
6768 goto exit;
6769 }
6770
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006771 /* Check TDLS status and update antenna mode */
6772 if ((QDF_STA_MODE == adapter->device_mode) &&
Kabilan Kannan32eb5022016-10-04 12:24:50 -07006773 cds_is_sta_active_connection_exists()) {
Archana Ramachandran2ad7de22016-04-22 16:53:25 -07006774 ret = wlan_hdd_tdls_antenna_switch(hdd_ctx, adapter,
6775 mode);
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006776 if (0 != ret)
6777 goto exit;
6778 }
6779
Archana Ramachandran393f3792015-11-13 17:13:21 -08006780 params.set_antenna_mode_resp =
6781 (void *)wlan_hdd_soc_set_antenna_mode_cb;
6782 hdd_info("Set antenna mode rx chains: %d tx chains: %d",
6783 params.num_rx_chains,
6784 params.num_tx_chains);
6785
6786
6787 INIT_COMPLETION(hdd_ctx->set_antenna_mode_cmpl);
6788 status = sme_soc_set_antenna_mode(hdd_ctx->hHal, &params);
6789 if (QDF_STATUS_SUCCESS != status) {
6790 hdd_err("set antenna mode failed status : %d", status);
6791 ret = -EFAULT;
6792 goto exit;
6793 }
6794
6795 ret = wait_for_completion_timeout(
6796 &hdd_ctx->set_antenna_mode_cmpl,
6797 msecs_to_jiffies(WLAN_WAIT_TIME_ANTENNA_MODE_REQ));
6798 if (!ret) {
6799 ret = -EFAULT;
6800 hdd_err("send set antenna mode timed out");
6801 goto exit;
6802 }
6803
6804 /* Update SME SMPS config */
6805 if (HDD_ANTENNA_MODE_1X1 == mode) {
6806 smps_enable = true;
6807 smps_mode = HDD_SMPS_MODE_STATIC;
6808 } else {
6809 smps_enable = false;
6810 smps_mode = HDD_SMPS_MODE_DISABLED;
6811 }
6812
6813 hdd_info("Update SME SMPS enable: %d mode: %d",
6814 smps_enable, smps_mode);
6815 status = sme_update_mimo_power_save(
6816 hdd_ctx->hHal, smps_enable, smps_mode, false);
6817 if (QDF_STATUS_SUCCESS != status) {
6818 hdd_err("Update SMPS config failed enable: %d mode: %d status: %d",
6819 smps_enable, smps_mode, status);
6820 ret = -EFAULT;
6821 goto exit;
6822 }
6823
Archana Ramachandran393f3792015-11-13 17:13:21 -08006824 hdd_ctx->current_antenna_mode = mode;
Archana Ramachandran5041b252016-04-25 14:29:25 -07006825 /* Update the user requested nss in the mac context.
6826 * This will be used in tdls protocol engine to form tdls
6827 * Management frames.
6828 */
6829 sme_update_user_configured_nss(
6830 hdd_ctx->hHal,
6831 hdd_ctx->current_antenna_mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006832
Archana Ramachandran5041b252016-04-25 14:29:25 -07006833 hdd_info("Successfully switched to mode: %d x %d",
6834 hdd_ctx->current_antenna_mode,
6835 hdd_ctx->current_antenna_mode);
6836 ret = 0;
Archana Ramachandran393f3792015-11-13 17:13:21 -08006837exit:
Kabilan Kannanff89f742016-08-15 18:14:10 -07006838#ifdef FEATURE_WLAN_TDLS
6839 /* Reset tdls NSS flags */
6840 if (hdd_ctx->tdls_nss_switch_in_progress &&
6841 hdd_ctx->tdls_nss_teardown_complete) {
6842 hdd_ctx->tdls_nss_switch_in_progress = false;
6843 hdd_ctx->tdls_nss_teardown_complete = false;
6844 }
6845 hdd_info("tdls_nss_switch_in_progress: %d tdls_nss_teardown_complete: %d",
6846 hdd_ctx->tdls_nss_switch_in_progress,
6847 hdd_ctx->tdls_nss_teardown_complete);
6848#endif
Archana Ramachandran393f3792015-11-13 17:13:21 -08006849 hdd_info("Set antenna status: %d current mode: %d",
6850 ret, hdd_ctx->current_antenna_mode);
6851 return ret;
6852
6853}
6854
6855/**
6856 * drv_cmd_get_antenna_mode() - GET ANTENNA MODE driver command
6857 * handler
6858 * @adapter: Pointer to hdd adapter
6859 * @hdd_ctx: Pointer to hdd context
6860 * @command: Pointer to input command
6861 * @command_len: length of the command
6862 * @priv_data: private data coming with the driver command
6863 *
6864 * Return: 0 for success non-zero for failure
6865 */
6866static inline int drv_cmd_get_antenna_mode(hdd_adapter_t *adapter,
6867 hdd_context_t *hdd_ctx,
6868 uint8_t *command,
6869 uint8_t command_len,
6870 hdd_priv_data_t *priv_data)
6871{
6872 uint32_t antenna_mode = 0;
6873 char extra[32];
6874 uint8_t len = 0;
6875
6876 antenna_mode = hdd_ctx->current_antenna_mode;
6877 len = scnprintf(extra, sizeof(extra), "%s %d", command,
6878 antenna_mode);
6879 len = QDF_MIN(priv_data->total_len, len + 1);
6880 if (copy_to_user(priv_data->buf, &extra, len)) {
6881 hdd_err("Failed to copy data to user buffer");
6882 return -EFAULT;
6883 }
6884
6885 hdd_info("Get antenna mode: %d", antenna_mode);
6886
6887 return 0;
6888}
6889
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006890/*
6891 * dummy (no-op) hdd driver command handler
6892 */
6893static int drv_cmd_dummy(hdd_adapter_t *adapter,
6894 hdd_context_t *hdd_ctx,
6895 uint8_t *command,
6896 uint8_t command_len,
6897 hdd_priv_data_t *priv_data)
6898{
6899 hdd_info("%s: Ignoring driver command \"%s\"",
6900 adapter->dev->name, command);
6901 return 0;
6902}
6903
6904/*
6905 * handler for any unsupported wlan hdd driver command
6906 */
6907static int drv_cmd_invalid(hdd_adapter_t *adapter,
6908 hdd_context_t *hdd_ctx,
6909 uint8_t *command,
6910 uint8_t command_len,
6911 hdd_priv_data_t *priv_data)
6912{
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306913 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006914 TRACE_CODE_HDD_UNSUPPORTED_IOCTL,
6915 adapter->sessionId, 0));
6916
6917 hdd_warn("%s: Unsupported driver command \"%s\"",
6918 adapter->dev->name, command);
6919
6920 return -ENOTSUPP;
6921}
6922
6923/**
6924 * drv_cmd_set_fcc_channel() - handle fcc constraint request
6925 * @adapter: HDD adapter
6926 * @hdd_ctx: HDD context
6927 * @command: command ptr, SET_FCC_CHANNEL 0/1 is the command
6928 * @command_len: command len
6929 * @priv_data: private data
6930 *
6931 * Return: status
6932 */
6933static int drv_cmd_set_fcc_channel(hdd_adapter_t *adapter,
6934 hdd_context_t *hdd_ctx,
6935 uint8_t *command,
6936 uint8_t command_len,
6937 hdd_priv_data_t *priv_data)
6938{
6939 uint8_t *value;
6940 uint8_t fcc_constraint;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306941 QDF_STATUS status;
Amar Singhal83a047a2016-05-19 15:56:11 -07006942 bool scan_pending;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006943 int ret = 0;
6944
6945 /*
6946 * this command would be called by user-space when it detects WLAN
6947 * ON after airplane mode is set. When APM is set, WLAN turns off.
6948 * But it can be turned back on. Otherwise; when APM is turned back
6949 * off, WLAN would turn back on. So at that point the command is
6950 * expected to come down. 0 means disable, 1 means enable. The
6951 * constraint is removed when parameter 1 is set or different
6952 * country code is set
6953 */
6954
6955 value = command + command_len + 1;
6956
6957 ret = kstrtou8(value, 10, &fcc_constraint);
6958 if ((ret < 0) || (fcc_constraint > 1)) {
6959 /*
6960 * If the input value is greater than max value of datatype,
6961 * then also it is a failure
6962 */
6963 hdd_err("value out of range");
6964 return -EINVAL;
6965 }
6966
Amar Singhal83a047a2016-05-19 15:56:11 -07006967 scan_pending = !qdf_list_empty(&hdd_ctx->hdd_scan_req_q);
6968 status = sme_handle_set_fcc_channel(hdd_ctx->hHal, !fcc_constraint,
6969 scan_pending);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306970 if (status != QDF_STATUS_SUCCESS) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006971 hdd_err("sme disable fn. returned err");
6972 ret = -EPERM;
6973 }
6974
6975 return ret;
6976}
6977
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306978/**
6979 * hdd_parse_set_channel_switch_command() - Parse and validate CHANNEL_SWITCH
6980 * command
6981 * @value: Pointer to the command
6982 * @chan_number: Pointer to the channel number
6983 * @chan_bw: Pointer to the channel bandwidth
6984 *
6985 * Parses and provides the channel number and channel width from the input
6986 * command which is expected to be of the format: CHANNEL_SWITCH <CH> <BW>
6987 * <CH> is channel number to move (where 1 = channel 1, 149 = channel 149, ...)
6988 * <BW> is bandwidth to move (where 20 = BW 20, 40 = BW 40, 80 = BW 80)
6989 *
6990 * Return: 0 for success, non-zero for failure
6991 */
6992static int hdd_parse_set_channel_switch_command(uint8_t *value,
6993 uint32_t *chan_number,
6994 uint32_t *chan_bw)
6995{
6996 const uint8_t *in_ptr = value;
6997 int ret;
6998
6999 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
7000
7001 /* no argument after the command */
7002 if (NULL == in_ptr) {
7003 hdd_err("No argument after the command");
7004 return -EINVAL;
7005 }
7006
7007 /* no space after the command */
7008 if (SPACE_ASCII_VALUE != *in_ptr) {
7009 hdd_err("No space after the command ");
7010 return -EINVAL;
7011 }
7012
7013 /* remove empty spaces and move the next argument */
7014 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
7015 in_ptr++;
7016
7017 /* no argument followed by spaces */
7018 if ('\0' == *in_ptr) {
7019 hdd_err("No argument followed by spaces");
7020 return -EINVAL;
7021 }
7022
7023 /* get the two arguments: channel number and bandwidth */
7024 ret = sscanf(in_ptr, "%u %u", chan_number, chan_bw);
7025 if (ret != 2) {
7026 hdd_err("Arguments retrieval from cmd string failed");
7027 return -EINVAL;
7028 }
7029
7030 return 0;
7031}
7032
7033/**
7034 * drv_cmd_set_channel_switch() - Switch SAP/P2P-GO operating channel
7035 * @adapter: HDD adapter
7036 * @hdd_ctx: HDD context
7037 * @command: Pointer to the input command CHANNEL_SWITCH
7038 * @command_len: Command len
7039 * @priv_data: Private data
7040 *
7041 * Handles private IOCTL CHANNEL_SWITCH command to switch the operating channel
7042 * of SAP/P2P-GO
7043 *
7044 * Return: 0 for success, non-zero for failure
7045 */
7046static int drv_cmd_set_channel_switch(hdd_adapter_t *adapter,
7047 hdd_context_t *hdd_ctx,
7048 uint8_t *command,
7049 uint8_t command_len,
7050 hdd_priv_data_t *priv_data)
7051{
7052 struct net_device *dev = adapter->dev;
7053 int status;
7054 uint32_t chan_number = 0, chan_bw = 0;
7055 uint8_t *value = command;
Kiran Kumar Lokere13644672016-02-29 15:40:10 -08007056 enum phy_ch_width width;
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307057
Krunal Sonibe766b02016-03-10 13:00:44 -08007058 if ((adapter->device_mode != QDF_P2P_GO_MODE) &&
7059 (adapter->device_mode != QDF_SAP_MODE)) {
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307060 hdd_err("IOCTL CHANNEL_SWITCH not supported for mode %d",
7061 adapter->device_mode);
7062 return -EINVAL;
7063 }
7064
7065 status = hdd_parse_set_channel_switch_command(value,
7066 &chan_number, &chan_bw);
7067 if (status) {
7068 hdd_err("Invalid CHANNEL_SWITCH command");
7069 return status;
7070 }
7071
7072 if ((chan_bw != 20) && (chan_bw != 40) && (chan_bw != 80)) {
7073 hdd_err("BW %d is not allowed for CHANNEL_SWITCH", chan_bw);
7074 return -EINVAL;
7075 }
7076
7077 if (chan_bw == 80)
7078 width = CH_WIDTH_80MHZ;
7079 else if (chan_bw == 40)
7080 width = CH_WIDTH_40MHZ;
7081 else
7082 width = CH_WIDTH_20MHZ;
7083
7084 hdd_info("CH:%d BW:%d", chan_number, chan_bw);
7085
7086 status = hdd_softap_set_channel_change(dev, chan_number, width);
7087 if (status) {
7088 hdd_err("Set channel change fail");
7089 return status;
7090 }
7091
7092 return 0;
7093}
7094
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007095/*
7096 * The following table contains all supported WLAN HDD
7097 * IOCTL driver commands and the handler for each of them.
7098 */
7099static const hdd_drv_cmd_t hdd_drv_cmds[] = {
7100 {"P2P_DEV_ADDR", drv_cmd_p2p_dev_addr},
7101 {"P2P_SET_NOA", drv_cmd_p2p_set_noa},
7102 {"P2P_SET_PS", drv_cmd_p2p_set_ps},
7103 {"SETBAND", drv_cmd_set_band},
7104 {"SETWMMPS", drv_cmd_set_wmmps},
7105 {"COUNTRY", drv_cmd_country},
7106 {"SETSUSPENDMODE", drv_cmd_dummy},
7107 {"SET_AP_WPS_P2P_IE", drv_cmd_dummy},
7108 {"BTCOEXSCAN", drv_cmd_dummy},
7109 {"RXFILTER", drv_cmd_dummy},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007110 {"SETROAMTRIGGER", drv_cmd_set_roam_trigger},
7111 {"GETROAMTRIGGER", drv_cmd_get_roam_trigger},
7112 {"SETROAMSCANPERIOD", drv_cmd_set_roam_scan_period},
7113 {"GETROAMSCANPERIOD", drv_cmd_get_roam_scan_period},
7114 {"SETROAMSCANREFRESHPERIOD", drv_cmd_set_roam_scan_refresh_period},
7115 {"GETROAMSCANREFRESHPERIOD", drv_cmd_get_roam_scan_refresh_period},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007116 {"SETROAMMODE", drv_cmd_set_roam_mode},
7117 {"GETROAMMODE", drv_cmd_get_roam_mode},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007118 {"SETROAMDELTA", drv_cmd_set_roam_delta},
7119 {"GETROAMDELTA", drv_cmd_get_roam_delta},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007120 {"GETBAND", drv_cmd_get_band},
7121 {"SETROAMSCANCHANNELS", drv_cmd_set_roam_scan_channels},
7122 {"GETROAMSCANCHANNELS", drv_cmd_get_roam_scan_channels},
7123 {"GETCCXMODE", drv_cmd_get_ccx_mode},
7124 {"GETOKCMODE", drv_cmd_get_okc_mode},
7125 {"GETFASTROAM", drv_cmd_get_fast_roam},
7126 {"GETFASTTRANSITION", drv_cmd_get_fast_transition},
7127 {"SETROAMSCANCHANNELMINTIME", drv_cmd_set_roam_scan_channel_min_time},
7128 {"SENDACTIONFRAME", drv_cmd_send_action_frame},
7129 {"GETROAMSCANCHANNELMINTIME", drv_cmd_get_roam_scan_channel_min_time},
7130 {"SETSCANCHANNELTIME", drv_cmd_set_scan_channel_time},
7131 {"GETSCANCHANNELTIME", drv_cmd_get_scan_channel_time},
7132 {"SETSCANHOMETIME", drv_cmd_set_scan_home_time},
7133 {"GETSCANHOMETIME", drv_cmd_get_scan_home_time},
7134 {"SETROAMINTRABAND", drv_cmd_set_roam_intra_band},
7135 {"GETROAMINTRABAND", drv_cmd_get_roam_intra_band},
7136 {"SETSCANNPROBES", drv_cmd_set_scan_n_probes},
7137 {"GETSCANNPROBES", drv_cmd_get_scan_n_probes},
7138 {"SETSCANHOMEAWAYTIME", drv_cmd_set_scan_home_away_time},
7139 {"GETSCANHOMEAWAYTIME", drv_cmd_get_scan_home_away_time},
7140 {"REASSOC", drv_cmd_reassoc},
7141 {"SETWESMODE", drv_cmd_set_wes_mode},
7142 {"GETWESMODE", drv_cmd_get_wes_mode},
7143 {"SETOPPORTUNISTICRSSIDIFF", drv_cmd_set_opportunistic_rssi_diff},
7144 {"GETOPPORTUNISTICRSSIDIFF", drv_cmd_get_opportunistic_rssi_diff},
7145 {"SETROAMRESCANRSSIDIFF", drv_cmd_set_roam_rescan_rssi_diff},
7146 {"GETROAMRESCANRSSIDIFF", drv_cmd_get_roam_rescan_rssi_diff},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007147 {"SETFASTROAM", drv_cmd_set_fast_roam},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007148 {"SETFASTTRANSITION", drv_cmd_set_fast_transition},
7149 {"FASTREASSOC", drv_cmd_fast_reassoc},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007150 {"SETROAMSCANCONTROL", drv_cmd_set_roam_scan_control},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007151 {"SETOKCMODE", drv_cmd_set_okc_mode},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007152 {"GETROAMSCANCONTROL", drv_cmd_get_roam_scan_control},
7153 {"BTCOEXMODE", drv_cmd_bt_coex_mode},
7154 {"SCAN-ACTIVE", drv_cmd_scan_active},
7155 {"SCAN-PASSIVE", drv_cmd_scan_passive},
7156 {"GETDWELLTIME", drv_cmd_get_dwell_time},
7157 {"SETDWELLTIME", drv_cmd_set_dwell_time},
7158 {"MIRACAST", drv_cmd_miracast},
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08007159 {"SETIBSSBEACONOUIDATA", drv_cmd_set_ibss_beacon_oui_data},
7160 {"SETRMCENABLE", drv_cmd_set_rmc_enable},
7161 {"SETRMCACTIONPERIOD", drv_cmd_set_rmc_action_period},
7162 {"GETIBSSPEERINFOALL", drv_cmd_get_ibss_peer_info_all},
7163 {"GETIBSSPEERINFO", drv_cmd_get_ibss_peer_info},
7164 {"SETRMCTXRATE", drv_cmd_set_rmc_tx_rate},
7165 {"SETIBSSTXFAILEVENT", drv_cmd_set_ibss_tx_fail_event},
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08007166#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007167 {"SETCCXROAMSCANCHANNELS", drv_cmd_set_ccx_roam_scan_channels},
7168 {"GETTSMSTATS", drv_cmd_get_tsm_stats},
7169 {"SETCCKMIE", drv_cmd_set_cckm_ie},
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07007170 {"CCXBEACONREQ", drv_cmd_ccx_beacon_req},
7171 {"CCXPLMREQ", drv_cmd_ccx_plm_req},
7172 {"SETCCXMODE", drv_cmd_set_ccx_mode},
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08007173#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007174 {"SETMCRATE", drv_cmd_set_mc_rate},
7175 {"MAXTXPOWER", drv_cmd_max_tx_power},
7176 {"SETDFSSCANMODE", drv_cmd_set_dfs_scan_mode},
7177 {"GETDFSSCANMODE", drv_cmd_get_dfs_scan_mode},
7178 {"GETLINKSTATUS", drv_cmd_get_link_status},
7179#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
7180 {"ENABLEEXTWOW", drv_cmd_enable_ext_wow},
7181 {"SETAPP1PARAMS", drv_cmd_set_app1_params},
7182 {"SETAPP2PARAMS", drv_cmd_set_app2_params},
7183#endif
7184#ifdef FEATURE_WLAN_TDLS
7185 {"TDLSSECONDARYCHANNELOFFSET", drv_cmd_tdls_secondary_channel_offset},
7186 {"TDLSOFFCHANNELMODE", drv_cmd_tdls_off_channel_mode},
7187 {"TDLSOFFCHANNEL", drv_cmd_tdls_off_channel},
7188 {"TDLSSCAN", drv_cmd_tdls_scan},
7189#endif
7190 {"RSSI", drv_cmd_get_rssi},
7191 {"LINKSPEED", drv_cmd_get_linkspeed},
7192#ifdef FEATURE_NAPI
7193 {"NAPI", drv_cmd_napi},
7194#endif /* FEATURE_NAPI */
7195 {"RXFILTER-REMOVE", drv_cmd_rx_filter_remove},
7196 {"RXFILTER-ADD", drv_cmd_rx_filter_add},
7197 {"SET_FCC_CHANNEL", drv_cmd_set_fcc_channel},
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307198 {"CHANNEL_SWITCH", drv_cmd_set_channel_switch},
Archana Ramachandran393f3792015-11-13 17:13:21 -08007199 {"SETANTENNAMODE", drv_cmd_set_antenna_mode},
7200 {"GETANTENNAMODE", drv_cmd_get_antenna_mode},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007201};
7202
7203/**
7204 * hdd_drv_cmd_process() - chooses and runs the proper
7205 * handler based on the input command
7206 * @adapter: Pointer to the hdd adapter
7207 * @cmd: Pointer to the driver command
7208 * @priv_data: Pointer to the data associated with the command
7209 *
7210 * This function parses the input hdd driver command and runs
7211 * the proper handler
7212 *
7213 * Return: 0 for success non-zero for failure
7214 */
7215static int hdd_drv_cmd_process(hdd_adapter_t *adapter,
7216 uint8_t *cmd,
7217 hdd_priv_data_t *priv_data)
7218{
7219 hdd_context_t *hdd_ctx;
7220 int i;
7221 const int cmd_num_total = ARRAY_SIZE(hdd_drv_cmds);
7222 uint8_t *cmd_i = NULL;
7223 hdd_drv_cmd_handler_t handler = NULL;
7224 int len = 0;
7225
7226 if (!adapter || !cmd || !priv_data) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007227 hdd_err("at least 1 param is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007228 return -EINVAL;
7229 }
7230
7231 hdd_ctx = (hdd_context_t *)adapter->pHddCtx;
7232
7233 for (i = 0; i < cmd_num_total; i++) {
7234
7235 cmd_i = (uint8_t *)hdd_drv_cmds[i].cmd;
7236 handler = hdd_drv_cmds[i].handler;
7237 len = strlen(cmd_i);
7238
7239 if (!handler) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007240 hdd_err("no. %d handler is NULL", i);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007241 return -EINVAL;
7242 }
7243
7244 if (strncasecmp(cmd, cmd_i, len) == 0)
7245 return handler(adapter, hdd_ctx,
7246 cmd, len, priv_data);
7247 }
7248
7249 return drv_cmd_invalid(adapter, hdd_ctx, cmd, len, priv_data);
7250}
7251
7252/**
7253 * hdd_driver_command() - top level wlan hdd driver command handler
7254 * @adapter: Pointer to the hdd adapter
7255 * @priv_data: Pointer to the raw command data
7256 *
7257 * This function is the top level wlan hdd driver command handler. It
7258 * handles the command with the help of hdd_drv_cmd_process()
7259 *
7260 * Return: 0 for success non-zero for failure
7261 */
7262static int hdd_driver_command(hdd_adapter_t *adapter,
7263 hdd_priv_data_t *priv_data)
7264{
7265 uint8_t *command = NULL;
7266 int ret = 0;
7267
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307268 ENTER();
7269
Anurag Chouhan6d760662016-02-20 16:05:43 +05307270 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007271 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007272 return -EINVAL;
7273 }
7274
7275 /*
7276 * Note that valid pointers are provided by caller
7277 */
7278
7279 /* copy to local struct to avoid numerous changes to legacy code */
7280 if (priv_data->total_len <= 0 ||
7281 priv_data->total_len > WLAN_PRIV_DATA_MAX_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007282 hdd_warn("Invalid priv_data.total_len(%d)!!!",
7283 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007284 ret = -EINVAL;
7285 goto exit;
7286 }
7287
7288 /* Allocate +1 for '\0' */
7289 command = kmalloc(priv_data->total_len + 1, GFP_KERNEL);
7290 if (!command) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007291 hdd_err("failed to allocate memory");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007292 ret = -ENOMEM;
7293 goto exit;
7294 }
7295
7296 if (copy_from_user(command, priv_data->buf, priv_data->total_len)) {
7297 ret = -EFAULT;
7298 goto exit;
7299 }
7300
7301 /* Make sure the command is NUL-terminated */
7302 command[priv_data->total_len] = '\0';
7303
7304 hdd_info("%s: %s", adapter->dev->name, command);
7305 ret = hdd_drv_cmd_process(adapter, command, priv_data);
7306
7307exit:
7308 if (command)
7309 kfree(command);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307310 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007311 return ret;
7312}
7313
7314#ifdef CONFIG_COMPAT
7315static int hdd_driver_compat_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
7316{
7317 struct {
7318 compat_uptr_t buf;
7319 int used_len;
7320 int total_len;
7321 } compat_priv_data;
7322 hdd_priv_data_t priv_data;
7323 int ret = 0;
7324
7325 /*
7326 * Note that adapter and ifr have already been verified by caller,
7327 * and HDD context has also been validated
7328 */
7329 if (copy_from_user(&compat_priv_data, ifr->ifr_data,
7330 sizeof(compat_priv_data))) {
7331 ret = -EFAULT;
7332 goto exit;
7333 }
7334 priv_data.buf = compat_ptr(compat_priv_data.buf);
7335 priv_data.used_len = compat_priv_data.used_len;
7336 priv_data.total_len = compat_priv_data.total_len;
7337 ret = hdd_driver_command(adapter, &priv_data);
7338exit:
7339 return ret;
7340}
7341#else /* CONFIG_COMPAT */
7342static int hdd_driver_compat_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
7343{
7344 /* will never be invoked */
7345 return 0;
7346}
7347#endif /* CONFIG_COMPAT */
7348
7349static int hdd_driver_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
7350{
7351 hdd_priv_data_t priv_data;
7352 int ret = 0;
7353
7354 /*
7355 * Note that adapter and ifr have already been verified by caller,
7356 * and HDD context has also been validated
7357 */
7358 if (copy_from_user(&priv_data, ifr->ifr_data, sizeof(priv_data)))
7359 ret = -EFAULT;
7360 else
7361 ret = hdd_driver_command(adapter, &priv_data);
7362
7363 return ret;
7364}
7365
7366/**
7367 * __hdd_ioctl() - ioctl handler for wlan network interfaces
7368 * @dev: device upon which the ioctl was received
7369 * @ifr: ioctl request information
7370 * @cmd: ioctl command
7371 *
7372 * This function does initial processing of wlan device ioctls.
7373 * Currently two flavors of ioctls are supported. The primary ioctl
7374 * that is supported is the (SIOCDEVPRIVATE + 1) ioctl which is used
7375 * for Android "DRIVER" commands. The other ioctl that is
7376 * conditionally supported is the SIOCIOCTLTX99 ioctl which is used
7377 * for FTM on some platforms. This function simply verifies that the
7378 * driver is in a sane state, and that the ioctl is one of the
7379 * supported flavors, in which case flavor-specific handlers are
7380 * dispatched.
7381 *
7382 * Return: 0 on success, non-zero on error
7383 */
7384static int __hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7385{
7386 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
7387 hdd_context_t *hdd_ctx;
7388 int ret;
7389
Jeff Johnson3c3994a2016-02-11 08:12:30 -08007390 ENTER_DEV(dev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307391
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007392 if (dev != adapter->dev) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007393 hdd_alert("HDD adapter/dev inconsistency");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007394 ret = -ENODEV;
7395 goto exit;
7396 }
7397
7398 if ((!ifr) || (!ifr->ifr_data)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007399 hdd_err("invalid data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007400 ret = -EINVAL;
7401 goto exit;
7402 }
7403#if defined(QCA_WIFI_FTM) && defined(LINUX_QCMBR)
Anurag Chouhan6d760662016-02-20 16:05:43 +05307404 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007405 if (SIOCIOCTLTX99 == cmd) {
7406 ret = wlan_hdd_qcmbr_unified_ioctl(adapter, ifr);
7407 goto exit;
7408 }
7409 }
7410#endif
7411
7412 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
7413 ret = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307414 if (ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007415 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007416
7417 switch (cmd) {
7418 case (SIOCDEVPRIVATE + 1):
7419 if (is_compat_task())
7420 ret = hdd_driver_compat_ioctl(adapter, ifr);
7421 else
7422 ret = hdd_driver_ioctl(adapter, ifr);
7423 break;
7424 default:
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007425 hdd_err("unknown ioctl %d", cmd);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007426 ret = -EINVAL;
7427 break;
7428 }
7429exit:
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307430 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007431 return ret;
7432}
7433
7434/**
7435 * hdd_ioctl() - ioctl handler (wrapper) for wlan network interfaces
7436 * @dev: device upon which the ioctl was received
7437 * @ifr: ioctl request information
7438 * @cmd: ioctl command
7439 *
7440 * This function acts as an SSR-protecting wrapper to __hdd_ioctl()
7441 * which is where the ioctls are really handled.
7442 *
7443 * Return: 0 on success, non-zero on error
7444 */
7445int hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7446{
7447 int ret;
7448
7449 cds_ssr_protect(__func__);
7450 ret = __hdd_ioctl(dev, ifr, cmd);
7451 cds_ssr_unprotect(__func__);
7452 return ret;
7453}