blob: 2ae94abe5e218c5f7bc0a0b16d3ae5b45877cdfd [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Rajeev Kumarea95edd2017-01-11 20:49:36 -08002 * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/*
23 * This file was originally distributed by Qualcomm Atheros, Inc.
24 * under proprietary terms before Copyright ownership was assigned
25 * to the Linux Foundation.
26 */
27
28/* Include Files */
29
30#include <wlan_hdd_includes.h>
31#include <wlan_hdd_wowl.h>
32#include "wlan_hdd_trace.h"
33#include "wlan_hdd_ioctl.h"
34#include "wlan_hdd_power.h"
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"
Rajeev Kumarea95edd2017-01-11 20:49:36 -080038#include "scheduler_api.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080039
40#include "wlan_hdd_p2p.h"
41#include <linux/ctype.h>
42#include "wma.h"
43#include "wlan_hdd_napi.h"
44
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -080045#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080046#include <sme_api.h>
47#include <sir_api.h>
48#endif
49#include "hif.h"
50
51#if defined(LINUX_QCMBR)
52#define SIOCIOCTLTX99 (SIOCDEVPRIVATE+13)
53#endif
54
55/*
56 * Size of Driver command strings from upper layer
57 */
58#define SIZE_OF_SETROAMMODE 11 /* size of SETROAMMODE */
59#define SIZE_OF_GETROAMMODE 11 /* size of GETROAMMODE */
60
Rajeev Kumar8e3e2832015-11-06 16:02:54 -080061/*
62 * Ibss prop IE from command will be of size:
63 * size = sizeof(oui) + sizeof(oui_data) + 1(Element ID) + 1(EID Length)
64 * OUI_DATA should be at least 3 bytes long
65 */
66#define WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH (3)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080067
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -080068#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080069#define TID_MIN_VALUE 0
70#define TID_MAX_VALUE 15
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -080071#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080072
73/*
74 * Maximum buffer size used for returning the data back to user space
75 */
76#define WLAN_MAX_BUF_SIZE 1024
77#define WLAN_PRIV_DATA_MAX_LEN 8192
78
79/*
80 * Driver miracast parameters 0-Disabled
81 * 1-Source, 2-Sink
82 */
83#define WLAN_HDD_DRIVER_MIRACAST_CFG_MIN_VAL 0
84#define WLAN_HDD_DRIVER_MIRACAST_CFG_MAX_VAL 2
85
86/*
87 * When ever we need to print IBSSPEERINFOALL for more than 16 STA
88 * we will split the printing.
89 */
90#define NUM_OF_STA_DATA_TO_PRINT 16
91
92/*
93 * Android DRIVER command structures
94 */
95struct android_wifi_reassoc_params {
96 unsigned char bssid[18];
97 int channel;
98};
99
100#define ANDROID_WIFI_ACTION_FRAME_SIZE 1040
101struct android_wifi_af_params {
102 unsigned char bssid[18];
103 int channel;
104 int dwell_time;
105 int len;
106 unsigned char data[ANDROID_WIFI_ACTION_FRAME_SIZE];
107};
108
109/*
110 * Define HDD driver command handling entry, each contains a command
111 * string and the handler.
112 */
113typedef int (*hdd_drv_cmd_handler_t)(hdd_adapter_t *adapter,
114 hdd_context_t *hdd_ctx,
115 uint8_t *cmd,
116 uint8_t cmd_name_len,
117 hdd_priv_data_t *priv_data);
118
119typedef struct {
120 const char *cmd;
121 hdd_drv_cmd_handler_t handler;
122} hdd_drv_cmd_t;
123
124#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
125#define WLAN_WAIT_TIME_READY_TO_EXTWOW 2000
126#define WLAN_HDD_MAX_TCP_PORT 65535
127#endif
128
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800129static uint16_t cesium_pid;
130extern struct sock *cesium_nl_srv_sock;
131
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -0800132#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800133static void hdd_get_tsm_stats_cb(tAniTrafStrmMetrics tsm_metrics,
134 const uint32_t staId, void *context)
135{
136 struct statsContext *stats_context = NULL;
137 hdd_adapter_t *adapter = NULL;
138
139 if (NULL == context) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700140 hdd_err("Bad param, context [%p]", context);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800141 return;
142 }
143
144 /*
145 * there is a race condition that exists between this callback
146 * function and the caller since the caller could time out either
147 * before or while this code is executing. we use a spinlock to
148 * serialize these actions
149 */
150 spin_lock(&hdd_context_lock);
151
152 stats_context = context;
153 adapter = stats_context->pAdapter;
154 if ((NULL == adapter) ||
155 (STATS_CONTEXT_MAGIC != stats_context->magic)) {
156 /*
157 * the caller presumably timed out so there is
158 * nothing we can do
159 */
160 spin_unlock(&hdd_context_lock);
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700161 hdd_warn("Invalid context, adapter [%p] magic [%08x]",
162 adapter, stats_context->magic);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800163 return;
164 }
165
166 /* context is valid so caller is still waiting */
167
168 /* paranoia: invalidate the magic */
169 stats_context->magic = 0;
170
171 /* copy over the tsm stats */
172 adapter->tsmStats.UplinkPktQueueDly = tsm_metrics.UplinkPktQueueDly;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530173 qdf_mem_copy(adapter->tsmStats.UplinkPktQueueDlyHist,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800174 tsm_metrics.UplinkPktQueueDlyHist,
175 sizeof(adapter->tsmStats.UplinkPktQueueDlyHist) /
176 sizeof(adapter->tsmStats.UplinkPktQueueDlyHist[0]));
177 adapter->tsmStats.UplinkPktTxDly = tsm_metrics.UplinkPktTxDly;
178 adapter->tsmStats.UplinkPktLoss = tsm_metrics.UplinkPktLoss;
179 adapter->tsmStats.UplinkPktCount = tsm_metrics.UplinkPktCount;
180 adapter->tsmStats.RoamingCount = tsm_metrics.RoamingCount;
181 adapter->tsmStats.RoamingDly = tsm_metrics.RoamingDly;
182
183 /* notify the caller */
184 complete(&stats_context->completion);
185
186 /* serialization is complete */
187 spin_unlock(&hdd_context_lock);
188}
189
190static
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530191QDF_STATUS hdd_get_tsm_stats(hdd_adapter_t *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800192 const uint8_t tid,
193 tAniTrafStrmMetrics *tsm_metrics)
194{
195 hdd_station_ctx_t *hdd_sta_ctx = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530196 QDF_STATUS hstatus;
197 QDF_STATUS vstatus = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800198 unsigned long rc;
Houston Hoffman59c097f2016-11-09 15:50:25 -0800199 static struct statsContext context;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800200 hdd_context_t *hdd_ctx = NULL;
201
202 if (NULL == adapter) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700203 hdd_err("adapter is NULL");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530204 return QDF_STATUS_E_FAULT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800205 }
206
207 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
208 hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
209
210 /* we are connected prepare our callback context */
211 init_completion(&context.completion);
212 context.pAdapter = adapter;
213 context.magic = STATS_CONTEXT_MAGIC;
214
215 /* query tsm stats */
216 hstatus = sme_get_tsm_stats(hdd_ctx->hHal, hdd_get_tsm_stats_cb,
217 hdd_sta_ctx->conn_info.staId[0],
218 hdd_sta_ctx->conn_info.bssId,
219 &context, hdd_ctx->pcds_context, tid);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530220 if (QDF_STATUS_SUCCESS != hstatus) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700221 hdd_err("Unable to retrieve statistics");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530222 vstatus = QDF_STATUS_E_FAULT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800223 } else {
224 /* request was sent -- wait for the response */
225 rc = wait_for_completion_timeout(&context.completion,
226 msecs_to_jiffies(WLAN_WAIT_TIME_STATS));
227 if (!rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700228 hdd_err("SME timed out while retrieving statistics");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530229 vstatus = QDF_STATUS_E_TIMEOUT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800230 }
231 }
232
233 /*
234 * either we never sent a request, we sent a request and received a
235 * response or we sent a request and timed out. if we never sent a
236 * request or if we sent a request and got a response, we want to
237 * clear the magic out of paranoia. if we timed out there is a
238 * race condition such that the callback function could be
239 * executing at the same time we are. of primary concern is if the
240 * callback function had already verified the "magic" but had not
241 * yet set the completion variable when a timeout occurred. we
242 * serialize these activities by invalidating the magic while
243 * holding a shared spinlock which will cause us to block if the
244 * callback is currently executing
245 */
246 spin_lock(&hdd_context_lock);
247 context.magic = 0;
248 spin_unlock(&hdd_context_lock);
249
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530250 if (QDF_STATUS_SUCCESS == vstatus) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800251 tsm_metrics->UplinkPktQueueDly =
252 adapter->tsmStats.UplinkPktQueueDly;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530253 qdf_mem_copy(tsm_metrics->UplinkPktQueueDlyHist,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800254 adapter->tsmStats.UplinkPktQueueDlyHist,
255 sizeof(adapter->tsmStats.UplinkPktQueueDlyHist) /
256 sizeof(adapter->tsmStats.
257 UplinkPktQueueDlyHist[0]));
258 tsm_metrics->UplinkPktTxDly = adapter->tsmStats.UplinkPktTxDly;
259 tsm_metrics->UplinkPktLoss = adapter->tsmStats.UplinkPktLoss;
260 tsm_metrics->UplinkPktCount = adapter->tsmStats.UplinkPktCount;
261 tsm_metrics->RoamingCount = adapter->tsmStats.RoamingCount;
262 tsm_metrics->RoamingDly = adapter->tsmStats.RoamingDly;
263 }
264 return vstatus;
265}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -0800266#endif /*FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800267
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800268/* Function header is left blank intentionally */
269static int hdd_parse_setrmcenable_command(uint8_t *pValue,
270 uint8_t *pRmcEnable)
271{
272 uint8_t *inPtr = pValue;
273 int tempInt;
274 int v = 0;
275 char buf[32];
276 *pRmcEnable = 0;
277
278 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
279
280 if (NULL == inPtr) {
281 return 0;
282 }
283
284 else if (SPACE_ASCII_VALUE != *inPtr) {
285 return 0;
286 }
287
288 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
289 inPtr++;
290
291 if ('\0' == *inPtr) {
292 return 0;
293 }
294
295 sscanf(inPtr, "%32s ", buf);
296 v = kstrtos32(buf, 10, &tempInt);
297 if (v < 0) {
298 return -EINVAL;
299 }
300
301 *pRmcEnable = tempInt;
302
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700303 hdd_info("ucRmcEnable: %d", *pRmcEnable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800304
305 return 0;
306}
307
308/* Function header is left blank intentionally */
309static int hdd_parse_setrmcactionperiod_command(uint8_t *pValue,
310 uint32_t *pActionPeriod)
311{
312 uint8_t *inPtr = pValue;
313 int tempInt;
314 int v = 0;
315 char buf[32];
316 *pActionPeriod = 0;
317
318 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
319
320 if (NULL == inPtr) {
321 return -EINVAL;
322 }
323
324 else if (SPACE_ASCII_VALUE != *inPtr) {
325 return -EINVAL;
326 }
327
328 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
329 inPtr++;
330
331 if ('\0' == *inPtr) {
332 return 0;
333 }
334
335 sscanf(inPtr, "%32s ", buf);
336 v = kstrtos32(buf, 10, &tempInt);
337 if (v < 0) {
338 return -EINVAL;
339 }
340
341 if ((tempInt < WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STAMIN) ||
342 (tempInt > WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STAMAX)) {
343 return -EINVAL;
344 }
345
346 *pActionPeriod = tempInt;
347
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700348 hdd_info("uActionPeriod: %d", *pActionPeriod);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800349
350 return 0;
351}
352
353/* Function header is left blank intentionally */
354static int hdd_parse_setrmcrate_command(uint8_t *pValue,
355 uint32_t *pRate,
356 tTxrateinfoflags *pTxFlags)
357{
358 uint8_t *inPtr = pValue;
359 int tempInt;
360 int v = 0;
361 char buf[32];
362 *pRate = 0;
363 *pTxFlags = 0;
364
365 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
366
367 if (NULL == inPtr) {
368 return -EINVAL;
369 }
370
371 else if (SPACE_ASCII_VALUE != *inPtr) {
372 return -EINVAL;
373 }
374
375 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
376 inPtr++;
377
378 if ('\0' == *inPtr) {
379 return 0;
380 }
381
382 sscanf(inPtr, "%32s ", buf);
383 v = kstrtos32(buf, 10, &tempInt);
384 if (v < 0) {
385 return -EINVAL;
386 }
387
388 switch (tempInt) {
389 default:
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700390 hdd_warn("Unsupported rate: %d", tempInt);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800391 return -EINVAL;
392 case 0:
393 case 6:
394 case 9:
395 case 12:
396 case 18:
397 case 24:
398 case 36:
399 case 48:
400 case 54:
401 *pTxFlags = eHAL_TX_RATE_LEGACY;
402 *pRate = tempInt * 10;
403 break;
404 case 65:
405 *pTxFlags = eHAL_TX_RATE_HT20;
406 *pRate = tempInt * 10;
407 break;
408 case 72:
409 *pTxFlags = eHAL_TX_RATE_HT20 | eHAL_TX_RATE_SGI;
410 *pRate = 722;
411 break;
412 }
413
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700414 hdd_info("Rate: %d", *pRate);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800415
416 return 0;
417}
418
419/**
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700420 * hdd_get_ibss_peer_info_cb() - IBSS peer Info request callback
421 * @UserData: Adapter private data
422 * @pPeerInfoRsp: Peer info response
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800423 *
424 * This is an asynchronous callback function from SME when the peer info
425 * is received
426 *
427 * Return: 0 for success non-zero for failure
428 */
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700429void
430hdd_get_ibss_peer_info_cb(void *pUserData,
431 tSirPeerInfoRspParams *pPeerInfo)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800432{
433 hdd_adapter_t *adapter = (hdd_adapter_t *) pUserData;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800434 hdd_station_ctx_t *pStaCtx;
435 uint8_t i;
436
437 /* Sanity check */
438 if ((NULL == adapter) ||
439 (WLAN_HDD_ADAPTER_MAGIC != adapter->magic)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700440 hdd_alert("invalid adapter or adapter has invalid magic");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800441 return;
442 }
443
444 pStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
445 if (NULL != pPeerInfo && QDF_STATUS_SUCCESS == pPeerInfo->status) {
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700446 /* validate number of peers */
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530447 if (pPeerInfo->numPeers > SIR_MAX_NUM_STA_IN_IBSS) {
448 hdd_warn("Limiting num_peers %u to %u",
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700449 pPeerInfo->numPeers, SIR_MAX_NUM_STA_IN_IBSS);
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530450 pPeerInfo->numPeers = SIR_MAX_NUM_STA_IN_IBSS;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800451 }
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530452 pStaCtx->ibss_peer_info.status = pPeerInfo->status;
453 pStaCtx->ibss_peer_info.numPeers = pPeerInfo->numPeers;
454
455 for (i = 0; i < pPeerInfo->numPeers; i++)
456 pStaCtx->ibss_peer_info.peerInfoParams[i] =
457 pPeerInfo->peerInfoParams[i];
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800458 } else {
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530459 hdd_err("peerInfo %s: status %u, numPeers %u",
460 pPeerInfo ? "valid" : "null",
461 pPeerInfo ? pPeerInfo->status : QDF_STATUS_E_FAILURE,
462 pPeerInfo ? pPeerInfo->numPeers : 0);
463 pStaCtx->ibss_peer_info.numPeers = 0;
464 pStaCtx->ibss_peer_info.status = QDF_STATUS_E_FAILURE;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800465 }
466
467 complete(&adapter->ibss_peer_info_comp);
468}
469
470/**
471 * hdd_cfg80211_get_ibss_peer_info_all() - get ibss peers' info
472 * @adapter: Adapter context
473 *
474 * Request function to get IBSS peer info from lower layers
475 *
476 * Return: 0 for success non-zero for failure
477 */
478static
479QDF_STATUS hdd_cfg80211_get_ibss_peer_info_all(hdd_adapter_t *adapter)
480{
481 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
482 QDF_STATUS retStatus = QDF_STATUS_E_FAILURE;
483 unsigned long rc;
484
485 INIT_COMPLETION(adapter->ibss_peer_info_comp);
486
487 retStatus = sme_request_ibss_peer_info(hHal, adapter,
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700488 hdd_get_ibss_peer_info_cb,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800489 true, 0xFF);
490
491 if (QDF_STATUS_SUCCESS == retStatus) {
492 rc = wait_for_completion_timeout
493 (&adapter->ibss_peer_info_comp,
494 msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT));
495
496 /* status will be 0 if timed out */
497 if (!rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700498 hdd_warn("Warning: IBSS_PEER_INFO_TIMEOUT");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800499 retStatus = QDF_STATUS_E_FAILURE;
500 return retStatus;
501 }
502 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700503 hdd_warn("Warning: sme_request_ibss_peer_info Request failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800504 }
505
506 return retStatus;
507}
508
509/**
510 * hdd_cfg80211_get_ibss_peer_info() - get ibss peer info
511 * @adapter: Adapter context
512 * @staIdx: Sta index for which the peer info is requested
513 *
514 * Request function to get IBSS peer info from lower layers
515 *
516 * Return: 0 for success non-zero for failure
517 */
518static QDF_STATUS
519hdd_cfg80211_get_ibss_peer_info(hdd_adapter_t *adapter, uint8_t staIdx)
520{
521 unsigned long rc;
522 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
523 QDF_STATUS retStatus = QDF_STATUS_E_FAILURE;
524
525 INIT_COMPLETION(adapter->ibss_peer_info_comp);
526
527 retStatus = sme_request_ibss_peer_info(hHal, adapter,
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700528 hdd_get_ibss_peer_info_cb,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800529 false, staIdx);
530
531 if (QDF_STATUS_SUCCESS == retStatus) {
532 rc = wait_for_completion_timeout(
533 &adapter->ibss_peer_info_comp,
534 msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT));
535
536 /* status = 0 on timeout */
537 if (!rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700538 hdd_warn("Warning: IBSS_PEER_INFO_TIMEOUT");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800539 retStatus = QDF_STATUS_E_FAILURE;
540 return retStatus;
541 }
542 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700543 hdd_warn("Warning: sme_request_ibss_peer_info Request failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800544 }
545
546 return retStatus;
547}
548
549/* Function header is left blank intentionally */
Jeff Johnsonf731b302016-10-05 16:00:55 -0700550static QDF_STATUS
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800551hdd_parse_get_ibss_peer_info(uint8_t *pValue, struct qdf_mac_addr *pPeerMacAddr)
552{
553 uint8_t *inPtr = pValue;
554 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
555
556 if (NULL == inPtr) {
557 return QDF_STATUS_E_FAILURE;;
558 }
559
560 else if (SPACE_ASCII_VALUE != *inPtr) {
561 return QDF_STATUS_E_FAILURE;;
562 }
563
564 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
565 inPtr++;
566
567 if ('\0' == *inPtr) {
568 return QDF_STATUS_E_FAILURE;;
569 }
570
571 if (inPtr[2] != ':' || inPtr[5] != ':' || inPtr[8] != ':' ||
572 inPtr[11] != ':' || inPtr[14] != ':') {
573 return QDF_STATUS_E_FAILURE;;
574 }
575 sscanf(inPtr, "%2x:%2x:%2x:%2x:%2x:%2x",
576 (unsigned int *)&pPeerMacAddr->bytes[0],
577 (unsigned int *)&pPeerMacAddr->bytes[1],
578 (unsigned int *)&pPeerMacAddr->bytes[2],
579 (unsigned int *)&pPeerMacAddr->bytes[3],
580 (unsigned int *)&pPeerMacAddr->bytes[4],
581 (unsigned int *)&pPeerMacAddr->bytes[5]);
582
583 return QDF_STATUS_SUCCESS;
584}
585
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800586static void hdd_get_band_helper(hdd_context_t *hdd_ctx, int *pBand)
587{
588 eCsrBand band = -1;
589 sme_get_freq_band((tHalHandle) (hdd_ctx->hHal), &band);
590 switch (band) {
591 case eCSR_BAND_ALL:
592 *pBand = WLAN_HDD_UI_BAND_AUTO;
593 break;
594
595 case eCSR_BAND_24:
596 *pBand = WLAN_HDD_UI_BAND_2_4_GHZ;
597 break;
598
599 case eCSR_BAND_5G:
600 *pBand = WLAN_HDD_UI_BAND_5_GHZ;
601 break;
602
603 default:
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700604 hdd_warn("Invalid Band %d", band);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800605 *pBand = -1;
606 break;
607 }
608}
609
610/**
611 * _hdd_parse_bssid_and_chan() - helper function to parse bssid and channel
612 * @data: input data
613 * @target_ap_bssid: pointer to bssid (output parameter)
614 * @channel: pointer to channel (output parameter)
615 *
616 * Return: 0 if parsing is successful; -EINVAL otherwise
617 */
618static int _hdd_parse_bssid_and_chan(const uint8_t **data,
619 uint8_t *bssid,
620 uint8_t *channel)
621{
622 const uint8_t *in_ptr;
623 int v = 0;
624 int temp_int;
625 uint8_t temp_buf[32];
626
627 /* 12 hexa decimal digits, 5 ':' and '\0' */
628 uint8_t mac_addr[18];
629
630 if (!data || !*data)
631 return -EINVAL;
632
633 in_ptr = *data;
634
635 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
636 /* no argument after the command */
637 if (NULL == in_ptr)
638 goto error;
639 /* no space after the command */
640 else if (SPACE_ASCII_VALUE != *in_ptr)
641 goto error;
642
643 /* remove empty spaces */
644 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
645 in_ptr++;
646
647 /* no argument followed by spaces */
648 if ('\0' == *in_ptr)
649 goto error;
650
651 v = sscanf(in_ptr, "%17s", mac_addr);
652 if (!((1 == v) && hdd_is_valid_mac_address(mac_addr))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700653 hdd_err("Invalid MAC address or All hex inputs are not read (%d)",
654 v);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800655 goto error;
656 }
657
658 bssid[0] = hex_to_bin(mac_addr[0]) << 4 |
659 hex_to_bin(mac_addr[1]);
660 bssid[1] = hex_to_bin(mac_addr[3]) << 4 |
661 hex_to_bin(mac_addr[4]);
662 bssid[2] = hex_to_bin(mac_addr[6]) << 4 |
663 hex_to_bin(mac_addr[7]);
664 bssid[3] = hex_to_bin(mac_addr[9]) << 4 |
665 hex_to_bin(mac_addr[10]);
666 bssid[4] = hex_to_bin(mac_addr[12]) << 4 |
667 hex_to_bin(mac_addr[13]);
668 bssid[5] = hex_to_bin(mac_addr[15]) << 4 |
669 hex_to_bin(mac_addr[16]);
670
671 /* point to the next argument */
672 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
673 /* no argument after the command */
674 if (NULL == in_ptr)
675 goto error;
676
677 /* remove empty spaces */
678 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
679 in_ptr++;
680
681 /* no argument followed by spaces */
682 if ('\0' == *in_ptr)
683 goto error;
684
685 /* get the next argument ie the channel number */
686 v = sscanf(in_ptr, "%31s ", temp_buf);
687 if (1 != v)
688 goto error;
689
690 v = kstrtos32(temp_buf, 10, &temp_int);
691 if ((v < 0) || (temp_int < 0) ||
692 (temp_int > WNI_CFG_CURRENT_CHANNEL_STAMAX))
693 return -EINVAL;
694
695 *channel = temp_int;
696 *data = in_ptr;
697 return 0;
698error:
699 *data = in_ptr;
700 return -EINVAL;
701}
702
703/**
704 * hdd_parse_send_action_frame_data() - HDD Parse send action frame data
705 * @pValue: Pointer to input data
706 * @pTargetApBssid: Pointer to target Ap bssid
707 * @pChannel: Pointer to the Target AP channel
708 * @pDwellTime: Pointer to the time to stay off-channel
709 * after transmitting action frame
710 * @pBuf: Pointer to data
711 * @pBufLen: Pointer to data length
712 *
713 * This function parses the send action frame data passed in the format
714 * SENDACTIONFRAME<space><bssid><space><channel><space><dwelltime><space><data>
715 *
716 * Return: 0 for success non-zero for failure
717 */
718static int
719hdd_parse_send_action_frame_v1_data(const uint8_t *pValue,
720 uint8_t *pTargetApBssid,
721 uint8_t *pChannel, uint8_t *pDwellTime,
722 uint8_t **pBuf, uint8_t *pBufLen)
723{
724 const uint8_t *inPtr = pValue;
725 const uint8_t *dataEnd;
726 int tempInt;
727 int j = 0;
728 int i = 0;
729 int v = 0;
730 uint8_t tempBuf[32];
731 uint8_t tempByte = 0;
732
733 if (_hdd_parse_bssid_and_chan(&inPtr, pTargetApBssid, pChannel))
734 return -EINVAL;
735
736 /* point to the next argument */
737 inPtr = strnchr(inPtr, strlen(inPtr), SPACE_ASCII_VALUE);
738 /* no argument after the command */
739 if (NULL == inPtr)
740 return -EINVAL;
741 /* removing empty spaces */
742 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
743 inPtr++;
744
745 /* no argument followed by spaces */
746 if ('\0' == *inPtr) {
747 return -EINVAL;
748 }
749
750 /* getting the next argument ie the dwell time */
751 v = sscanf(inPtr, "%31s ", tempBuf);
752 if (1 != v)
753 return -EINVAL;
754
755 v = kstrtos32(tempBuf, 10, &tempInt);
756 if (v < 0 || tempInt < 0)
757 return -EINVAL;
758
759 *pDwellTime = tempInt;
760
761 /* point to the next argument */
762 inPtr = strnchr(inPtr, strlen(inPtr), SPACE_ASCII_VALUE);
763 /* no argument after the command */
764 if (NULL == inPtr)
765 return -EINVAL;
766 /* removing empty spaces */
767 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
768 inPtr++;
769
770 /* no argument followed by spaces */
771 if ('\0' == *inPtr) {
772 return -EINVAL;
773 }
774
775 /* find the length of data */
776 dataEnd = inPtr;
777 while (('\0' != *dataEnd)) {
778 dataEnd++;
779 }
780 *pBufLen = dataEnd - inPtr;
781 if (*pBufLen <= 0)
782 return -EINVAL;
783
784 /*
785 * Allocate the number of bytes based on the number of input characters
786 * whether it is even or odd.
787 * if the number of input characters are even, then we need N/2 byte.
788 * if the number of input characters are odd, then we need do (N+1)/2
789 * to compensate rounding off.
790 * For example, if N = 18, then (18 + 1)/2 = 9 bytes are enough.
791 * If N = 19, then we need 10 bytes, hence (19 + 1)/2 = 10 bytes
792 */
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530793 *pBuf = qdf_mem_malloc((*pBufLen + 1) / 2);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800794 if (NULL == *pBuf) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700795 hdd_err("qdf_mem_malloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800796 return -ENOMEM;
797 }
798
799 /* the buffer received from the upper layer is character buffer,
800 * we need to prepare the buffer taking 2 characters in to a U8 hex
801 * decimal number for example 7f0000f0...form a buffer to contain 7f
802 * in 0th location, 00 in 1st and f0 in 3rd location
803 */
804 for (i = 0, j = 0; j < *pBufLen; j += 2) {
805 if (j + 1 == *pBufLen) {
806 tempByte = hex_to_bin(inPtr[j]);
807 } else {
808 tempByte =
809 (hex_to_bin(inPtr[j]) << 4) |
810 (hex_to_bin(inPtr[j + 1]));
811 }
812 (*pBuf)[i++] = tempByte;
813 }
814 *pBufLen = i;
815 return 0;
816}
817
818/**
819 * hdd_parse_reassoc_command_data() - HDD Parse reassoc command data
820 * @pValue: Pointer to input data (its a NULL terminated string)
821 * @pTargetApBssid: Pointer to target Ap bssid
822 * @pChannel: Pointer to the Target AP channel
823 *
824 * This function parses the reasoc command data passed in the format
825 * REASSOC<space><bssid><space><channel>
826 *
827 * Return: 0 for success non-zero for failure
828 */
829static int hdd_parse_reassoc_command_v1_data(const uint8_t *pValue,
830 uint8_t *pTargetApBssid,
831 uint8_t *pChannel)
832{
833 const uint8_t *inPtr = pValue;
834
835 if (_hdd_parse_bssid_and_chan(&inPtr, pTargetApBssid, pChannel))
836 return -EINVAL;
837
838 return 0;
839}
840
Naveen Rawat05376ee2016-07-18 16:43:32 -0700841#ifdef WLAN_FEATURE_ROAM_OFFLOAD
842void hdd_wma_send_fastreassoc_cmd(int sessionId, const tSirMacAddr bssid,
843 int channel)
844{
845 struct wma_roam_invoke_cmd *fastreassoc;
Rajeev Kumarea95edd2017-01-11 20:49:36 -0800846 struct scheduler_msg msg = {0};
Naveen Rawat05376ee2016-07-18 16:43:32 -0700847
848 fastreassoc = qdf_mem_malloc(sizeof(*fastreassoc));
849 if (NULL == fastreassoc) {
850 hdd_err("qdf_mem_malloc failed for fastreassoc");
851 return;
852 }
853 fastreassoc->vdev_id = sessionId;
854 fastreassoc->channel = channel;
855 fastreassoc->bssid[0] = bssid[0];
856 fastreassoc->bssid[1] = bssid[1];
857 fastreassoc->bssid[2] = bssid[2];
858 fastreassoc->bssid[3] = bssid[3];
859 fastreassoc->bssid[4] = bssid[4];
860 fastreassoc->bssid[5] = bssid[5];
861
862 msg.type = SIR_HAL_ROAM_INVOKE;
863 msg.reserved = 0;
864 msg.bodyptr = fastreassoc;
Rajeev Kumarea95edd2017-01-11 20:49:36 -0800865 if (QDF_STATUS_SUCCESS != scheduler_post_msg(QDF_MODULE_ID_WMA,
Naveen Rawat05376ee2016-07-18 16:43:32 -0700866 &msg)) {
867 qdf_mem_free(fastreassoc);
868 hdd_err("Not able to post ROAM_INVOKE_CMD message to WMA");
869 }
870}
Naveen Rawat05376ee2016-07-18 16:43:32 -0700871#endif
872
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800873/**
874 * hdd_reassoc() - perform a userspace-directed reassoc
Deepak Dhamdhere5a36a4a2016-11-12 15:08:22 -0800875 * @adapter: Adapter upon which the command was received
876 * @bssid: BSSID with which to reassociate
877 * @channel: channel upon which to reassociate
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700878 * @src: The source for the trigger of this action
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800879 *
880 * This function performs a userspace-directed reassoc operation
881 *
882 * Return: 0 for success non-zero for failure
883 */
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700884int hdd_reassoc(hdd_adapter_t *adapter, const uint8_t *bssid,
Deepak Dhamdhere5a36a4a2016-11-12 15:08:22 -0800885 uint8_t channel, const handoff_src src)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800886{
887 hdd_station_ctx_t *pHddStaCtx;
Naveen Rawat05376ee2016-07-18 16:43:32 -0700888 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800889 int ret = 0;
890
Naveen Rawat05376ee2016-07-18 16:43:32 -0700891 if (hdd_ctx == NULL) {
892 hdd_err("Invalid hdd ctx");
893 return -EINVAL;
894 }
895
Krunal Sonibe766b02016-03-10 13:00:44 -0800896 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800897 hdd_warn("Unsupported in mode %s(%d)",
898 hdd_device_mode_to_string(adapter->device_mode),
899 adapter->device_mode);
900 return -EINVAL;
901 }
902
903 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
904
905 /* if not associated, no need to proceed with reassoc */
906 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700907 hdd_info("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800908 ret = -EINVAL;
909 goto exit;
910 }
911
912 /*
913 * if the target bssid is same as currently associated AP,
Deepak Dhamdhere5a36a4a2016-11-12 15:08:22 -0800914 * use the current connections's channel.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800915 */
916 if (!memcmp(bssid, pHddStaCtx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530917 QDF_MAC_ADDR_SIZE)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700918 hdd_info("Reassoc BSSID is same as currently associated AP bssid");
Deepak Dhamdhere5a36a4a2016-11-12 15:08:22 -0800919 channel = pHddStaCtx->conn_info.operationChannel;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800920 }
921
922 /* Check channel number is a valid channel number */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530923 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800924 wlan_hdd_validate_operation_channel(adapter, channel)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700925 hdd_err("Invalid Channel %d", channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800926 ret = -EINVAL;
927 goto exit;
928 }
929
930 /* Proceed with reassoc */
Naveen Rawat05376ee2016-07-18 16:43:32 -0700931 if (roaming_offload_enabled(hdd_ctx)) {
932 hdd_wma_send_fastreassoc_cmd((int)adapter->sessionId,
933 bssid, (int)channel);
934 } else {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800935 tCsrHandoffRequest handoffInfo;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800936
937 handoffInfo.channel = channel;
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700938 handoffInfo.src = src;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530939 qdf_mem_copy(handoffInfo.bssid.bytes, bssid, QDF_MAC_ADDR_SIZE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800940 sme_handoff_request(hdd_ctx->hHal, adapter->sessionId,
941 &handoffInfo);
942 }
943exit:
944 return ret;
945}
946
947/**
948 * hdd_parse_reassoc_v1() - parse version 1 of the REASSOC command
949 * @adapter: Adapter upon which the command was received
950 * @command: ASCII text command that was received
951 *
952 * This function parses the v1 REASSOC command with the format
953 *
954 * REASSOC xx:xx:xx:xx:xx:xx CH
955 *
956 * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the
957 * BSSID and CH is the ASCII representation of the channel. For
958 * example
959 *
960 * REASSOC 00:0a:0b:11:22:33 48
961 *
962 * Return: 0 for success non-zero for failure
963 */
964static int hdd_parse_reassoc_v1(hdd_adapter_t *adapter, const char *command)
965{
966 uint8_t channel = 0;
967 tSirMacAddr bssid;
968 int ret;
969
970 ret = hdd_parse_reassoc_command_v1_data(command, bssid, &channel);
971 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700972 hdd_err("Failed to parse reassoc command data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800973 } else {
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700974 ret = hdd_reassoc(adapter, bssid, channel, REASSOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800975 }
976 return ret;
977}
978
979/**
980 * hdd_parse_reassoc_v2() - parse version 2 of the REASSOC command
981 * @adapter: Adapter upon which the command was received
982 * @command: Command that was received, ASCII command
983 * followed by binary data
984 *
985 * This function parses the v2 REASSOC command with the format
986 *
987 * REASSOC <android_wifi_reassoc_params>
988 *
989 * Return: 0 for success non-zero for failure
990 */
991static int hdd_parse_reassoc_v2(hdd_adapter_t *adapter, const char *command)
992{
993 struct android_wifi_reassoc_params params;
994 tSirMacAddr bssid;
995 int ret;
996
997 /* The params are located after "REASSOC " */
998 memcpy(&params, command + 8, sizeof(params));
999
1000 if (!mac_pton(params.bssid, (u8 *) &bssid)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001001 hdd_err("MAC address parsing failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001002 ret = -EINVAL;
1003 } else {
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -07001004 ret = hdd_reassoc(adapter, bssid, params.channel, REASSOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001005 }
1006 return ret;
1007}
1008
1009/**
1010 * hdd_parse_reassoc() - parse the REASSOC command
1011 * @adapter: Adapter upon which the command was received
1012 * @command: Command that was received
1013 *
1014 * There are two different versions of the REASSOC command. Version 1
1015 * of the command contains a parameter list that is ASCII characters
1016 * whereas version 2 contains a combination of ASCII and binary
1017 * payload. Determine if a version 1 or a version 2 command is being
1018 * parsed by examining the parameters, and then dispatch the parser
1019 * that is appropriate for the command.
1020 *
1021 * Return: 0 for success non-zero for failure
1022 */
1023static int hdd_parse_reassoc(hdd_adapter_t *adapter, const char *command)
1024{
1025 int ret;
1026
1027 /* both versions start with "REASSOC "
1028 * v1 has a bssid and channel # as an ASCII string
1029 * REASSOC xx:xx:xx:xx:xx:xx CH
1030 * v2 has a C struct
1031 * REASSOC <binary c struct>
1032 *
1033 * The first field in the v2 struct is also the bssid in ASCII.
1034 * But in the case of a v2 message the BSSID is NUL-terminated.
1035 * Hence we can peek at that offset to see if this is V1 or V2
1036 * REASSOC xx:xx:xx:xx:xx:xx*
1037 * 1111111111222222
1038 * 01234567890123456789012345
1039 */
1040 if (command[25]) {
1041 ret = hdd_parse_reassoc_v1(adapter, command);
1042 } else {
1043 ret = hdd_parse_reassoc_v2(adapter, command);
1044 }
1045
1046 return ret;
1047}
1048
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001049/**
1050 * hdd_sendactionframe() - send a userspace-supplied action frame
1051 * @adapter: Adapter upon which the command was received
1052 * @bssid: BSSID target of the action frame
1053 * @channel: Channel upon which to send the frame
1054 * @dwell_time: Amount of time to dwell when the frame is sent
1055 * @payload_len:Length of the payload
1056 * @payload: Payload of the frame
1057 *
1058 * This function sends a userspace-supplied action frame
1059 *
1060 * Return: 0 for success non-zero for failure
1061 */
1062static int
1063hdd_sendactionframe(hdd_adapter_t *adapter, const uint8_t *bssid,
1064 const uint8_t channel, const uint8_t dwell_time,
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001065 const int payload_len, const uint8_t *payload)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001066{
1067 struct ieee80211_channel chan;
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001068 int frame_len, ret = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001069 uint8_t *frame;
1070 struct ieee80211_hdr_3addr *hdr;
1071 u64 cookie;
1072 hdd_station_ctx_t *pHddStaCtx;
1073 hdd_context_t *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001074 tpSirMacVendorSpecificFrameHdr pVendorSpecific =
1075 (tpSirMacVendorSpecificFrameHdr) payload;
1076#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
1077 struct cfg80211_mgmt_tx_params params;
1078#endif
1079
Krunal Sonibe766b02016-03-10 13:00:44 -08001080 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001081 hdd_warn("Unsupported in mode %s(%d)",
1082 hdd_device_mode_to_string(adapter->device_mode),
1083 adapter->device_mode);
1084 return -EINVAL;
1085 }
1086
1087 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
1088 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1089
1090 /* if not associated, no need to send action frame */
1091 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001092 hdd_info("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001093 ret = -EINVAL;
1094 goto exit;
1095 }
1096
1097 /*
1098 * if the target bssid is different from currently associated AP,
1099 * then no need to send action frame
1100 */
1101 if (memcmp(bssid, pHddStaCtx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05301102 QDF_MAC_ADDR_SIZE)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001103 hdd_info("STA is not associated to this AP");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001104 ret = -EINVAL;
1105 goto exit;
1106 }
1107
1108 chan.center_freq = sme_chn_to_freq(channel);
1109 /* Check if it is specific action frame */
1110 if (pVendorSpecific->category ==
1111 SIR_MAC_ACTION_VENDOR_SPECIFIC_CATEGORY) {
1112 static const uint8_t Oui[] = { 0x00, 0x00, 0xf0 };
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301113 if (!qdf_mem_cmp(pVendorSpecific->Oui, (void *)Oui, 3)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001114 /*
1115 * if the channel number is different from operating
1116 * channel then no need to send action frame
1117 */
1118 if (channel != 0) {
1119 if (channel !=
1120 pHddStaCtx->conn_info.operationChannel) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001121 hdd_info("channel(%d) is different from operating channel(%d)",
1122 channel,
1123 pHddStaCtx->conn_info.
1124 operationChannel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001125 ret = -EINVAL;
1126 goto exit;
1127 }
1128 /*
1129 * If channel number is specified and same
1130 * as home channel, ensure that action frame
1131 * is sent immediately by cancelling
1132 * roaming scans. Otherwise large dwell times
1133 * may cause long delays in sending action
1134 * frames.
1135 */
1136 sme_abort_roam_scan(hdd_ctx->hHal,
1137 adapter->sessionId);
1138 } else {
1139 /*
1140 * 0 is accepted as current home channel,
1141 * delayed transmission of action frame is ok.
1142 */
1143 chan.center_freq =
1144 sme_chn_to_freq(pHddStaCtx->conn_info.
1145 operationChannel);
1146 }
1147 }
1148 }
1149 if (chan.center_freq == 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001150 hdd_err("Invalid channel number %d", channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001151 ret = -EINVAL;
1152 goto exit;
1153 }
1154
1155 frame_len = payload_len + 24;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301156 frame = qdf_mem_malloc(frame_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001157 if (!frame) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001158 hdd_err("memory allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001159 ret = -ENOMEM;
1160 goto exit;
1161 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001162
1163 hdr = (struct ieee80211_hdr_3addr *)frame;
1164 hdr->frame_control =
1165 cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301166 qdf_mem_copy(hdr->addr1, bssid, QDF_MAC_ADDR_SIZE);
1167 qdf_mem_copy(hdr->addr2, adapter->macAddressCurrent.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05301168 QDF_MAC_ADDR_SIZE);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301169 qdf_mem_copy(hdr->addr3, bssid, QDF_MAC_ADDR_SIZE);
1170 qdf_mem_copy(hdr + 1, payload, payload_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001171
1172#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
1173 params.chan = &chan;
1174 params.offchan = 0;
1175 params.wait = dwell_time;
1176 params.buf = frame;
1177 params.len = frame_len;
1178 params.no_cck = 1;
1179 params.dont_wait_for_ack = 1;
1180 ret = wlan_hdd_mgmt_tx(NULL, &adapter->wdev, &params, &cookie);
1181#else
1182 ret = wlan_hdd_mgmt_tx(NULL,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001183 &(adapter->wdev),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001184 &chan, 0,
Amar Singhal01098f72015-10-08 11:55:32 -07001185
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001186 dwell_time, frame, frame_len, 1, 1, &cookie);
1187#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
1188
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301189 qdf_mem_free(frame);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001190exit:
1191 return ret;
1192}
1193
1194/**
1195 * hdd_parse_sendactionframe_v1() - parse version 1 of the
1196 * SENDACTIONFRAME command
1197 * @adapter: Adapter upon which the command was received
1198 * @command: ASCII text command that was received
1199 *
1200 * This function parses the v1 SENDACTIONFRAME command with the format
1201 *
1202 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DW xxxxxx
1203 *
1204 * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the
1205 * BSSID, CH is the ASCII representation of the channel, DW is the
1206 * ASCII representation of the dwell time, and xxxxxx is the Hex-ASCII
1207 * payload. For example
1208 *
1209 * SENDACTIONFRAME 00:0a:0b:11:22:33 48 40 aabbccddee
1210 *
1211 * Return: 0 for success non-zero for failure
1212 */
1213static int
1214hdd_parse_sendactionframe_v1(hdd_adapter_t *adapter, const char *command)
1215{
1216 uint8_t channel = 0;
1217 uint8_t dwell_time = 0;
1218 uint8_t payload_len = 0;
1219 uint8_t *payload = NULL;
1220 tSirMacAddr bssid;
1221 int ret;
1222
1223 ret = hdd_parse_send_action_frame_v1_data(command, bssid, &channel,
1224 &dwell_time, &payload,
1225 &payload_len);
1226 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001227 hdd_err("Failed to parse send action frame data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001228 } else {
1229 ret = hdd_sendactionframe(adapter, bssid, channel,
1230 dwell_time, payload_len, payload);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301231 qdf_mem_free(payload);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001232 }
1233
1234 return ret;
1235}
1236
1237/**
1238 * hdd_parse_sendactionframe_v2() - parse version 2 of the
1239 * SENDACTIONFRAME command
1240 * @adapter: Adapter upon which the command was received
1241 * @command: Command that was received, ASCII command
1242 * followed by binary data
1243 *
1244 * This function parses the v2 SENDACTIONFRAME command with the format
1245 *
1246 * SENDACTIONFRAME <android_wifi_af_params>
1247 *
1248 * Return: 0 for success non-zero for failure
1249 */
1250static int
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001251hdd_parse_sendactionframe_v2(hdd_adapter_t *adapter,
1252 const char *command, int total_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001253{
1254 struct android_wifi_af_params *params;
1255 tSirMacAddr bssid;
1256 int ret;
1257
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001258 /* The params are located after "SENDACTIONFRAME " */
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001259 total_len -= 16;
1260 params = (struct android_wifi_af_params *)(command + 16);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001261
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001262 if (params->len <= 0 || params->len > ANDROID_WIFI_ACTION_FRAME_SIZE ||
1263 (params->len > total_len)) {
1264 hdd_err("Invalid payload length: %d", params->len);
1265 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001266 }
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001267
1268 if (!mac_pton(params->bssid, (u8 *)&bssid)) {
1269 hdd_err("MAC address parsing failed");
1270 return -EINVAL;
1271 }
1272
1273 if (params->channel < 0 ||
1274 params->channel > WNI_CFG_CURRENT_CHANNEL_STAMAX) {
1275 hdd_err("Invalid channel: %d", params->channel);
1276 return -EINVAL;
1277 }
1278
1279 if (params->dwell_time < 0) {
1280 hdd_err("Invalid dwell_time: %d", params->dwell_time);
1281 return -EINVAL;
1282 }
1283
1284 ret = hdd_sendactionframe(adapter, bssid, params->channel,
1285 params->dwell_time, params->len, params->data);
1286
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001287 return ret;
1288}
1289
1290/**
1291 * hdd_parse_sendactionframe() - parse the SENDACTIONFRAME command
1292 * @adapter: Adapter upon which the command was received
1293 * @command: Command that was received
1294 *
1295 * There are two different versions of the SENDACTIONFRAME command.
1296 * Version 1 of the command contains a parameter list that is ASCII
1297 * characters whereas version 2 contains a combination of ASCII and
1298 * binary payload. Determine if a version 1 or a version 2 command is
1299 * being parsed by examining the parameters, and then dispatch the
1300 * parser that is appropriate for the version of the command.
1301 *
1302 * Return: 0 for success non-zero for failure
1303 */
1304static int
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001305hdd_parse_sendactionframe(hdd_adapter_t *adapter, const char *command,
1306 int total_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001307{
1308 int ret;
1309
1310 /*
1311 * both versions start with "SENDACTIONFRAME "
1312 * v1 has a bssid and other parameters as an ASCII string
1313 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DWELL LEN FRAME
1314 * v2 has a C struct
1315 * SENDACTIONFRAME <binary c struct>
1316 *
1317 * The first field in the v2 struct is also the bssid in ASCII.
1318 * But in the case of a v2 message the BSSID is NUL-terminated.
1319 * Hence we can peek at that offset to see if this is V1 or V2
1320 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx*
1321 * 111111111122222222223333
1322 * 0123456789012345678901234567890123
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001323 * For both the commands, a valid command must have atleast
1324 * first 34 length of data.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001325 */
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001326 if (total_len < 34) {
1327 hdd_err("Invalid command (total_len=%d)", total_len);
1328 return -EINVAL;
1329 }
1330
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001331 if (command[33]) {
1332 ret = hdd_parse_sendactionframe_v1(adapter, command);
1333 } else {
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001334 ret = hdd_parse_sendactionframe_v2(adapter, command, total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001335 }
1336
1337 return ret;
1338}
1339
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001340/**
1341 * hdd_parse_channellist() - HDD Parse channel list
1342 * @pValue: Pointer to input channel list
1343 * @ChannelList: Pointer to local output array to record
1344 * channel list
1345 * @pNumChannels: Pointer to number of roam scan channels
1346 *
1347 * This function parses the channel list passed in the format
1348 * SETROAMSCANCHANNELS<space><Number of channels><space>Channel 1<space>Channel 2<space>Channel N
1349 * if the Number of channels (N) does not match with the actual number
1350 * of channels passed then take the minimum of N and count of
1351 * (Ch1, Ch2, ...Ch M). For example, if SETROAMSCANCHANNELS 3 36 40 44 48,
1352 * only 36, 40 and 44 shall be taken. If SETROAMSCANCHANNELS 5 36 40 44 48,
1353 * ignore 5 and take 36, 40, 44 and 48. This function does not take care of
1354 * removing duplicate channels from the list
1355 *
1356 * Return: 0 for success non-zero for failure
1357 */
1358static int
1359hdd_parse_channellist(const uint8_t *pValue, uint8_t *pChannelList,
1360 uint8_t *pNumChannels)
1361{
1362 const uint8_t *inPtr = pValue;
1363 int tempInt;
1364 int j = 0;
1365 int v = 0;
1366 char buf[32];
1367
1368 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
1369 /* no argument after the command */
1370 if (NULL == inPtr) {
1371 return -EINVAL;
1372 }
1373
1374 /* no space after the command */
1375 else if (SPACE_ASCII_VALUE != *inPtr) {
1376 return -EINVAL;
1377 }
1378
1379 /* remove empty spaces */
1380 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
1381 inPtr++;
1382
1383 /* no argument followed by spaces */
1384 if ('\0' == *inPtr) {
1385 return -EINVAL;
1386 }
1387
1388 /* get the first argument ie the number of channels */
1389 v = sscanf(inPtr, "%31s ", buf);
1390 if (1 != v)
1391 return -EINVAL;
1392
1393 v = kstrtos32(buf, 10, &tempInt);
1394 if ((v < 0) ||
1395 (tempInt <= 0) || (tempInt > WNI_CFG_VALID_CHANNEL_LIST_LEN)) {
1396 return -EINVAL;
1397 }
1398
1399 *pNumChannels = tempInt;
1400
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001401 hdd_info("Number of channels are: %d", *pNumChannels);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001402
1403 for (j = 0; j < (*pNumChannels); j++) {
1404 /*
1405 * inPtr pointing to the beginning of first space after number
1406 * of channels
1407 */
1408 inPtr = strpbrk(inPtr, " ");
1409 /* no channel list after the number of channels argument */
1410 if (NULL == inPtr) {
1411 if (0 != j) {
1412 *pNumChannels = j;
1413 return 0;
1414 } else {
1415 return -EINVAL;
1416 }
1417 }
1418
1419 /* remove empty space */
1420 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
1421 inPtr++;
1422
1423 /*
1424 * no channel list after the number of channels
1425 * argument and spaces
1426 */
1427 if ('\0' == *inPtr) {
1428 if (0 != j) {
1429 *pNumChannels = j;
1430 return 0;
1431 } else {
1432 return -EINVAL;
1433 }
1434 }
1435
1436 v = sscanf(inPtr, "%31s ", buf);
1437 if (1 != v)
1438 return -EINVAL;
1439
1440 v = kstrtos32(buf, 10, &tempInt);
1441 if ((v < 0) ||
1442 (tempInt <= 0) ||
1443 (tempInt > WNI_CFG_CURRENT_CHANNEL_STAMAX)) {
1444 return -EINVAL;
1445 }
1446 pChannelList[j] = tempInt;
1447
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001448 hdd_info("Channel %d added to preferred channel list",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001449 pChannelList[j]);
1450 }
1451
1452 return 0;
1453}
1454
1455/**
1456 * hdd_parse_set_roam_scan_channels_v1() - parse version 1 of the
1457 * SETROAMSCANCHANNELS command
1458 * @adapter: Adapter upon which the command was received
1459 * @command: ASCII text command that was received
1460 *
1461 * This function parses the v1 SETROAMSCANCHANNELS command with the format
1462 *
1463 * SETROAMSCANCHANNELS N C1 C2 ... Cn
1464 *
1465 * Where "N" is the ASCII representation of the number of channels and
1466 * C1 thru Cn is the ASCII representation of the channels. For example
1467 *
1468 * SETROAMSCANCHANNELS 4 36 40 44 48
1469 *
1470 * Return: 0 for success non-zero for failure
1471 */
1472static int
1473hdd_parse_set_roam_scan_channels_v1(hdd_adapter_t *adapter,
1474 const char *command)
1475{
1476 uint8_t channel_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
1477 uint8_t num_chan = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301478 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001479 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1480 int ret;
1481
1482 ret = hdd_parse_channellist(command, channel_list, &num_chan);
1483 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001484 hdd_err("Failed to parse channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001485 goto exit;
1486 }
1487
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301488 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001489 TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL,
1490 adapter->sessionId, num_chan));
1491
1492 if (num_chan > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001493 hdd_err("number of channels (%d) supported exceeded max (%d)",
1494 num_chan, WNI_CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001495 ret = -EINVAL;
1496 goto exit;
1497 }
1498
1499 status =
1500 sme_change_roam_scan_channel_list(hdd_ctx->hHal,
1501 adapter->sessionId,
1502 channel_list, num_chan);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301503 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001504 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001505 ret = -EINVAL;
1506 goto exit;
1507 }
1508exit:
1509 return ret;
1510}
1511
1512/**
1513 * hdd_parse_set_roam_scan_channels_v2() - parse version 2 of the
1514 * SETROAMSCANCHANNELS command
1515 * @adapter: Adapter upon which the command was received
1516 * @command: Command that was received, ASCII command
1517 * followed by binary data
1518 *
1519 * This function parses the v2 SETROAMSCANCHANNELS command with the format
1520 *
1521 * SETROAMSCANCHANNELS [N][C1][C2][Cn]
1522 *
1523 * The command begins with SETROAMSCANCHANNELS followed by a space, but
1524 * what follows the space is an array of u08 parameters. For example
1525 *
1526 * SETROAMSCANCHANNELS [0x04 0x24 0x28 0x2c 0x30]
1527 *
1528 * Return: 0 for success non-zero for failure
1529 */
1530static int
1531hdd_parse_set_roam_scan_channels_v2(hdd_adapter_t *adapter,
1532 const char *command)
1533{
1534 const uint8_t *value;
1535 uint8_t channel_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
1536 uint8_t channel;
1537 uint8_t num_chan;
1538 int i;
1539 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301540 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001541 int ret = 0;
1542
1543 /* array of values begins after "SETROAMSCANCHANNELS " */
1544 value = command + 20;
1545
1546 num_chan = *value++;
1547 if (num_chan > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001548 hdd_err("number of channels (%d) supported exceeded max (%d)",
1549 num_chan, WNI_CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001550 ret = -EINVAL;
1551 goto exit;
1552 }
1553
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301554 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001555 TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL,
1556 adapter->sessionId, num_chan));
1557
1558 for (i = 0; i < num_chan; i++) {
1559 channel = *value++;
1560 if (channel > WNI_CFG_CURRENT_CHANNEL_STAMAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001561 hdd_err("index %d invalid channel %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001562 i, channel);
1563 ret = -EINVAL;
1564 goto exit;
1565 }
1566 channel_list[i] = channel;
1567 }
1568 status =
1569 sme_change_roam_scan_channel_list(hdd_ctx->hHal,
1570 adapter->sessionId,
1571 channel_list, num_chan);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301572 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001573 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001574 ret = -EINVAL;
1575 goto exit;
1576 }
1577exit:
1578 return ret;
1579}
1580
1581/**
1582 * hdd_parse_set_roam_scan_channels() - parse the
1583 * SETROAMSCANCHANNELS command
1584 * @adapter: Adapter upon which the command was received
1585 * @command: Command that was received
1586 *
1587 * There are two different versions of the SETROAMSCANCHANNELS command.
1588 * Version 1 of the command contains a parameter list that is ASCII
1589 * characters whereas version 2 contains a binary payload. Determine
1590 * if a version 1 or a version 2 command is being parsed by examining
1591 * the parameters, and then dispatch the parser that is appropriate for
1592 * the command.
1593 *
1594 * Return: 0 for success non-zero for failure
1595 */
1596static int
1597hdd_parse_set_roam_scan_channels(hdd_adapter_t *adapter, const char *command)
1598{
1599 const char *cursor;
1600 char ch;
1601 bool v1;
1602 int ret;
1603
1604 /* start after "SETROAMSCANCHANNELS " */
1605 cursor = command + 20;
1606
1607 /* assume we have a version 1 command until proven otherwise */
1608 v1 = true;
1609
1610 /* v1 params will only contain ASCII digits and space */
1611 while ((ch = *cursor++) && v1) {
1612 if (!(isdigit(ch) || isspace(ch))) {
1613 v1 = false;
1614 }
1615 }
1616 if (v1) {
1617 ret = hdd_parse_set_roam_scan_channels_v1(adapter, command);
1618 } else {
1619 ret = hdd_parse_set_roam_scan_channels_v2(adapter, command);
1620 }
1621
1622 return ret;
1623}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001624
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08001625#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001626/**
1627 * hdd_parse_plm_cmd() - HDD Parse Plm command
1628 * @pValue: Pointer to input data
1629 * @pPlmRequest:Pointer to output struct tpSirPlmReq
1630 *
1631 * This function parses the plm command passed in the format
1632 * CCXPLMREQ<space><enable><space><dialog_token><space>
1633 * <meas_token><space><num_of_bursts><space><burst_int><space>
1634 * <measu duration><space><burst_len><space><desired_tx_pwr>
1635 * <space><multcast_addr><space><number_of_channels>
1636 * <space><channel_numbers>
1637 *
1638 * Return: 0 for success non-zero for failure
1639 */
Jeff Johnsonf731b302016-10-05 16:00:55 -07001640static QDF_STATUS hdd_parse_plm_cmd(uint8_t *pValue, tSirPlmReq *pPlmRequest)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001641{
1642 uint8_t *cmdPtr = NULL;
1643 int count, content = 0, ret = 0;
1644 char buf[32];
1645
1646 /* move to argument list */
1647 cmdPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
1648 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301649 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001650
1651 /* no space after the command */
1652 if (SPACE_ASCII_VALUE != *cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301653 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001654
1655 /* remove empty spaces */
1656 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1657 cmdPtr++;
1658
1659 /* START/STOP PLM req */
1660 ret = sscanf(cmdPtr, "%31s ", buf);
1661 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301662 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001663
1664 ret = kstrtos32(buf, 10, &content);
1665 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301666 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001667
1668 pPlmRequest->enable = content;
1669 cmdPtr = strpbrk(cmdPtr, " ");
1670
1671 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301672 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001673
1674 /* remove empty spaces */
1675 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1676 cmdPtr++;
1677
1678 /* Dialog token of radio meas req containing meas reqIE */
1679 ret = sscanf(cmdPtr, "%31s ", buf);
1680 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301681 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001682
1683 ret = kstrtos32(buf, 10, &content);
1684 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301685 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001686
1687 pPlmRequest->diag_token = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001688 hdd_debug("diag token %d", pPlmRequest->diag_token);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001689 cmdPtr = strpbrk(cmdPtr, " ");
1690
1691 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301692 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001693
1694 /* remove empty spaces */
1695 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1696 cmdPtr++;
1697
1698 /* measurement token of meas req IE */
1699 ret = sscanf(cmdPtr, "%31s ", buf);
1700 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301701 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001702
1703 ret = kstrtos32(buf, 10, &content);
1704 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301705 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001706
1707 pPlmRequest->meas_token = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001708 hdd_debug("meas token %d", pPlmRequest->meas_token);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001709
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001710 hdd_err("PLM req %s", pPlmRequest->enable ? "START" : "STOP");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001711 if (pPlmRequest->enable) {
1712
1713 cmdPtr = strpbrk(cmdPtr, " ");
1714
1715 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301716 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001717
1718 /* remove empty spaces */
1719 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1720 cmdPtr++;
1721
1722 /* total number of bursts after which STA stops sending */
1723 ret = sscanf(cmdPtr, "%31s ", buf);
1724 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301725 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001726
1727 ret = kstrtos32(buf, 10, &content);
1728 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301729 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001730
1731 if (content < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301732 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001733
1734 pPlmRequest->numBursts = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001735 hdd_debug("num burst %d", pPlmRequest->numBursts);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001736 cmdPtr = strpbrk(cmdPtr, " ");
1737
1738 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301739 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001740
1741 /* remove empty spaces */
1742 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1743 cmdPtr++;
1744
1745 /* burst interval in seconds */
1746 ret = sscanf(cmdPtr, "%31s ", buf);
1747 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301748 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001749
1750 ret = kstrtos32(buf, 10, &content);
1751 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301752 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001753
1754 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301755 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001756
1757 pPlmRequest->burstInt = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001758 hdd_debug("burst Int %d", pPlmRequest->burstInt);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001759 cmdPtr = strpbrk(cmdPtr, " ");
1760
1761 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301762 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001763
1764 /* remove empty spaces */
1765 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1766 cmdPtr++;
1767
1768 /* Meas dur in TU's,STA goes off-ch and transmit PLM bursts */
1769 ret = sscanf(cmdPtr, "%31s ", buf);
1770 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301771 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001772
1773 ret = kstrtos32(buf, 10, &content);
1774 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301775 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001776
1777 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301778 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001779
1780 pPlmRequest->measDuration = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001781 hdd_debug("measDur %d", pPlmRequest->measDuration);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001782 cmdPtr = strpbrk(cmdPtr, " ");
1783
1784 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301785 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001786
1787 /* remove empty spaces */
1788 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1789 cmdPtr++;
1790
1791 /* burst length of PLM bursts */
1792 ret = sscanf(cmdPtr, "%31s ", buf);
1793 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301794 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001795
1796 ret = kstrtos32(buf, 10, &content);
1797 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301798 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001799
1800 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301801 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001802
1803 pPlmRequest->burstLen = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001804 hdd_debug("burstLen %d", pPlmRequest->burstLen);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001805 cmdPtr = strpbrk(cmdPtr, " ");
1806
1807 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301808 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001809
1810 /* remove empty spaces */
1811 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1812 cmdPtr++;
1813
1814 /* desired tx power for transmission of PLM bursts */
1815 ret = sscanf(cmdPtr, "%31s ", buf);
1816 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301817 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001818
1819 ret = kstrtos32(buf, 10, &content);
1820 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301821 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001822
1823 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301824 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001825
1826 pPlmRequest->desiredTxPwr = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001827 hdd_debug("desiredTxPwr %d",
1828 pPlmRequest->desiredTxPwr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001829
Anurag Chouhan6d760662016-02-20 16:05:43 +05301830 for (count = 0; count < QDF_MAC_ADDR_SIZE; count++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001831 cmdPtr = strpbrk(cmdPtr, " ");
1832
1833 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301834 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001835
1836 /* remove empty spaces */
1837 while ((SPACE_ASCII_VALUE == *cmdPtr)
1838 && ('\0' != *cmdPtr))
1839 cmdPtr++;
1840
1841 ret = sscanf(cmdPtr, "%31s ", buf);
1842 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301843 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001844
1845 ret = kstrtos32(buf, 16, &content);
1846 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301847 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001848
Srinivas Girigowda5146dee2015-11-18 21:46:48 -08001849 pPlmRequest->mac_addr.bytes[count] = content;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001850 }
1851
Srinivas Girigowda5146dee2015-11-18 21:46:48 -08001852 hdd_debug("MC addr " MAC_ADDRESS_STR,
1853 MAC_ADDR_ARRAY(pPlmRequest->mac_addr.bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001854
1855 cmdPtr = strpbrk(cmdPtr, " ");
1856
1857 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301858 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001859
1860 /* remove empty spaces */
1861 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1862 cmdPtr++;
1863
1864 /* number of channels */
1865 ret = sscanf(cmdPtr, "%31s ", buf);
1866 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301867 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001868
1869 ret = kstrtos32(buf, 10, &content);
1870 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301871 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001872
1873 if (content < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301874 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001875
Srinivas Girigowda0fb6cc42016-08-26 14:53:59 -07001876 content = QDF_MIN(content, WNI_CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001877 pPlmRequest->plmNumCh = content;
Srinivas Girigowda0fb6cc42016-08-26 14:53:59 -07001878 hdd_debug("numch: %d", pPlmRequest->plmNumCh);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001879
1880 /* Channel numbers */
1881 for (count = 0; count < pPlmRequest->plmNumCh; count++) {
1882 cmdPtr = strpbrk(cmdPtr, " ");
1883
1884 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301885 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001886
1887 /* remove empty spaces */
1888 while ((SPACE_ASCII_VALUE == *cmdPtr)
1889 && ('\0' != *cmdPtr))
1890 cmdPtr++;
1891
1892 ret = sscanf(cmdPtr, "%31s ", buf);
1893 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301894 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001895
1896 ret = kstrtos32(buf, 10, &content);
Srinivas Girigowda0fb6cc42016-08-26 14:53:59 -07001897 if (ret < 0 || content <= 0 ||
1898 content > WNI_CFG_CURRENT_CHANNEL_STAMAX)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301899 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001900
1901 pPlmRequest->plmChList[count] = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001902 hdd_debug(" ch- %d", pPlmRequest->plmChList[count]);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001903 }
1904 }
1905 /* If PLM START */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301906 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001907}
1908#endif
1909
1910#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
1911static void wlan_hdd_ready_to_extwow(void *callbackContext, bool is_success)
1912{
1913 hdd_context_t *hdd_ctx = (hdd_context_t *) callbackContext;
1914 int rc;
1915
1916 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301917 if (rc)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001918 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001919 hdd_ctx->ext_wow_should_suspend = is_success;
1920 complete(&hdd_ctx->ready_to_extwow);
1921}
1922
1923static int hdd_enable_ext_wow(hdd_adapter_t *adapter,
1924 tpSirExtWoWParams arg_params)
1925{
1926 tSirExtWoWParams params;
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301927 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001928 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1929 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
1930 int rc;
1931
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301932 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001933
1934 INIT_COMPLETION(hdd_ctx->ready_to_extwow);
1935
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301936 qdf_ret_status = sme_configure_ext_wow(hHal, &params,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001937 &wlan_hdd_ready_to_extwow,
1938 hdd_ctx);
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301939 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001940 hdd_err("sme_configure_ext_wow returned failure %d",
1941 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001942 return -EPERM;
1943 }
1944
1945 rc = wait_for_completion_timeout(&hdd_ctx->ready_to_extwow,
1946 msecs_to_jiffies(WLAN_WAIT_TIME_READY_TO_EXTWOW));
1947 if (!rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001948 hdd_err("Failed to get ready to extwow");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001949 return -EPERM;
1950 }
1951
1952 if (hdd_ctx->ext_wow_should_suspend) {
1953 if (hdd_ctx->config->extWowGotoSuspend) {
1954 pm_message_t state;
1955
1956 state.event = PM_EVENT_SUSPEND;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001957 hdd_info("Received ready to ExtWoW. Going to suspend");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001958
1959 rc = wlan_hdd_cfg80211_suspend_wlan(hdd_ctx->wiphy, NULL);
1960 if (rc < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001961 hdd_err("wlan_hdd_cfg80211_suspend_wlan failed, error = %d",
1962 rc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001963 return rc;
1964 }
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301965 qdf_ret_status = wlan_hdd_bus_suspend(state);
1966 if (qdf_ret_status != QDF_STATUS_SUCCESS) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001967 hdd_err("wlan_hdd_suspend failed, status = %d",
1968 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001969 wlan_hdd_cfg80211_resume_wlan(hdd_ctx->wiphy);
1970 return -EPERM;
1971 }
1972 }
1973 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001974 hdd_err("Received ready to ExtWoW failure");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001975 return -EPERM;
1976 }
1977
1978 return 0;
1979}
1980
1981static int hdd_enable_ext_wow_parser(hdd_adapter_t *adapter, int vdev_id,
1982 int value)
1983{
1984 tSirExtWoWParams params;
1985 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1986 int rc;
1987
1988 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301989 if (rc)
1990 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001991
1992 if (value < EXT_WOW_TYPE_APP_TYPE1 ||
1993 value > EXT_WOW_TYPE_APP_TYPE1_2) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001994 hdd_err("Invalid type");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001995 return -EINVAL;
1996 }
1997
1998 if (value == EXT_WOW_TYPE_APP_TYPE1 &&
1999 hdd_ctx->is_extwow_app_type1_param_set)
2000 params.type = value;
2001 else if (value == EXT_WOW_TYPE_APP_TYPE2 &&
2002 hdd_ctx->is_extwow_app_type2_param_set)
2003 params.type = value;
2004 else if (value == EXT_WOW_TYPE_APP_TYPE1_2 &&
2005 hdd_ctx->is_extwow_app_type1_param_set &&
2006 hdd_ctx->is_extwow_app_type2_param_set)
2007 params.type = value;
2008 else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002009 hdd_err("Set app params before enable it value %d",
2010 value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002011 return -EINVAL;
2012 }
2013
2014 params.vdev_id = vdev_id;
2015 params.wakeup_pin_num = hdd_ctx->config->extWowApp1WakeupPinNumber |
2016 (hdd_ctx->config->extWowApp2WakeupPinNumber
2017 << 8);
2018
2019 return hdd_enable_ext_wow(adapter, &params);
2020}
2021
2022static int hdd_set_app_type1_params(tHalHandle hHal,
2023 tpSirAppType1Params arg_params)
2024{
2025 tSirAppType1Params params;
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05302026 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002027
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302028 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002029
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05302030 qdf_ret_status = sme_configure_app_type1_params(hHal, &params);
2031 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002032 hdd_err("sme_configure_app_type1_params returned failure %d",
2033 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002034 return -EPERM;
2035 }
2036
2037 return 0;
2038}
2039
2040static int hdd_set_app_type1_parser(hdd_adapter_t *adapter,
2041 char *arg, int len)
2042{
2043 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2044 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
2045 char id[20], password[20];
2046 tSirAppType1Params params;
Srinivas Girigowda04209912015-11-24 12:11:13 -08002047 int rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002048
2049 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302050 if (rc)
2051 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002052
2053 if (2 != sscanf(arg, "%8s %16s", id, password)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002054 hdd_err("Invalid Number of arguments");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002055 return -EINVAL;
2056 }
2057
2058 memset(&params, 0, sizeof(tSirAppType1Params));
2059 params.vdev_id = adapter->sessionId;
Anurag Chouhanc5548422016-02-24 18:33:27 +05302060 qdf_copy_macaddr(&params.wakee_mac_addr, &adapter->macAddressCurrent);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002061
2062 params.id_length = strlen(id);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302063 qdf_mem_copy(params.identification_id, id, params.id_length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002064 params.pass_length = strlen(password);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302065 qdf_mem_copy(params.password, password, params.pass_length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002066
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002067 hdd_info("%d %pM %.8s %u %.16s %u",
2068 params.vdev_id, params.wakee_mac_addr.bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002069 params.identification_id, params.id_length,
2070 params.password, params.pass_length);
2071
2072 return hdd_set_app_type1_params(hHal, &params);
2073}
2074
2075static int hdd_set_app_type2_params(tHalHandle hHal,
2076 tpSirAppType2Params arg_params)
2077{
2078 tSirAppType2Params params;
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05302079 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002080
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302081 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002082
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05302083 qdf_ret_status = sme_configure_app_type2_params(hHal, &params);
2084 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002085 hdd_err("sme_configure_app_type2_params returned failure %d",
2086 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002087 return -EPERM;
2088 }
2089
2090 return 0;
2091}
2092
2093static int hdd_set_app_type2_parser(hdd_adapter_t *adapter,
2094 char *arg, int len)
2095{
2096 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2097 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
2098 char mac_addr[20], rc4_key[20];
Anurag Chouhan6d760662016-02-20 16:05:43 +05302099 unsigned int gateway_mac[QDF_MAC_ADDR_SIZE];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002100 tSirAppType2Params params;
2101 int ret;
2102
2103 ret = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302104 if (ret)
2105 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002106
2107 memset(&params, 0, sizeof(tSirAppType2Params));
2108
Bhargav Shahf4fd97d2015-07-08 10:21:37 +05302109 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 -08002110 mac_addr, rc4_key, (unsigned int *)&params.ip_id,
2111 (unsigned int *)&params.ip_device_ip,
2112 (unsigned int *)&params.ip_server_ip,
2113 (unsigned int *)&params.tcp_seq,
2114 (unsigned int *)&params.tcp_ack_seq,
Bhargav Shahf4fd97d2015-07-08 10:21:37 +05302115 (uint16_t *)&params.tcp_src_port,
2116 (uint16_t *)&params.tcp_dst_port,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002117 (unsigned int *)&params.keepalive_init,
2118 (unsigned int *)&params.keepalive_min,
2119 (unsigned int *)&params.keepalive_max,
2120 (unsigned int *)&params.keepalive_inc,
2121 (unsigned int *)&params.tcp_tx_timeout_val,
2122 (unsigned int *)&params.tcp_rx_timeout_val);
2123
2124 if (ret != 15 && ret != 7) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002125 hdd_err("Invalid Number of arguments");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002126 return -EINVAL;
2127 }
2128
2129 if (6 !=
2130 sscanf(mac_addr, "%02x:%02x:%02x:%02x:%02x:%02x", &gateway_mac[0],
2131 &gateway_mac[1], &gateway_mac[2], &gateway_mac[3],
2132 &gateway_mac[4], &gateway_mac[5])) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002133 hdd_err("Invalid MacAddress Input %s", mac_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002134 return -EINVAL;
2135 }
2136
2137 if (params.tcp_src_port > WLAN_HDD_MAX_TCP_PORT ||
2138 params.tcp_dst_port > WLAN_HDD_MAX_TCP_PORT) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002139 hdd_err("Invalid TCP Port Number");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002140 return -EINVAL;
2141 }
2142
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302143 qdf_mem_copy(&params.gateway_mac.bytes, (uint8_t *) &gateway_mac,
Anurag Chouhan6d760662016-02-20 16:05:43 +05302144 QDF_MAC_ADDR_SIZE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002145
2146 params.rc4_key_len = strlen(rc4_key);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302147 qdf_mem_copy(params.rc4_key, rc4_key, params.rc4_key_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002148
2149 params.vdev_id = adapter->sessionId;
2150 params.tcp_src_port = (params.tcp_src_port != 0) ?
2151 params.tcp_src_port : hdd_ctx->config->extWowApp2TcpSrcPort;
2152 params.tcp_dst_port = (params.tcp_dst_port != 0) ?
2153 params.tcp_dst_port : hdd_ctx->config->extWowApp2TcpDstPort;
2154 params.keepalive_init = (params.keepalive_init != 0) ?
2155 params.keepalive_init : hdd_ctx->config->
2156 extWowApp2KAInitPingInterval;
2157 params.keepalive_min =
2158 (params.keepalive_min != 0) ?
2159 params.keepalive_min :
2160 hdd_ctx->config->extWowApp2KAMinPingInterval;
2161 params.keepalive_max =
2162 (params.keepalive_max != 0) ?
2163 params.keepalive_max :
2164 hdd_ctx->config->extWowApp2KAMaxPingInterval;
2165 params.keepalive_inc =
2166 (params.keepalive_inc != 0) ?
2167 params.keepalive_inc :
2168 hdd_ctx->config->extWowApp2KAIncPingInterval;
2169 params.tcp_tx_timeout_val =
2170 (params.tcp_tx_timeout_val != 0) ?
2171 params.tcp_tx_timeout_val :
2172 hdd_ctx->config->extWowApp2TcpTxTimeout;
2173 params.tcp_rx_timeout_val =
2174 (params.tcp_rx_timeout_val != 0) ?
2175 params.tcp_rx_timeout_val :
2176 hdd_ctx->config->extWowApp2TcpRxTimeout;
2177
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002178 hdd_info("%pM %.16s %u %u %u %u %u %u %u %u %u %u %u %u %u",
2179 gateway_mac, rc4_key, params.ip_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002180 params.ip_device_ip, params.ip_server_ip, params.tcp_seq,
2181 params.tcp_ack_seq, params.tcp_src_port, params.tcp_dst_port,
2182 params.keepalive_init, params.keepalive_min,
2183 params.keepalive_max, params.keepalive_inc,
2184 params.tcp_tx_timeout_val, params.tcp_rx_timeout_val);
2185
2186 return hdd_set_app_type2_params(hHal, &params);
2187}
2188#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
2189
2190/**
2191 * hdd_parse_setmaxtxpower_command() - HDD Parse MAXTXPOWER command
2192 * @pValue: Pointer to MAXTXPOWER command
2193 * @pDbm: Pointer to tx power
2194 *
2195 * This function parses the MAXTXPOWER command passed in the format
2196 * MAXTXPOWER<space>X(Tx power in dbm)
2197 *
2198 * For example input commands:
2199 * 1) MAXTXPOWER -8 -> This is translated into set max TX power to -8 dbm
2200 * 2) MAXTXPOWER -23 -> This is translated into set max TX power to -23 dbm
2201 *
2202 * Return: 0 for success non-zero for failure
2203 */
2204static int hdd_parse_setmaxtxpower_command(uint8_t *pValue, int *pTxPower)
2205{
2206 uint8_t *inPtr = pValue;
2207 int tempInt;
2208 int v = 0;
2209 *pTxPower = 0;
2210
2211 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2212 /* no argument after the command */
2213 if (NULL == inPtr) {
2214 return -EINVAL;
2215 }
2216
2217 /* no space after the command */
2218 else if (SPACE_ASCII_VALUE != *inPtr) {
2219 return -EINVAL;
2220 }
2221
2222 /* remove empty spaces */
2223 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2224 inPtr++;
2225
2226 /* no argument followed by spaces */
2227 if ('\0' == *inPtr) {
2228 return 0;
2229 }
2230
2231 v = kstrtos32(inPtr, 10, &tempInt);
2232
2233 /* Range checking for passed parameter */
2234 if ((tempInt < HDD_MIN_TX_POWER) || (tempInt > HDD_MAX_TX_POWER)) {
2235 return -EINVAL;
2236 }
2237
2238 *pTxPower = tempInt;
2239
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002240 hdd_info("SETMAXTXPOWER: %d", *pTxPower);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002241
2242 return 0;
2243} /* End of hdd_parse_setmaxtxpower_command */
2244
2245static int hdd_get_dwell_time(struct hdd_config *pCfg, uint8_t *command,
2246 char *extra, uint8_t n, uint8_t *len)
2247{
2248 int ret = 0;
2249
2250 if (!pCfg || !command || !extra || !len) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002251 hdd_err("argument passed for GETDWELLTIME is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002252 ret = -EINVAL;
2253 return ret;
2254 }
2255
2256 if (strncmp(command, "GETDWELLTIME ACTIVE MAX", 23) == 0) {
2257 *len = scnprintf(extra, n, "GETDWELLTIME ACTIVE MAX %u\n",
2258 (int)pCfg->nActiveMaxChnTime);
2259 return ret;
2260 } else if (strncmp(command, "GETDWELLTIME ACTIVE MIN", 23) == 0) {
2261 *len = scnprintf(extra, n, "GETDWELLTIME ACTIVE MIN %u\n",
2262 (int)pCfg->nActiveMinChnTime);
2263 return ret;
2264 } else if (strncmp(command, "GETDWELLTIME PASSIVE MAX", 24) == 0) {
2265 *len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MAX %u\n",
2266 (int)pCfg->nPassiveMaxChnTime);
2267 return ret;
2268 } else if (strncmp(command, "GETDWELLTIME PASSIVE MIN", 24) == 0) {
2269 *len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MIN %u\n",
2270 (int)pCfg->nPassiveMinChnTime);
2271 return ret;
2272 } else if (strncmp(command, "GETDWELLTIME", 12) == 0) {
2273 *len = scnprintf(extra, n, "GETDWELLTIME %u \n",
2274 (int)pCfg->nActiveMaxChnTime);
2275 return ret;
2276 } else {
2277 ret = -EINVAL;
2278 }
2279
2280 return ret;
2281}
2282
2283static int hdd_set_dwell_time(hdd_adapter_t *adapter, uint8_t *command)
2284{
2285 tHalHandle hHal;
2286 struct hdd_config *pCfg;
2287 uint8_t *value = command;
2288 tSmeConfigParams smeConfig;
2289 int val = 0, temp = 0;
2290
2291 pCfg = (WLAN_HDD_GET_CTX(adapter))->config;
2292 hHal = WLAN_HDD_GET_HAL_CTX(adapter);
2293 if (!pCfg || !hHal) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002294 hdd_err("argument passed for SETDWELLTIME is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002295 return -EINVAL;
2296 }
2297
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302298 qdf_mem_zero(&smeConfig, sizeof(smeConfig));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002299 sme_get_config_param(hHal, &smeConfig);
2300
2301 if (strncmp(command, "SETDWELLTIME ACTIVE MAX", 23) == 0) {
2302 value = value + 24;
2303 temp = kstrtou32(value, 10, &val);
2304 if (temp != 0 || val < CFG_ACTIVE_MAX_CHANNEL_TIME_MIN ||
2305 val > CFG_ACTIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002306 hdd_err("argument passed for SETDWELLTIME ACTIVE MAX is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002307 return -EFAULT;
2308 }
2309 pCfg->nActiveMaxChnTime = val;
2310 smeConfig.csrConfig.nActiveMaxChnTime = val;
2311 sme_update_config(hHal, &smeConfig);
2312 } else if (strncmp(command, "SETDWELLTIME ACTIVE MIN", 23) == 0) {
2313 value = value + 24;
2314 temp = kstrtou32(value, 10, &val);
2315 if (temp != 0 || val < CFG_ACTIVE_MIN_CHANNEL_TIME_MIN ||
2316 val > CFG_ACTIVE_MIN_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002317 hdd_err("argument passed for SETDWELLTIME ACTIVE MIN is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002318 return -EFAULT;
2319 }
2320 pCfg->nActiveMinChnTime = val;
2321 smeConfig.csrConfig.nActiveMinChnTime = val;
2322 sme_update_config(hHal, &smeConfig);
2323 } else if (strncmp(command, "SETDWELLTIME PASSIVE MAX", 24) == 0) {
2324 value = value + 25;
2325 temp = kstrtou32(value, 10, &val);
2326 if (temp != 0 || val < CFG_PASSIVE_MAX_CHANNEL_TIME_MIN ||
2327 val > CFG_PASSIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002328 hdd_err("argument passed for SETDWELLTIME PASSIVE MAX is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002329 return -EFAULT;
2330 }
2331 pCfg->nPassiveMaxChnTime = val;
2332 smeConfig.csrConfig.nPassiveMaxChnTime = val;
2333 sme_update_config(hHal, &smeConfig);
2334 } else if (strncmp(command, "SETDWELLTIME PASSIVE MIN", 24) == 0) {
2335 value = value + 25;
2336 temp = kstrtou32(value, 10, &val);
2337 if (temp != 0 || val < CFG_PASSIVE_MIN_CHANNEL_TIME_MIN ||
2338 val > CFG_PASSIVE_MIN_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002339 hdd_err("argument passed for SETDWELLTIME PASSIVE MIN is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002340 return -EFAULT;
2341 }
2342 pCfg->nPassiveMinChnTime = val;
2343 smeConfig.csrConfig.nPassiveMinChnTime = val;
2344 sme_update_config(hHal, &smeConfig);
2345 } else if (strncmp(command, "SETDWELLTIME", 12) == 0) {
2346 value = value + 13;
2347 temp = kstrtou32(value, 10, &val);
2348 if (temp != 0 || val < CFG_ACTIVE_MAX_CHANNEL_TIME_MIN ||
2349 val > CFG_ACTIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002350 hdd_err("argument passed for SETDWELLTIME is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002351 return -EFAULT;
2352 }
2353 pCfg->nActiveMaxChnTime = val;
2354 smeConfig.csrConfig.nActiveMaxChnTime = val;
2355 sme_update_config(hHal, &smeConfig);
2356 } else {
2357 return -EINVAL;
2358 }
2359
2360 return 0;
2361}
2362
2363static void hdd_get_link_status_cb(uint8_t status, void *context)
2364{
2365 struct statsContext *pLinkContext;
2366 hdd_adapter_t *adapter;
2367
2368 if (NULL == context) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002369 hdd_err("Bad context [%p]", context);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002370 return;
2371 }
2372
2373 pLinkContext = context;
2374 adapter = pLinkContext->pAdapter;
2375
2376 spin_lock(&hdd_context_lock);
2377
2378 if ((NULL == adapter) ||
2379 (LINK_STATUS_MAGIC != pLinkContext->magic)) {
2380 /*
2381 * the caller presumably timed out so there is
2382 * nothing we can do
2383 */
2384 spin_unlock(&hdd_context_lock);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002385 hdd_warn("Invalid context, adapter [%p] magic [%08x]",
2386 adapter, pLinkContext->magic);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002387 return;
2388 }
2389
2390 /* context is valid so caller is still waiting */
2391
2392 /* paranoia: invalidate the magic */
2393 pLinkContext->magic = 0;
2394
2395 /* copy over the status */
2396 adapter->linkStatus = status;
2397
2398 /* notify the caller */
2399 complete(&pLinkContext->completion);
2400
2401 /* serialization is complete */
2402 spin_unlock(&hdd_context_lock);
2403}
2404
2405/**
2406 * wlan_hdd_get_link_status() - get link status
2407 * @pAdapter: pointer to the adapter
2408 *
2409 * This function sends a request to query the link status and waits
2410 * on a timer to invoke the callback. if the callback is invoked then
2411 * latest link status shall be returned or otherwise cached value
2412 * will be returned.
2413 *
2414 * Return: On success, link status shall be returned.
2415 * On error or not associated, link status 0 will be returned.
2416 */
2417static int wlan_hdd_get_link_status(hdd_adapter_t *adapter)
2418{
2419
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002420 hdd_station_ctx_t *pHddStaCtx =
2421 WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Houston Hoffman59c097f2016-11-09 15:50:25 -08002422 static struct statsContext context;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302423 QDF_STATUS hstatus;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002424 unsigned long rc;
2425
Prashanth Bhatta9e143052015-12-04 11:56:47 -08002426 if (cds_is_driver_recovering()) {
2427 hdd_warn("Recovery in Progress. State: 0x%x Ignore!!!",
2428 cds_get_driver_state());
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002429 return 0;
2430 }
2431
Krunal Sonibe766b02016-03-10 13:00:44 -08002432 if ((QDF_STA_MODE != adapter->device_mode) &&
2433 (QDF_P2P_CLIENT_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002434 hdd_warn("Unsupported in mode %s(%d)",
2435 hdd_device_mode_to_string(adapter->device_mode),
2436 adapter->device_mode);
2437 return 0;
2438 }
2439
2440 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
2441 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
2442 /* If not associated, then expected link status return
2443 * value is 0
2444 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002445 hdd_info("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002446 return 0;
2447 }
2448
2449 init_completion(&context.completion);
2450 context.pAdapter = adapter;
2451 context.magic = LINK_STATUS_MAGIC;
2452 hstatus = sme_get_link_status(WLAN_HDD_GET_HAL_CTX(adapter),
2453 hdd_get_link_status_cb,
2454 &context, adapter->sessionId);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302455 if (QDF_STATUS_SUCCESS != hstatus) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002456 hdd_err("Unable to retrieve link status");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002457 /* return a cached value */
2458 } else {
2459 /* request is sent -- wait for the response */
2460 rc = wait_for_completion_timeout(&context.completion,
2461 msecs_to_jiffies(WLAN_WAIT_TIME_LINK_STATUS));
2462 if (!rc)
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002463 hdd_err("SME timed out while retrieving link status");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002464 }
2465
2466 spin_lock(&hdd_context_lock);
2467 context.magic = 0;
2468 spin_unlock(&hdd_context_lock);
2469
2470 /* either callback updated adapter stats or it has cached data */
2471 return adapter->linkStatus;
2472}
2473
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002474static void hdd_tx_fail_ind_callback(uint8_t *MacAddr, uint8_t seqNo)
2475{
2476 int payload_len;
2477 struct sk_buff *skb;
2478 struct nlmsghdr *nlh;
2479 uint8_t *data;
2480
2481 payload_len = ETH_ALEN;
2482
Ryan Hsu5e2e2052016-04-28 10:19:38 -07002483 if (0 == cesium_pid || cesium_nl_srv_sock == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002484 hdd_err("cesium process not registered");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002485 return;
2486 }
2487
2488 skb = nlmsg_new(payload_len, GFP_ATOMIC);
2489 if (skb == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002490 hdd_err("nlmsg_new() failed for msg size[%d]",
2491 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002492 return;
2493 }
2494
2495 nlh = nlmsg_put(skb, cesium_pid, seqNo, 0, payload_len, NLM_F_REQUEST);
2496
2497 if (NULL == nlh) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002498 hdd_err("nlmsg_put() failed for msg size[%d]",
2499 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002500
2501 kfree_skb(skb);
2502 return;
2503 }
2504
2505 data = nlmsg_data(nlh);
2506 memcpy(data, MacAddr, ETH_ALEN);
2507
2508 if (nlmsg_unicast(cesium_nl_srv_sock, skb, cesium_pid) < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002509 hdd_err("nlmsg_unicast() failed for msg size[%d]",
2510 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002511 }
2512
2513 return;
2514}
2515
2516
2517/**
2518 * hdd_ParseuserParams - return a pointer to the next argument
2519 * @pValue: Input argument string
2520 * @ppArg: Output pointer to the next argument
2521 *
2522 * This function parses argument stream and finds the pointer
2523 * to the next argument
2524 *
2525 * Return: 0 if the next argument found; -EINVAL otherwise
2526 */
2527static int hdd_parse_user_params(uint8_t *pValue, uint8_t **ppArg)
2528{
2529 uint8_t *pVal;
2530
2531 pVal = strnchr(pValue, strlen(pValue), ' ');
2532
2533 if (NULL == pVal) {
2534 /* no argument remains */
2535 return -EINVAL;
2536 } else if (SPACE_ASCII_VALUE != *pVal) {
2537 /* no space after the current argument */
2538 return -EINVAL;
2539 }
2540
2541 pVal++;
2542
2543 /* remove empty spaces */
2544 while ((SPACE_ASCII_VALUE == *pVal) && ('\0' != *pVal)) {
2545 pVal++;
2546 }
2547
2548 /* no argument followed by spaces */
2549 if ('\0' == *pVal) {
2550 return -EINVAL;
2551 }
2552
2553 *ppArg = pVal;
2554
2555 return 0;
2556}
2557
2558/**
2559 * hdd_parse_ibsstx_fail_event_params - Parse params
2560 * for SETIBSSTXFAILEVENT
2561 * @pValue: Input ibss tx fail event argument
2562 * @tx_fail_count: (Output parameter) Tx fail counter
2563 * @pid: (Output parameter) PID
2564 *
2565 * Return: 0 if the parsing succeeds; -EINVAL otherwise
2566 */
2567static int hdd_parse_ibsstx_fail_event_params(uint8_t *pValue,
2568 uint8_t *tx_fail_count,
2569 uint16_t *pid)
2570{
2571 uint8_t *param = NULL;
2572 int ret;
2573
2574 ret = hdd_parse_user_params(pValue, &param);
2575
2576 if (0 == ret && NULL != param) {
2577 if (1 != sscanf(param, "%hhu", tx_fail_count)) {
2578 ret = -EINVAL;
2579 goto done;
2580 }
2581 } else {
2582 goto done;
2583 }
2584
2585 if (0 == *tx_fail_count) {
2586 *pid = 0;
2587 goto done;
2588 }
2589
2590 pValue = param;
2591 pValue++;
2592
2593 ret = hdd_parse_user_params(pValue, &param);
2594
2595 if (0 == ret) {
2596 if (1 != sscanf(param, "%hu", pid)) {
2597 ret = -EINVAL;
2598 goto done;
2599 }
2600 } else {
2601 goto done;
2602 }
2603
2604done:
2605 return ret;
2606}
2607
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08002608#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002609/**
2610 * hdd_parse_ese_beacon_req() - Parse ese beacon request
2611 * @pValue: Pointer to data
2612 * @pEseBcnReq: Output pointer to store parsed ie information
2613 *
2614 * This function parses the ese beacon request passed in the format
2615 * CCXBEACONREQ<space><Number of fields><space><Measurement token>
2616 * <space>Channel 1<space>Scan Mode <space>Meas Duration<space>Channel N
2617 * <space>Scan Mode N<space>Meas Duration N
2618 *
2619 * If the Number of bcn req fields (N) does not match with the
2620 * actual number of fields passed then take N.
2621 * <Meas Token><Channel><Scan Mode> and <Meas Duration> are treated
2622 * as one pair. For example, CCXBEACONREQ 2 1 1 1 30 2 44 0 40.
2623 * This function does not take care of removing duplicate channels from the
2624 * list
2625 *
2626 * Return: 0 for success non-zero for failure
2627 */
2628static int hdd_parse_ese_beacon_req(uint8_t *pValue,
2629 tCsrEseBeaconReq *pEseBcnReq)
2630{
2631 uint8_t *inPtr = pValue;
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002632 uint8_t input = 0;
2633 uint32_t tempInt = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002634 int j = 0, i = 0, v = 0;
2635 char buf[32];
2636
2637 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2638 /* no argument after the command */
2639 if (NULL == inPtr) {
2640 return -EINVAL;
2641 }
2642 /* no space after the command */
2643 else if (SPACE_ASCII_VALUE != *inPtr) {
2644 return -EINVAL;
2645 }
2646
2647 /* remove empty spaces */
2648 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2649 inPtr++;
2650
2651 /* no argument followed by spaces */
2652 if ('\0' == *inPtr)
2653 return -EINVAL;
2654
Srinivas Girigowda476deeb2016-07-19 16:21:29 -07002655 /* Getting the first argument ie Number of IE fields */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002656 v = sscanf(inPtr, "%31s ", buf);
2657 if (1 != v)
2658 return -EINVAL;
2659
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002660 v = kstrtou8(buf, 10, &input);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002661 if (v < 0)
2662 return -EINVAL;
2663
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002664 input = QDF_MIN(input, SIR_ESE_MAX_MEAS_IE_REQS);
2665 pEseBcnReq->numBcnReqIe = input;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002666
Srinivas Girigowda476deeb2016-07-19 16:21:29 -07002667 hdd_info("Number of Bcn Req Ie fields: %d", pEseBcnReq->numBcnReqIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002668
2669 for (j = 0; j < (pEseBcnReq->numBcnReqIe); j++) {
2670 for (i = 0; i < 4; i++) {
2671 /*
2672 * inPtr pointing to the beginning of 1st space
2673 * after number of ie fields
2674 */
2675 inPtr = strpbrk(inPtr, " ");
2676 /* no ie data after the number of ie fields argument */
2677 if (NULL == inPtr)
2678 return -EINVAL;
2679
2680 /* remove empty space */
2681 while ((SPACE_ASCII_VALUE == *inPtr)
2682 && ('\0' != *inPtr))
2683 inPtr++;
2684
2685 /*
2686 * no ie data after the number of ie fields
2687 * argument and spaces
2688 */
2689 if ('\0' == *inPtr)
2690 return -EINVAL;
2691
2692 v = sscanf(inPtr, "%31s ", buf);
2693 if (1 != v)
2694 return -EINVAL;
2695
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002696 v = kstrtou32(buf, 10, &tempInt);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002697 if (v < 0)
2698 return -EINVAL;
2699
2700 switch (i) {
2701 case 0: /* Measurement token */
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002702 if (!tempInt) {
2703 hdd_err("Invalid Measurement Token: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002704 tempInt);
2705 return -EINVAL;
2706 }
2707 pEseBcnReq->bcnReq[j].measurementToken =
2708 tempInt;
2709 break;
2710
2711 case 1: /* Channel number */
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002712 if (!tempInt ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002713 (tempInt >
2714 WNI_CFG_CURRENT_CHANNEL_STAMAX)) {
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002715 hdd_err("Invalid Channel Number: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002716 tempInt);
2717 return -EINVAL;
2718 }
2719 pEseBcnReq->bcnReq[j].channel = tempInt;
2720 break;
2721
2722 case 2: /* Scan mode */
2723 if ((tempInt < eSIR_PASSIVE_SCAN)
2724 || (tempInt > eSIR_BEACON_TABLE)) {
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002725 hdd_err("Invalid Scan Mode: %u Expected{0|1|2}",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002726 tempInt);
2727 return -EINVAL;
2728 }
2729 pEseBcnReq->bcnReq[j].scanMode = tempInt;
2730 break;
2731
2732 case 3: /* Measurement duration */
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002733 if ((!tempInt
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002734 && (pEseBcnReq->bcnReq[j].scanMode !=
2735 eSIR_BEACON_TABLE)) ||
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002736 (pEseBcnReq->bcnReq[j].scanMode ==
2737 eSIR_BEACON_TABLE)) {
2738 hdd_err("Invalid Measurement Duration: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002739 tempInt);
2740 return -EINVAL;
2741 }
2742 pEseBcnReq->bcnReq[j].measurementDuration =
2743 tempInt;
2744 break;
2745 }
2746 }
2747 }
2748
2749 for (j = 0; j < pEseBcnReq->numBcnReqIe; j++) {
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002750 hdd_info("Index: %d Measurement Token: %u Channel: %u Scan Mode: %u Measurement Duration: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002751 j,
2752 pEseBcnReq->bcnReq[j].measurementToken,
2753 pEseBcnReq->bcnReq[j].channel,
2754 pEseBcnReq->bcnReq[j].scanMode,
2755 pEseBcnReq->bcnReq[j].measurementDuration);
2756 }
2757
2758 return 0;
2759}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002760
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002761/**
2762 * hdd_parse_get_cckm_ie() - HDD Parse and fetch the CCKM IE
2763 * @pValue: Pointer to input data
2764 * @pCckmIe: Pointer to output cckm Ie
2765 * @pCckmIeLen: Pointer to output cckm ie length
2766 *
2767 * This function parses the SETCCKM IE command
2768 * SETCCKMIE<space><ie data>
2769 *
2770 * Return: 0 for success non-zero for failure
2771 */
2772static int hdd_parse_get_cckm_ie(uint8_t *pValue, uint8_t **pCckmIe,
2773 uint8_t *pCckmIeLen)
2774{
2775 uint8_t *inPtr = pValue;
2776 uint8_t *dataEnd;
2777 int j = 0;
2778 int i = 0;
2779 uint8_t tempByte = 0;
2780 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2781 /* no argument after the command */
2782 if (NULL == inPtr) {
2783 return -EINVAL;
2784 }
2785 /* no space after the command */
2786 else if (SPACE_ASCII_VALUE != *inPtr) {
2787 return -EINVAL;
2788 }
2789 /* remove empty spaces */
2790 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2791 inPtr++;
2792 /* no argument followed by spaces */
2793 if ('\0' == *inPtr) {
2794 return -EINVAL;
2795 }
2796 /* find the length of data */
2797 dataEnd = inPtr;
2798 while (('\0' != *dataEnd)) {
2799 dataEnd++;
2800 ++(*pCckmIeLen);
2801 }
2802 if (*pCckmIeLen <= 0)
2803 return -EINVAL;
2804 /*
2805 * Allocate the number of bytes based on the number of input characters
2806 * whether it is even or odd.
2807 * if the number of input characters are even, then we need N / 2 byte.
2808 * if the number of input characters are odd, then we need do
2809 * (N + 1) / 2 to compensate rounding off.
2810 * For example, if N = 18, then (18 + 1) / 2 = 9 bytes are enough.
2811 * If N = 19, then we need 10 bytes, hence (19 + 1) / 2 = 10 bytes
2812 */
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302813 *pCckmIe = qdf_mem_malloc((*pCckmIeLen + 1) / 2);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002814 if (NULL == *pCckmIe) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002815 hdd_err("qdf_mem_malloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002816 return -ENOMEM;
2817 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002818 /*
2819 * the buffer received from the upper layer is character buffer,
2820 * we need to prepare the buffer taking 2 characters in to a U8 hex
2821 * decimal number for example 7f0000f0...form a buffer to contain
2822 * 7f in 0th location, 00 in 1st and f0 in 3rd location
2823 */
2824 for (i = 0, j = 0; j < *pCckmIeLen; j += 2) {
2825 tempByte = (hex_to_bin(inPtr[j]) << 4) |
2826 (hex_to_bin(inPtr[j + 1]));
2827 (*pCckmIe)[i++] = tempByte;
2828 }
2829 *pCckmIeLen = i;
2830 return 0;
2831}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08002832#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002833
2834int wlan_hdd_set_mc_rate(hdd_adapter_t *pAdapter, int targetRate)
2835{
2836 tSirRateUpdateInd rateUpdate = {0};
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302837 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002838 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
2839 struct hdd_config *pConfig = NULL;
2840
2841 if (pHddCtx == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002842 hdd_err("HDD context is null");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002843 return -EINVAL;
2844 }
Krunal Sonibe766b02016-03-10 13:00:44 -08002845 if ((QDF_IBSS_MODE != pAdapter->device_mode) &&
2846 (QDF_SAP_MODE != pAdapter->device_mode) &&
2847 (QDF_STA_MODE != pAdapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002848 hdd_err("Received SETMCRATE cmd in invalid mode %s(%d)",
2849 hdd_device_mode_to_string(pAdapter->device_mode),
2850 pAdapter->device_mode);
2851 hdd_err("SETMCRATE cmd is allowed only in STA, IBSS or SOFTAP mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002852 return -EINVAL;
2853 }
2854 pConfig = pHddCtx->config;
2855 rateUpdate.nss = (pConfig->enable2x2 == 0) ? 0 : 1;
2856 rateUpdate.dev_mode = pAdapter->device_mode;
2857 rateUpdate.mcastDataRate24GHz = targetRate;
2858 rateUpdate.mcastDataRate24GHzTxFlag = 1;
2859 rateUpdate.mcastDataRate5GHz = targetRate;
2860 rateUpdate.bcastDataRate = -1;
Anurag Chouhanc5548422016-02-24 18:33:27 +05302861 qdf_copy_macaddr(&rateUpdate.bssid, &pAdapter->macAddressCurrent);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002862 hdd_info("MC Target rate %d, mac = %pM, dev_mode %s(%d)",
2863 rateUpdate.mcastDataRate24GHz, rateUpdate.bssid.bytes,
2864 hdd_device_mode_to_string(pAdapter->device_mode),
2865 pAdapter->device_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002866 status = sme_send_rate_update_ind(pHddCtx->hHal, &rateUpdate);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302867 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002868 hdd_err("SETMCRATE failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002869 return -EFAULT;
2870 }
2871 return 0;
2872}
2873
2874static int drv_cmd_p2p_dev_addr(hdd_adapter_t *adapter,
2875 hdd_context_t *hdd_ctx,
2876 uint8_t *command,
2877 uint8_t command_len,
2878 hdd_priv_data_t *priv_data)
2879{
2880 int ret = 0;
2881
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302882 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002883 TRACE_CODE_HDD_P2P_DEV_ADDR_IOCTL,
2884 adapter->sessionId,
2885 (unsigned)(*(hdd_ctx->p2pDeviceAddress.bytes + 2)
2886 << 24 | *(hdd_ctx->p2pDeviceAddress.bytes
2887 + 3) << 16 | *(hdd_ctx->
2888 p2pDeviceAddress.bytes + 4) << 8 |
2889 *(hdd_ctx->p2pDeviceAddress.bytes +
2890 5))));
2891
2892 if (copy_to_user(priv_data->buf, hdd_ctx->p2pDeviceAddress.bytes,
2893 sizeof(tSirMacAddr))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002894 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002895 ret = -EFAULT;
2896 }
2897
2898 return ret;
2899}
2900
2901/**
2902 * drv_cmd_p2p_set_noa() - Handler for P2P_SET_NOA driver command
2903 * @adapter: Adapter on which the command was received
2904 * @hdd_ctx: HDD global context
2905 * @command: Entire driver command received from userspace
2906 * @command_len: Length of @command
2907 * @priv_data: Pointer to ioctl private data structure
2908 *
2909 * This is a trivial command hander function which simply forwards the
2910 * command to the actual command processor within the P2P module.
2911 *
2912 * Return: 0 on success, non-zero on failure
2913 */
2914static int drv_cmd_p2p_set_noa(hdd_adapter_t *adapter,
2915 hdd_context_t *hdd_ctx,
2916 uint8_t *command,
2917 uint8_t command_len,
2918 hdd_priv_data_t *priv_data)
2919{
2920 return hdd_set_p2p_noa(adapter->dev, command);
2921}
2922
2923/**
2924 * drv_cmd_p2p_set_ps() - Handler for P2P_SET_PS driver command
2925 * @adapter: Adapter on which the command was received
2926 * @hdd_ctx: HDD global context
2927 * @command: Entire driver command received from userspace
2928 * @command_len: Length of @command
2929 * @priv_data: Pointer to ioctl private data structure
2930 *
2931 * This is a trivial command hander function which simply forwards the
2932 * command to the actual command processor within the P2P module.
2933 *
2934 * Return: 0 on success, non-zero on failure
2935 */
2936static int drv_cmd_p2p_set_ps(hdd_adapter_t *adapter,
2937 hdd_context_t *hdd_ctx,
2938 uint8_t *command,
2939 uint8_t command_len,
2940 hdd_priv_data_t *priv_data)
2941{
2942 return hdd_set_p2p_opps(adapter->dev, command);
2943}
2944
2945static int drv_cmd_set_band(hdd_adapter_t *adapter,
2946 hdd_context_t *hdd_ctx,
2947 uint8_t *command,
2948 uint8_t command_len,
2949 hdd_priv_data_t *priv_data)
2950{
2951 int ret = 0;
2952
2953 uint8_t *ptr = command;
2954
2955 /* Change band request received */
2956
2957 /*
2958 * First 8 bytes will have "SETBAND " and
2959 * 9 byte will have band setting value
2960 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002961 hdd_info("SetBandCommand Info comm %s UL %d, TL %d",
2962 command, priv_data->used_len,
2963 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002964
2965 /* Change band request received */
2966 ret = hdd_set_band_helper(adapter->dev, ptr);
2967
2968 return ret;
2969}
2970
2971static int drv_cmd_set_wmmps(hdd_adapter_t *adapter,
2972 hdd_context_t *hdd_ctx,
2973 uint8_t *command,
2974 uint8_t command_len,
2975 hdd_priv_data_t *priv_data)
2976{
2977 return hdd_wmmps_helper(adapter, command);
2978}
2979
2980static int drv_cmd_country(hdd_adapter_t *adapter,
2981 hdd_context_t *hdd_ctx,
2982 uint8_t *command,
2983 uint8_t command_len,
2984 hdd_priv_data_t *priv_data)
2985{
2986 int ret = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302987 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002988 unsigned long rc;
2989 char *country_code;
2990
2991 country_code = command + 8;
2992
2993 INIT_COMPLETION(adapter->change_country_code);
2994
2995 status = sme_change_country_code(hdd_ctx->hHal,
2996 wlan_hdd_change_country_code_callback,
2997 country_code,
2998 adapter,
2999 hdd_ctx->pcds_context,
3000 eSIR_TRUE,
3001 eSIR_TRUE);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303002 if (status == QDF_STATUS_SUCCESS) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003003 rc = wait_for_completion_timeout(
3004 &adapter->change_country_code,
3005 msecs_to_jiffies(WLAN_WAIT_TIME_COUNTRY));
3006 if (!rc)
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003007 hdd_err("SME while setting country code timed out");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003008 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003009 hdd_err("SME Change Country code fail, status %d",
3010 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003011 ret = -EINVAL;
3012 }
3013
3014 return ret;
3015}
3016
3017static int drv_cmd_set_roam_trigger(hdd_adapter_t *adapter,
3018 hdd_context_t *hdd_ctx,
3019 uint8_t *command,
3020 uint8_t command_len,
3021 hdd_priv_data_t *priv_data)
3022{
3023 int ret = 0;
3024 uint8_t *value = command;
3025 int8_t rssi = 0;
3026 uint8_t lookUpThreshold = CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_DEFAULT;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303027 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003028
3029 /* Move pointer to ahead of SETROAMTRIGGER<delimiter> */
3030 value = value + command_len + 1;
3031
3032 /* Convert the value from ascii to integer */
3033 ret = kstrtos8(value, 10, &rssi);
3034 if (ret < 0) {
3035 /*
3036 * If the input value is greater than max value of datatype,
3037 * then also kstrtou8 fails
3038 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003039 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
3040 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN,
3041 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003042 ret = -EINVAL;
3043 goto exit;
3044 }
3045
3046 lookUpThreshold = abs(rssi);
3047
3048 if ((lookUpThreshold < CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN)
3049 || (lookUpThreshold > CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003050 hdd_err("Neighbor lookup threshold value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003051 lookUpThreshold,
3052 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN,
3053 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX);
3054 ret = -EINVAL;
3055 goto exit;
3056 }
3057
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303058 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003059 TRACE_CODE_HDD_SETROAMTRIGGER_IOCTL,
3060 adapter->sessionId, lookUpThreshold));
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003061 hdd_info("Received Command to Set Roam trigger (Neighbor lookup threshold) = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003062 lookUpThreshold);
3063
3064 hdd_ctx->config->nNeighborLookupRssiThreshold = lookUpThreshold;
3065 status = sme_set_neighbor_lookup_rssi_threshold(hdd_ctx->hHal,
3066 adapter->sessionId,
3067 lookUpThreshold);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303068 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003069 hdd_err("Failed to set roam trigger, try again");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003070 ret = -EPERM;
3071 goto exit;
3072 }
3073
3074exit:
3075 return ret;
3076}
3077
3078static int drv_cmd_get_roam_trigger(hdd_adapter_t *adapter,
3079 hdd_context_t *hdd_ctx,
3080 uint8_t *command,
3081 uint8_t command_len,
3082 hdd_priv_data_t *priv_data)
3083{
3084 int ret = 0;
3085 uint8_t lookUpThreshold =
3086 sme_get_neighbor_lookup_rssi_threshold(hdd_ctx->hHal);
3087 int rssi = (-1) * lookUpThreshold;
3088 char extra[32];
3089 uint8_t len = 0;
3090
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303091 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003092 TRACE_CODE_HDD_GETROAMTRIGGER_IOCTL,
3093 adapter->sessionId, lookUpThreshold));
3094
3095 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303096 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003097 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003098 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003099 ret = -EFAULT;
3100 }
3101
3102 return ret;
3103}
3104
3105static int drv_cmd_set_roam_scan_period(hdd_adapter_t *adapter,
3106 hdd_context_t *hdd_ctx,
3107 uint8_t *command,
3108 uint8_t command_len,
3109 hdd_priv_data_t *priv_data)
3110{
3111 int ret = 0;
3112 uint8_t *value = command;
3113 uint8_t roamScanPeriod = 0;
3114 uint16_t neighborEmptyScanRefreshPeriod =
3115 CFG_EMPTY_SCAN_REFRESH_PERIOD_DEFAULT;
3116
3117 /* input refresh period is in terms of seconds */
3118
3119 /* Move pointer to ahead of SETROAMSCANPERIOD<delimiter> */
3120 value = value + command_len + 1;
3121
3122 /* Convert the value from ascii to integer */
3123 ret = kstrtou8(value, 10, &roamScanPeriod);
3124 if (ret < 0) {
3125 /*
3126 * If the input value is greater than max value of datatype,
3127 * then also kstrtou8 fails
3128 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003129 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
3130 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000),
3131 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003132 ret = -EINVAL;
3133 goto exit;
3134 }
3135
3136 if ((roamScanPeriod < (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000))
3137 || (roamScanPeriod > (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003138 hdd_err("Roam scan period value %d is out of range (Min: %d Max: %d)",
3139 roamScanPeriod,
3140 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000),
3141 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003142 ret = -EINVAL;
3143 goto exit;
3144 }
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303145 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003146 TRACE_CODE_HDD_SETROAMSCANPERIOD_IOCTL,
3147 adapter->sessionId, roamScanPeriod));
3148 neighborEmptyScanRefreshPeriod = roamScanPeriod * 1000;
3149
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003150 hdd_info("Received Command to Set roam scan period (Empty Scan refresh period) = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003151 roamScanPeriod);
3152
3153 hdd_ctx->config->nEmptyScanRefreshPeriod =
3154 neighborEmptyScanRefreshPeriod;
3155 sme_update_empty_scan_refresh_period(hdd_ctx->hHal,
3156 adapter->sessionId,
3157 neighborEmptyScanRefreshPeriod);
3158
3159exit:
3160 return ret;
3161}
3162
3163static int drv_cmd_get_roam_scan_period(hdd_adapter_t *adapter,
3164 hdd_context_t *hdd_ctx,
3165 uint8_t *command,
3166 uint8_t command_len,
3167 hdd_priv_data_t *priv_data)
3168{
3169 int ret = 0;
3170 uint16_t nEmptyScanRefreshPeriod =
3171 sme_get_empty_scan_refresh_period(hdd_ctx->hHal);
3172 char extra[32];
3173 uint8_t len = 0;
3174
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303175 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003176 TRACE_CODE_HDD_GETROAMSCANPERIOD_IOCTL,
3177 adapter->sessionId,
3178 nEmptyScanRefreshPeriod));
3179 len = scnprintf(extra, sizeof(extra), "%s %d",
3180 "GETROAMSCANPERIOD",
3181 (nEmptyScanRefreshPeriod / 1000));
3182 /* Returned value is in units of seconds */
Anurag Chouhan6d760662016-02-20 16:05:43 +05303183 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003184 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003185 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003186 ret = -EFAULT;
3187 }
3188
3189 return ret;
3190}
3191
3192static int drv_cmd_set_roam_scan_refresh_period(hdd_adapter_t *adapter,
3193 hdd_context_t *hdd_ctx,
3194 uint8_t *command,
3195 uint8_t command_len,
3196 hdd_priv_data_t *priv_data)
3197{
3198 int ret = 0;
3199 uint8_t *value = command;
3200 uint8_t roamScanRefreshPeriod = 0;
3201 uint16_t neighborScanRefreshPeriod =
3202 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_DEFAULT;
3203
3204 /* input refresh period is in terms of seconds */
3205 /* Move pointer to ahead of SETROAMSCANREFRESHPERIOD<delimiter> */
3206 value = value + command_len + 1;
3207
3208 /* Convert the value from ascii to integer */
3209 ret = kstrtou8(value, 10, &roamScanRefreshPeriod);
3210 if (ret < 0) {
3211 /*
3212 * If the input value is greater than max value of datatype,
3213 * then also kstrtou8 fails
3214 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003215 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
3216 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN / 1000,
3217 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX / 1000);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003218 ret = -EINVAL;
3219 goto exit;
3220 }
3221
3222 if ((roamScanRefreshPeriod <
3223 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN / 1000))
3224 || (roamScanRefreshPeriod >
3225 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX / 1000))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003226 hdd_err("Neighbor scan results refresh period value %d is out of range (Min: %d Max: %d)",
3227 roamScanRefreshPeriod,
3228 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN
3229 / 1000),
3230 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX
3231 / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003232 ret = -EINVAL;
3233 goto exit;
3234 }
3235 neighborScanRefreshPeriod = roamScanRefreshPeriod * 1000;
3236
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003237 hdd_info("Received Command to Set roam scan refresh period (Scan refresh period) = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003238 roamScanRefreshPeriod);
3239
3240 hdd_ctx->config->nNeighborResultsRefreshPeriod =
3241 neighborScanRefreshPeriod;
3242 sme_set_neighbor_scan_refresh_period(hdd_ctx->hHal,
3243 adapter->sessionId,
3244 neighborScanRefreshPeriod);
3245
3246exit:
3247 return ret;
3248}
3249
3250static int drv_cmd_get_roam_scan_refresh_period(hdd_adapter_t *adapter,
3251 hdd_context_t *hdd_ctx,
3252 uint8_t *command,
3253 uint8_t command_len,
3254 hdd_priv_data_t *priv_data)
3255{
3256 int ret = 0;
3257 uint16_t value =
3258 sme_get_neighbor_scan_refresh_period(hdd_ctx->hHal);
3259 char extra[32];
3260 uint8_t len = 0;
3261
3262 len = scnprintf(extra, sizeof(extra), "%s %d",
3263 "GETROAMSCANREFRESHPERIOD",
3264 (value / 1000));
3265 /* Returned value is in units of seconds */
Anurag Chouhan6d760662016-02-20 16:05:43 +05303266 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003267 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003268 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003269 ret = -EFAULT;
3270 }
3271
3272 return ret;
3273}
3274
3275static int drv_cmd_set_roam_mode(hdd_adapter_t *adapter,
3276 hdd_context_t *hdd_ctx,
3277 uint8_t *command,
3278 uint8_t command_len,
3279 hdd_priv_data_t *priv_data)
3280{
3281 int ret = 0;
3282 uint8_t *value = command;
3283 uint8_t roamMode = CFG_LFR_FEATURE_ENABLED_DEFAULT;
3284
Deepak Dhamdherea2785822016-11-17 01:17:45 -08003285 if (!adapter->fast_roaming_allowed) {
3286 hdd_err("Roaming is always disabled on this interface");
3287 goto exit;
3288 }
3289
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003290 /* Move pointer to ahead of SETROAMMODE<delimiter> */
3291 value = value + SIZE_OF_SETROAMMODE + 1;
3292
3293 /* Convert the value from ascii to integer */
3294 ret = kstrtou8(value, SIZE_OF_SETROAMMODE, &roamMode);
3295 if (ret < 0) {
3296 /*
3297 * If the input value is greater than max value of datatype,
3298 * then also kstrtou8 fails
3299 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003300 hdd_err("kstrtou8 failed range [%d - %d]",
3301 CFG_LFR_FEATURE_ENABLED_MIN,
3302 CFG_LFR_FEATURE_ENABLED_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003303 ret = -EINVAL;
3304 goto exit;
3305 }
3306 if ((roamMode < CFG_LFR_FEATURE_ENABLED_MIN) ||
3307 (roamMode > CFG_LFR_FEATURE_ENABLED_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003308 hdd_err("Roam Mode value %d is out of range (Min: %d Max: %d)",
3309 roamMode,
3310 CFG_LFR_FEATURE_ENABLED_MIN,
3311 CFG_LFR_FEATURE_ENABLED_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003312 ret = -EINVAL;
3313 goto exit;
3314 }
3315
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003316 hdd_debug("Received Command to Set Roam Mode = %d",
3317 roamMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003318 /*
3319 * Note that
3320 * SETROAMMODE 0 is to enable LFR while
3321 * SETROAMMODE 1 is to disable LFR, but
3322 * notify_is_fast_roam_ini_feature_enabled 0/1 is to
3323 * enable/disable. So, we have to invert the value
3324 * to call sme_update_is_fast_roam_ini_feature_enabled.
3325 */
3326 if (CFG_LFR_FEATURE_ENABLED_MIN == roamMode)
3327 roamMode = CFG_LFR_FEATURE_ENABLED_MAX; /* Roam enable */
3328 else
3329 roamMode = CFG_LFR_FEATURE_ENABLED_MIN; /* Roam disable */
3330
3331 hdd_ctx->config->isFastRoamIniFeatureEnabled = roamMode;
3332 if (roamMode) {
3333 hdd_ctx->config->isRoamOffloadScanEnabled = roamMode;
3334 sme_update_roam_scan_offload_enabled(
3335 (tHalHandle)(hdd_ctx->hHal),
3336 hdd_ctx->config->isRoamOffloadScanEnabled);
3337 sme_update_is_fast_roam_ini_feature_enabled(
3338 hdd_ctx->hHal,
3339 adapter->sessionId,
3340 roamMode);
3341 } else {
3342 sme_update_is_fast_roam_ini_feature_enabled(
3343 hdd_ctx->hHal,
3344 adapter->sessionId,
3345 roamMode);
3346 hdd_ctx->config->isRoamOffloadScanEnabled = roamMode;
3347 sme_update_roam_scan_offload_enabled(
3348 (tHalHandle)(hdd_ctx->hHal),
3349 hdd_ctx->config->isRoamOffloadScanEnabled);
3350 }
3351
3352
3353exit:
3354 return ret;
3355}
3356
3357static int drv_cmd_get_roam_mode(hdd_adapter_t *adapter,
3358 hdd_context_t *hdd_ctx,
3359 uint8_t *command,
3360 uint8_t command_len,
3361 hdd_priv_data_t *priv_data)
3362{
3363 int ret = 0;
3364 bool roamMode = sme_get_is_lfr_feature_enabled(hdd_ctx->hHal);
3365 char extra[32];
3366 uint8_t len = 0;
3367
3368 /*
3369 * roamMode value shall be inverted because the sementics is different.
3370 */
3371 if (CFG_LFR_FEATURE_ENABLED_MIN == roamMode)
3372 roamMode = CFG_LFR_FEATURE_ENABLED_MAX;
3373 else
3374 roamMode = CFG_LFR_FEATURE_ENABLED_MIN;
3375
3376 len = scnprintf(extra, sizeof(extra), "%s %d", command, roamMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303377 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003378 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003379 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003380 ret = -EFAULT;
3381 }
3382
3383 return ret;
3384}
3385
3386static int drv_cmd_set_roam_delta(hdd_adapter_t *adapter,
3387 hdd_context_t *hdd_ctx,
3388 uint8_t *command,
3389 uint8_t command_len,
3390 hdd_priv_data_t *priv_data)
3391{
3392 int ret = 0;
3393 uint8_t *value = command;
3394 uint8_t roamRssiDiff = CFG_ROAM_RSSI_DIFF_DEFAULT;
3395
3396 /* Move pointer to ahead of SETROAMDELTA<delimiter> */
3397 value = value + command_len + 1;
3398
3399 /* Convert the value from ascii to integer */
3400 ret = kstrtou8(value, 10, &roamRssiDiff);
3401 if (ret < 0) {
3402 /*
3403 * If the input value is greater than max value of datatype,
3404 * then also kstrtou8 fails
3405 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003406 hdd_err("kstrtou8 failed range [%d - %d]",
3407 CFG_ROAM_RSSI_DIFF_MIN,
3408 CFG_ROAM_RSSI_DIFF_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003409 ret = -EINVAL;
3410 goto exit;
3411 }
3412
3413 if ((roamRssiDiff < CFG_ROAM_RSSI_DIFF_MIN) ||
3414 (roamRssiDiff > CFG_ROAM_RSSI_DIFF_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003415 hdd_err("Roam rssi diff value %d is out of range (Min: %d Max: %d)",
3416 roamRssiDiff,
3417 CFG_ROAM_RSSI_DIFF_MIN,
3418 CFG_ROAM_RSSI_DIFF_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003419 ret = -EINVAL;
3420 goto exit;
3421 }
3422
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003423 hdd_info("Received Command to Set roam rssi diff = %d",
3424 roamRssiDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003425
3426 hdd_ctx->config->RoamRssiDiff = roamRssiDiff;
3427 sme_update_roam_rssi_diff(hdd_ctx->hHal,
3428 adapter->sessionId,
3429 roamRssiDiff);
3430
3431exit:
3432 return ret;
3433}
3434
3435static int drv_cmd_get_roam_delta(hdd_adapter_t *adapter,
3436 hdd_context_t *hdd_ctx,
3437 uint8_t *command,
3438 uint8_t command_len,
3439 hdd_priv_data_t *priv_data)
3440{
3441 int ret = 0;
3442 uint8_t roamRssiDiff =
3443 sme_get_roam_rssi_diff(hdd_ctx->hHal);
3444 char extra[32];
3445 uint8_t len = 0;
3446
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303447 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003448 TRACE_CODE_HDD_GETROAMDELTA_IOCTL,
3449 adapter->sessionId, roamRssiDiff));
3450
3451 len = scnprintf(extra, sizeof(extra), "%s %d",
3452 command, roamRssiDiff);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303453 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003454
3455 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003456 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003457 ret = -EFAULT;
3458 }
3459
3460 return ret;
3461}
3462
3463static int drv_cmd_get_band(hdd_adapter_t *adapter,
3464 hdd_context_t *hdd_ctx,
3465 uint8_t *command,
3466 uint8_t command_len,
3467 hdd_priv_data_t *priv_data)
3468{
3469 int ret = 0;
3470 int band = -1;
3471 char extra[32];
3472 uint8_t len = 0;
3473
3474 hdd_get_band_helper(hdd_ctx, &band);
3475
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303476 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003477 TRACE_CODE_HDD_GETBAND_IOCTL,
3478 adapter->sessionId, band));
3479
3480 len = scnprintf(extra, sizeof(extra), "%s %d", command, band);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303481 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003482
3483 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003484 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003485 ret = -EFAULT;
3486 }
3487
3488 return ret;
3489}
3490
3491static int drv_cmd_set_roam_scan_channels(hdd_adapter_t *adapter,
3492 hdd_context_t *hdd_ctx,
3493 uint8_t *command,
3494 uint8_t command_len,
3495 hdd_priv_data_t *priv_data)
3496{
3497 return hdd_parse_set_roam_scan_channels(adapter, command);
3498}
3499
3500static int drv_cmd_get_roam_scan_channels(hdd_adapter_t *adapter,
3501 hdd_context_t *hdd_ctx,
3502 uint8_t *command,
3503 uint8_t command_len,
3504 hdd_priv_data_t *priv_data)
3505{
3506 int ret = 0;
3507 uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
3508 uint8_t numChannels = 0;
3509 uint8_t j = 0;
3510 char extra[128] = { 0 };
3511 int len;
3512
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303513 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003514 sme_get_roam_scan_channel_list(hdd_ctx->hHal,
3515 ChannelList,
3516 &numChannels,
3517 adapter->sessionId)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003518 hdd_alert("failed to get roam scan channel list");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003519 ret = -EFAULT;
3520 goto exit;
3521 }
3522
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303523 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003524 TRACE_CODE_HDD_GETROAMSCANCHANNELS_IOCTL,
3525 adapter->sessionId, numChannels));
3526 /*
3527 * output channel list is of the format
3528 * [Number of roam scan channels][Channel1][Channel2]...
3529 * copy the number of channels in the 0th index
3530 */
3531 len = scnprintf(extra, sizeof(extra), "%s %d", command,
3532 numChannels);
Selvaraj, Sridhar5cc4af42016-10-19 10:41:59 +05303533 for (j = 0; (j < numChannels) && len <= sizeof(extra); j++)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003534 len += scnprintf(extra + len, sizeof(extra) - len,
3535 " %d", ChannelList[j]);
3536
Anurag Chouhan6d760662016-02-20 16:05:43 +05303537 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003538 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003539 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003540 ret = -EFAULT;
3541 goto exit;
3542 }
3543
3544exit:
3545 return ret;
3546}
3547
3548static int drv_cmd_get_ccx_mode(hdd_adapter_t *adapter,
3549 hdd_context_t *hdd_ctx,
3550 uint8_t *command,
3551 uint8_t command_len,
3552 hdd_priv_data_t *priv_data)
3553{
3554 int ret = 0;
3555 bool eseMode = sme_get_is_ese_feature_enabled(hdd_ctx->hHal);
3556 char extra[32];
3557 uint8_t len = 0;
3558
3559 /*
3560 * Check if the features OKC/ESE/11R are supported simultaneously,
3561 * then this operation is not permitted (return FAILURE)
3562 */
3563 if (eseMode &&
3564 hdd_is_okc_mode_enabled(hdd_ctx) &&
3565 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003566 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003567 ret = -EPERM;
3568 goto exit;
3569 }
3570
3571 len = scnprintf(extra, sizeof(extra), "%s %d",
3572 "GETCCXMODE", eseMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303573 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003574 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003575 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003576 ret = -EFAULT;
3577 goto exit;
3578 }
3579
3580exit:
3581 return ret;
3582}
3583
3584static int drv_cmd_get_okc_mode(hdd_adapter_t *adapter,
3585 hdd_context_t *hdd_ctx,
3586 uint8_t *command,
3587 uint8_t command_len,
3588 hdd_priv_data_t *priv_data)
3589{
3590 int ret = 0;
3591 bool okcMode = hdd_is_okc_mode_enabled(hdd_ctx);
3592 char extra[32];
3593 uint8_t len = 0;
3594
3595 /*
3596 * Check if the features OKC/ESE/11R are supported simultaneously,
3597 * then this operation is not permitted (return FAILURE)
3598 */
3599 if (okcMode &&
3600 sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
3601 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003602 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003603 ret = -EPERM;
3604 goto exit;
3605 }
3606
3607 len = scnprintf(extra, sizeof(extra), "%s %d",
3608 "GETOKCMODE", okcMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303609 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003610
3611 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003612 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003613 ret = -EFAULT;
3614 goto exit;
3615 }
3616
3617exit:
3618 return ret;
3619}
3620
3621static int drv_cmd_get_fast_roam(hdd_adapter_t *adapter,
3622 hdd_context_t *hdd_ctx,
3623 uint8_t *command,
3624 uint8_t command_len,
3625 hdd_priv_data_t *priv_data)
3626{
3627 int ret = 0;
3628 bool lfrMode = sme_get_is_lfr_feature_enabled(hdd_ctx->hHal);
3629 char extra[32];
3630 uint8_t len = 0;
3631
3632 len = scnprintf(extra, sizeof(extra), "%s %d",
3633 "GETFASTROAM", lfrMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303634 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003635
3636 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003637 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003638 ret = -EFAULT;
3639 }
3640
3641 return ret;
3642}
3643
3644static int drv_cmd_get_fast_transition(hdd_adapter_t *adapter,
3645 hdd_context_t *hdd_ctx,
3646 uint8_t *command,
3647 uint8_t command_len,
3648 hdd_priv_data_t *priv_data)
3649{
3650 int ret = 0;
3651 bool ft = sme_get_is_ft_feature_enabled(hdd_ctx->hHal);
3652 char extra[32];
3653 uint8_t len = 0;
3654
3655 len = scnprintf(extra, sizeof(extra), "%s %d",
3656 "GETFASTTRANSITION", ft);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303657 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003658
3659 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003660 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003661 ret = -EFAULT;
3662 }
3663
3664 return ret;
3665}
3666
3667static int drv_cmd_set_roam_scan_channel_min_time(hdd_adapter_t *adapter,
3668 hdd_context_t *hdd_ctx,
3669 uint8_t *command,
3670 uint8_t command_len,
3671 hdd_priv_data_t *priv_data)
3672{
3673 int ret = 0;
3674 uint8_t *value = command;
3675 uint8_t minTime = CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_DEFAULT;
3676
3677 /* Move pointer to ahead of SETROAMSCANCHANNELMINTIME<delimiter> */
3678 value = value + command_len + 1;
3679
3680 /* Convert the value from ascii to integer */
3681 ret = kstrtou8(value, 10, &minTime);
3682 if (ret < 0) {
3683 /*
3684 * If the input value is greater than max value of datatype,
3685 * then also kstrtou8 fails
3686 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003687 hdd_err("kstrtou8 failed range [%d - %d]",
3688 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN,
3689 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003690 ret = -EINVAL;
3691 goto exit;
3692 }
3693
3694 if ((minTime < CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN) ||
3695 (minTime > CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003696 hdd_err("scan min channel time value %d is out of range (Min: %d Max: %d)",
3697 minTime,
3698 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN,
3699 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003700 ret = -EINVAL;
3701 goto exit;
3702 }
3703
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303704 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003705 TRACE_CODE_HDD_SETROAMSCANCHANNELMINTIME_IOCTL,
3706 adapter->sessionId, minTime));
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003707 hdd_info("Received Command to change channel min time = %d",
3708 minTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003709
3710 hdd_ctx->config->nNeighborScanMinChanTime = minTime;
3711 sme_set_neighbor_scan_min_chan_time(hdd_ctx->hHal,
3712 minTime,
3713 adapter->sessionId);
3714
3715exit:
3716 return ret;
3717}
3718
3719static int drv_cmd_send_action_frame(hdd_adapter_t *adapter,
3720 hdd_context_t *hdd_ctx,
3721 uint8_t *command,
3722 uint8_t command_len,
3723 hdd_priv_data_t *priv_data)
3724{
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07003725 return hdd_parse_sendactionframe(adapter, command,
3726 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003727}
3728
3729static int drv_cmd_get_roam_scan_channel_min_time(hdd_adapter_t *adapter,
3730 hdd_context_t *hdd_ctx,
3731 uint8_t *command,
3732 uint8_t command_len,
3733 hdd_priv_data_t *priv_data)
3734{
3735 int ret = 0;
3736 uint16_t val = sme_get_neighbor_scan_min_chan_time(hdd_ctx->hHal,
3737 adapter->sessionId);
3738 char extra[32];
3739 uint8_t len = 0;
3740
3741 /* value is interms of msec */
3742 len = scnprintf(extra, sizeof(extra), "%s %d",
3743 "GETROAMSCANCHANNELMINTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303744 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003745
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303746 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003747 TRACE_CODE_HDD_GETROAMSCANCHANNELMINTIME_IOCTL,
3748 adapter->sessionId, val));
3749
3750 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003751 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003752 ret = -EFAULT;
3753 }
3754
3755 return ret;
3756}
3757
3758static int drv_cmd_set_scan_channel_time(hdd_adapter_t *adapter,
3759 hdd_context_t *hdd_ctx,
3760 uint8_t *command,
3761 uint8_t command_len,
3762 hdd_priv_data_t *priv_data)
3763{
3764 int ret = 0;
3765 uint8_t *value = command;
3766 uint16_t maxTime = CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_DEFAULT;
3767
3768 /* Move pointer to ahead of SETSCANCHANNELTIME<delimiter> */
3769 value = value + command_len + 1;
3770
3771 /* Convert the value from ascii to integer */
3772 ret = kstrtou16(value, 10, &maxTime);
3773 if (ret < 0) {
3774 /*
3775 * If the input value is greater than max value of datatype,
3776 * then also kstrtou8 fails
3777 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003778 hdd_err("kstrtou16 failed range [%d - %d]",
3779 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN,
3780 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003781 ret = -EINVAL;
3782 goto exit;
3783 }
3784
3785 if ((maxTime < CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN) ||
3786 (maxTime > CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003787 hdd_err("lfr mode value %d is out of range (Min: %d Max: %d)",
3788 maxTime,
3789 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN,
3790 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003791 ret = -EINVAL;
3792 goto exit;
3793 }
3794
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003795 hdd_info("Received Command to change channel max time = %d",
3796 maxTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003797
3798 hdd_ctx->config->nNeighborScanMaxChanTime = maxTime;
3799 sme_set_neighbor_scan_max_chan_time(hdd_ctx->hHal,
3800 adapter->sessionId,
3801 maxTime);
3802
3803exit:
3804 return ret;
3805}
3806
3807static int drv_cmd_get_scan_channel_time(hdd_adapter_t *adapter,
3808 hdd_context_t *hdd_ctx,
3809 uint8_t *command,
3810 uint8_t command_len,
3811 hdd_priv_data_t *priv_data)
3812{
3813 int ret = 0;
3814 uint16_t val = sme_get_neighbor_scan_max_chan_time(hdd_ctx->hHal,
3815 adapter->sessionId);
3816 char extra[32];
3817 uint8_t len = 0;
3818
3819 /* value is interms of msec */
3820 len = scnprintf(extra, sizeof(extra), "%s %d",
3821 "GETSCANCHANNELTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303822 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003823
3824 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003825 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003826 ret = -EFAULT;
3827 }
3828
3829 return ret;
3830}
3831
3832static int drv_cmd_set_scan_home_time(hdd_adapter_t *adapter,
3833 hdd_context_t *hdd_ctx,
3834 uint8_t *command,
3835 uint8_t command_len,
3836 hdd_priv_data_t *priv_data)
3837{
3838 int ret = 0;
3839 uint8_t *value = command;
3840 uint16_t val = CFG_NEIGHBOR_SCAN_TIMER_PERIOD_DEFAULT;
3841
3842 /* Move pointer to ahead of SETSCANHOMETIME<delimiter> */
3843 value = value + command_len + 1;
3844
3845 /* Convert the value from ascii to integer */
3846 ret = kstrtou16(value, 10, &val);
3847 if (ret < 0) {
3848 /*
3849 * If the input value is greater than max value of datatype,
3850 * then also kstrtou8 fails
3851 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003852 hdd_err("kstrtou16 failed range [%d - %d]",
3853 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN,
3854 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003855 ret = -EINVAL;
3856 goto exit;
3857 }
3858
3859 if ((val < CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN) ||
3860 (val > CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003861 hdd_err("scan home time value %d is out of range (Min: %d Max: %d)",
3862 val,
3863 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN,
3864 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003865 ret = -EINVAL;
3866 goto exit;
3867 }
3868
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003869 hdd_info("Received Command to change scan home time = %d",
3870 val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003871
3872 hdd_ctx->config->nNeighborScanPeriod = val;
3873 sme_set_neighbor_scan_period(hdd_ctx->hHal,
3874 adapter->sessionId, val);
3875
3876exit:
3877 return ret;
3878}
3879
3880static int drv_cmd_get_scan_home_time(hdd_adapter_t *adapter,
3881 hdd_context_t *hdd_ctx,
3882 uint8_t *command,
3883 uint8_t command_len,
3884 hdd_priv_data_t *priv_data)
3885{
3886 int ret = 0;
3887 uint16_t val = sme_get_neighbor_scan_period(hdd_ctx->hHal,
3888 adapter->
3889 sessionId);
3890 char extra[32];
3891 uint8_t len = 0;
3892
3893 /* value is interms of msec */
3894 len = scnprintf(extra, sizeof(extra), "%s %d",
3895 "GETSCANHOMETIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303896 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003897
3898 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003899 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003900 ret = -EFAULT;
3901 }
3902
3903 return ret;
3904}
3905
3906static int drv_cmd_set_roam_intra_band(hdd_adapter_t *adapter,
3907 hdd_context_t *hdd_ctx,
3908 uint8_t *command,
3909 uint8_t command_len,
3910 hdd_priv_data_t *priv_data)
3911{
3912 int ret = 0;
3913 uint8_t *value = command;
3914 uint8_t val = CFG_ROAM_INTRA_BAND_DEFAULT;
3915
3916 /* Move pointer to ahead of SETROAMINTRABAND<delimiter> */
3917 value = value + command_len + 1;
3918
3919 /* Convert the value from ascii to integer */
3920 ret = kstrtou8(value, 10, &val);
3921 if (ret < 0) {
3922 /*
3923 * If the input value is greater than max value of datatype,
3924 * then also kstrtou8 fails
3925 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003926 hdd_err("kstrtou8 failed range [%d - %d]",
3927 CFG_ROAM_INTRA_BAND_MIN,
3928 CFG_ROAM_INTRA_BAND_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003929 ret = -EINVAL;
3930 goto exit;
3931 }
3932
3933 if ((val < CFG_ROAM_INTRA_BAND_MIN) ||
3934 (val > CFG_ROAM_INTRA_BAND_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003935 hdd_err("intra band mode value %d is out of range (Min: %d Max: %d)",
3936 val,
3937 CFG_ROAM_INTRA_BAND_MIN,
3938 CFG_ROAM_INTRA_BAND_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003939 ret = -EINVAL;
3940 goto exit;
3941 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003942 hdd_info("Received Command to change intra band = %d",
3943 val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003944
3945 hdd_ctx->config->nRoamIntraBand = val;
3946 sme_set_roam_intra_band(hdd_ctx->hHal, val);
3947
3948exit:
3949 return ret;
3950}
3951
3952static int drv_cmd_get_roam_intra_band(hdd_adapter_t *adapter,
3953 hdd_context_t *hdd_ctx,
3954 uint8_t *command,
3955 uint8_t command_len,
3956 hdd_priv_data_t *priv_data)
3957{
3958 int ret = 0;
3959 uint16_t val = sme_get_roam_intra_band(hdd_ctx->hHal);
3960 char extra[32];
3961 uint8_t len = 0;
3962
3963 /* value is interms of msec */
3964 len = scnprintf(extra, sizeof(extra), "%s %d",
3965 "GETROAMINTRABAND", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303966 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003967 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003968 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003969 ret = -EFAULT;
3970 }
3971
3972 return ret;
3973}
3974
3975static int drv_cmd_set_scan_n_probes(hdd_adapter_t *adapter,
3976 hdd_context_t *hdd_ctx,
3977 uint8_t *command,
3978 uint8_t command_len,
3979 hdd_priv_data_t *priv_data)
3980{
3981 int ret = 0;
3982 uint8_t *value = command;
3983 uint8_t nProbes = CFG_ROAM_SCAN_N_PROBES_DEFAULT;
3984
3985 /* Move pointer to ahead of SETSCANNPROBES<delimiter> */
3986 value = value + command_len + 1;
3987
3988 /* Convert the value from ascii to integer */
3989 ret = kstrtou8(value, 10, &nProbes);
3990 if (ret < 0) {
3991 /*
3992 * If the input value is greater than max value of datatype,
3993 * then also kstrtou8 fails
3994 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003995 hdd_err("kstrtou8 failed range [%d - %d]",
3996 CFG_ROAM_SCAN_N_PROBES_MIN,
3997 CFG_ROAM_SCAN_N_PROBES_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003998 ret = -EINVAL;
3999 goto exit;
4000 }
4001
4002 if ((nProbes < CFG_ROAM_SCAN_N_PROBES_MIN) ||
4003 (nProbes > CFG_ROAM_SCAN_N_PROBES_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004004 hdd_err("NProbes value %d is out of range (Min: %d Max: %d)",
4005 nProbes,
4006 CFG_ROAM_SCAN_N_PROBES_MIN,
4007 CFG_ROAM_SCAN_N_PROBES_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004008 ret = -EINVAL;
4009 goto exit;
4010 }
4011
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004012 hdd_info("Received Command to Set nProbes = %d",
4013 nProbes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004014
4015 hdd_ctx->config->nProbes = nProbes;
4016 sme_update_roam_scan_n_probes(hdd_ctx->hHal,
4017 adapter->sessionId, nProbes);
4018
4019exit:
4020 return ret;
4021}
4022
4023static int drv_cmd_get_scan_n_probes(hdd_adapter_t *adapter,
4024 hdd_context_t *hdd_ctx,
4025 uint8_t *command,
4026 uint8_t command_len,
4027 hdd_priv_data_t *priv_data)
4028{
4029 int ret = 0;
4030 uint8_t val = sme_get_roam_scan_n_probes(hdd_ctx->hHal);
4031 char extra[32];
4032 uint8_t len = 0;
4033
4034 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304035 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004036 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004037 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004038 ret = -EFAULT;
4039 }
4040
4041 return ret;
4042}
4043
4044static int drv_cmd_set_scan_home_away_time(hdd_adapter_t *adapter,
4045 hdd_context_t *hdd_ctx,
4046 uint8_t *command,
4047 uint8_t command_len,
4048 hdd_priv_data_t *priv_data)
4049{
4050 int ret = 0;
4051 uint8_t *value = command;
4052 uint16_t homeAwayTime = CFG_ROAM_SCAN_HOME_AWAY_TIME_DEFAULT;
4053
4054 /* input value is in units of msec */
4055
4056 /* Move pointer to ahead of SETSCANHOMEAWAYTIME<delimiter> */
4057 value = value + command_len + 1;
4058
4059 /* Convert the value from ascii to integer */
4060 ret = kstrtou16(value, 10, &homeAwayTime);
4061 if (ret < 0) {
4062 /*
4063 * If the input value is greater than max value of datatype,
4064 * then also kstrtou8 fails
4065 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004066 hdd_err("kstrtou8 failed range [%d - %d]",
4067 CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN,
4068 CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004069 ret = -EINVAL;
4070 goto exit;
4071 }
4072
4073 if ((homeAwayTime < CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN) ||
4074 (homeAwayTime > CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004075 hdd_err("homeAwayTime value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004076 homeAwayTime,
4077 CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN,
4078 CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX);
4079 ret = -EINVAL;
4080 goto exit;
4081 }
4082
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004083 hdd_info("Received Command to Set scan away time = %d",
4084 homeAwayTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004085
4086 if (hdd_ctx->config->nRoamScanHomeAwayTime !=
4087 homeAwayTime) {
4088 hdd_ctx->config->nRoamScanHomeAwayTime = homeAwayTime;
4089 sme_update_roam_scan_home_away_time(hdd_ctx->hHal,
4090 adapter->sessionId,
4091 homeAwayTime,
4092 true);
4093 }
4094
4095exit:
4096 return ret;
4097}
4098
4099static int drv_cmd_get_scan_home_away_time(hdd_adapter_t *adapter,
4100 hdd_context_t *hdd_ctx,
4101 uint8_t *command,
4102 uint8_t command_len,
4103 hdd_priv_data_t *priv_data)
4104{
4105 int ret = 0;
4106 uint16_t val = sme_get_roam_scan_home_away_time(hdd_ctx->hHal);
4107 char extra[32];
4108 uint8_t len = 0;
4109
4110 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304111 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004112
4113 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004114 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004115 ret = -EFAULT;
4116 }
4117
4118 return ret;
4119}
4120
4121static int drv_cmd_reassoc(hdd_adapter_t *adapter,
4122 hdd_context_t *hdd_ctx,
4123 uint8_t *command,
4124 uint8_t command_len,
4125 hdd_priv_data_t *priv_data)
4126{
4127 return hdd_parse_reassoc(adapter, command);
4128}
4129
4130static int drv_cmd_set_wes_mode(hdd_adapter_t *adapter,
4131 hdd_context_t *hdd_ctx,
4132 uint8_t *command,
4133 uint8_t command_len,
4134 hdd_priv_data_t *priv_data)
4135{
4136 int ret = 0;
4137 uint8_t *value = command;
4138 uint8_t wesMode = CFG_ENABLE_WES_MODE_NAME_DEFAULT;
4139
4140 /* Move pointer to ahead of SETWESMODE<delimiter> */
4141 value = value + command_len + 1;
4142
4143 /* Convert the value from ascii to integer */
4144 ret = kstrtou8(value, 10, &wesMode);
4145 if (ret < 0) {
4146 /*
4147 * If the input value is greater than max value of datatype,
4148 * then also kstrtou8 fails
4149 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004150 hdd_err("kstrtou8 failed range [%d - %d]",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004151 CFG_ENABLE_WES_MODE_NAME_MIN,
4152 CFG_ENABLE_WES_MODE_NAME_MAX);
4153 ret = -EINVAL;
4154 goto exit;
4155 }
4156
4157 if ((wesMode < CFG_ENABLE_WES_MODE_NAME_MIN) ||
4158 (wesMode > CFG_ENABLE_WES_MODE_NAME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004159 hdd_err("WES Mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004160 wesMode,
4161 CFG_ENABLE_WES_MODE_NAME_MIN,
4162 CFG_ENABLE_WES_MODE_NAME_MAX);
4163 ret = -EINVAL;
4164 goto exit;
4165 }
4166
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004167 hdd_info("Received Command to Set WES Mode rssi diff = %d",
4168 wesMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004169
4170 hdd_ctx->config->isWESModeEnabled = wesMode;
4171 sme_update_wes_mode(hdd_ctx->hHal, wesMode, adapter->sessionId);
4172
4173exit:
4174 return ret;
4175}
4176
4177static int drv_cmd_get_wes_mode(hdd_adapter_t *adapter,
4178 hdd_context_t *hdd_ctx,
4179 uint8_t *command,
4180 uint8_t command_len,
4181 hdd_priv_data_t *priv_data)
4182{
4183 int ret = 0;
4184 bool wesMode = sme_get_wes_mode(hdd_ctx->hHal);
4185 char extra[32];
4186 uint8_t len = 0;
4187
4188 len = scnprintf(extra, sizeof(extra), "%s %d", command, wesMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304189 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004190 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004191 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004192 ret = -EFAULT;
4193 }
4194
4195 return ret;
4196}
4197
4198static int drv_cmd_set_opportunistic_rssi_diff(hdd_adapter_t *adapter,
4199 hdd_context_t *hdd_ctx,
4200 uint8_t *command,
4201 uint8_t command_len,
4202 hdd_priv_data_t *priv_data)
4203{
4204 int ret = 0;
4205 uint8_t *value = command;
4206 uint8_t nOpportunisticThresholdDiff =
4207 CFG_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF_DEFAULT;
4208
4209 /* Move pointer to ahead of SETOPPORTUNISTICRSSIDIFF<delimiter> */
4210 value = value + command_len + 1;
4211
4212 /* Convert the value from ascii to integer */
4213 ret = kstrtou8(value, 10, &nOpportunisticThresholdDiff);
4214 if (ret < 0) {
4215 /*
4216 * If the input value is greater than max value of datatype,
4217 * then also kstrtou8 fails
4218 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004219 hdd_err("kstrtou8 failed.");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004220 ret = -EINVAL;
4221 goto exit;
4222 }
4223
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004224 hdd_info("Received Command to Set Opportunistic Threshold diff = %d",
4225 nOpportunisticThresholdDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004226
4227 sme_set_roam_opportunistic_scan_threshold_diff(hdd_ctx->hHal,
4228 adapter->sessionId,
4229 nOpportunisticThresholdDiff);
4230
4231exit:
4232 return ret;
4233}
4234
4235static int drv_cmd_get_opportunistic_rssi_diff(hdd_adapter_t *adapter,
4236 hdd_context_t *hdd_ctx,
4237 uint8_t *command,
4238 uint8_t command_len,
4239 hdd_priv_data_t *priv_data)
4240{
4241 int ret = 0;
4242 int8_t val = sme_get_roam_opportunistic_scan_threshold_diff(
4243 hdd_ctx->hHal);
4244 char extra[32];
4245 uint8_t len = 0;
4246
4247 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304248 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004249 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004250 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004251 ret = -EFAULT;
4252 }
4253
4254 return ret;
4255}
4256
4257static int drv_cmd_set_roam_rescan_rssi_diff(hdd_adapter_t *adapter,
4258 hdd_context_t *hdd_ctx,
4259 uint8_t *command,
4260 uint8_t command_len,
4261 hdd_priv_data_t *priv_data)
4262{
4263 int ret = 0;
4264 uint8_t *value = command;
4265 uint8_t nRoamRescanRssiDiff = CFG_ROAM_RESCAN_RSSI_DIFF_DEFAULT;
4266
4267 /* Move pointer to ahead of SETROAMRESCANRSSIDIFF<delimiter> */
4268 value = value + command_len + 1;
4269
4270 /* Convert the value from ascii to integer */
4271 ret = kstrtou8(value, 10, &nRoamRescanRssiDiff);
4272 if (ret < 0) {
4273 /*
4274 * If the input value is greater than max value of datatype,
4275 * then also kstrtou8 fails
4276 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004277 hdd_err("kstrtou8 failed.");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004278 ret = -EINVAL;
4279 goto exit;
4280 }
4281
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004282 hdd_info("Received Command to Set Roam Rescan RSSI Diff = %d",
4283 nRoamRescanRssiDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004284
4285 sme_set_roam_rescan_rssi_diff(hdd_ctx->hHal,
4286 adapter->sessionId,
4287 nRoamRescanRssiDiff);
4288
4289exit:
4290 return ret;
4291}
4292
4293static int drv_cmd_get_roam_rescan_rssi_diff(hdd_adapter_t *adapter,
4294 hdd_context_t *hdd_ctx,
4295 uint8_t *command,
4296 uint8_t command_len,
4297 hdd_priv_data_t *priv_data)
4298{
4299 int ret = 0;
4300 uint8_t val = sme_get_roam_rescan_rssi_diff(hdd_ctx->hHal);
4301 char extra[32];
4302 uint8_t len = 0;
4303
4304 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304305 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004306 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004307 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004308 ret = -EFAULT;
4309 }
4310
4311 return ret;
4312}
4313
4314static int drv_cmd_set_fast_roam(hdd_adapter_t *adapter,
4315 hdd_context_t *hdd_ctx,
4316 uint8_t *command,
4317 uint8_t command_len,
4318 hdd_priv_data_t *priv_data)
4319{
4320 int ret = 0;
4321 uint8_t *value = command;
4322 uint8_t lfrMode = CFG_LFR_FEATURE_ENABLED_DEFAULT;
4323
Deepak Dhamdherea2785822016-11-17 01:17:45 -08004324 if (!adapter->fast_roaming_allowed) {
4325 hdd_err("Roaming is always disabled on this interface");
4326 goto exit;
4327 }
4328
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004329 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4330 value = value + command_len + 1;
4331
4332 /* Convert the value from ascii to integer */
4333 ret = kstrtou8(value, 10, &lfrMode);
4334 if (ret < 0) {
4335 /*
4336 * If the input value is greater than max value of datatype,
4337 * then also kstrtou8 fails
4338 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004339 hdd_err("kstrtou8 failed range [%d - %d]",
4340 CFG_LFR_FEATURE_ENABLED_MIN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004341 CFG_LFR_FEATURE_ENABLED_MAX);
4342 ret = -EINVAL;
4343 goto exit;
4344 }
4345
4346 if ((lfrMode < CFG_LFR_FEATURE_ENABLED_MIN) ||
4347 (lfrMode > CFG_LFR_FEATURE_ENABLED_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004348 hdd_err("lfr mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004349 lfrMode,
4350 CFG_LFR_FEATURE_ENABLED_MIN,
4351 CFG_LFR_FEATURE_ENABLED_MAX);
4352 ret = -EINVAL;
4353 goto exit;
4354 }
4355
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004356 hdd_info("Received Command to change lfr mode = %d",
4357 lfrMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004358
4359 hdd_ctx->config->isFastRoamIniFeatureEnabled = lfrMode;
4360 sme_update_is_fast_roam_ini_feature_enabled(hdd_ctx->hHal,
4361 adapter->
4362 sessionId,
4363 lfrMode);
4364
4365exit:
4366 return ret;
4367}
4368
4369static int drv_cmd_set_fast_transition(hdd_adapter_t *adapter,
4370 hdd_context_t *hdd_ctx,
4371 uint8_t *command,
4372 uint8_t command_len,
4373 hdd_priv_data_t *priv_data)
4374{
4375 int ret = 0;
4376 uint8_t *value = command;
4377 uint8_t ft = CFG_FAST_TRANSITION_ENABLED_NAME_DEFAULT;
4378
4379 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4380 value = value + command_len + 1;
4381
4382 /* Convert the value from ascii to integer */
4383 ret = kstrtou8(value, 10, &ft);
4384 if (ret < 0) {
4385 /*
4386 * If the input value is greater than max value of datatype,
4387 * then also kstrtou8 fails
4388 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004389 hdd_err("kstrtou8 failed range [%d - %d]",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004390 CFG_FAST_TRANSITION_ENABLED_NAME_MIN,
4391 CFG_FAST_TRANSITION_ENABLED_NAME_MAX);
4392 ret = -EINVAL;
4393 goto exit;
4394 }
4395
4396 if ((ft < CFG_FAST_TRANSITION_ENABLED_NAME_MIN) ||
4397 (ft > CFG_FAST_TRANSITION_ENABLED_NAME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004398 hdd_err("ft mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004399 ft,
4400 CFG_FAST_TRANSITION_ENABLED_NAME_MIN,
4401 CFG_FAST_TRANSITION_ENABLED_NAME_MAX);
4402 ret = -EINVAL;
4403 goto exit;
4404 }
4405
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004406 hdd_info("Received Command to change ft mode = %d", ft);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004407
4408 hdd_ctx->config->isFastTransitionEnabled = ft;
4409 sme_update_fast_transition_enabled(hdd_ctx->hHal, ft);
4410
4411exit:
4412 return ret;
4413}
4414
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004415static int drv_cmd_fast_reassoc(hdd_adapter_t *adapter,
4416 hdd_context_t *hdd_ctx,
4417 uint8_t *command,
4418 uint8_t command_len,
4419 hdd_priv_data_t *priv_data)
4420{
4421 int ret = 0;
4422 uint8_t *value = command;
4423 uint8_t channel = 0;
4424 tSirMacAddr targetApBssid;
4425 uint32_t roamId = 0;
4426 tCsrRoamModifyProfileFields modProfileFields;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004427 tCsrHandoffRequest handoffInfo;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004428 hdd_station_ctx_t *pHddStaCtx;
4429
Krunal Sonibe766b02016-03-10 13:00:44 -08004430 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004431 hdd_warn("Unsupported in mode %s(%d)",
4432 hdd_device_mode_to_string(adapter->device_mode),
4433 adapter->device_mode);
4434 return -EINVAL;
4435 }
4436
4437 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
4438
4439 /* if not associated, no need to proceed with reassoc */
4440 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004441 hdd_info("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004442 ret = -EINVAL;
4443 goto exit;
4444 }
4445
4446 ret = hdd_parse_reassoc_command_v1_data(value, targetApBssid,
4447 &channel);
4448 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004449 hdd_err("Failed to parse reassoc command data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004450 goto exit;
4451 }
4452
4453 /*
4454 * if the target bssid is same as currently associated AP,
4455 * issue reassoc to same AP
4456 */
Ankit Guptaa5076012016-09-14 11:32:19 -07004457 if (!qdf_mem_cmp(targetApBssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004458 pHddStaCtx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05304459 QDF_MAC_ADDR_SIZE)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004460 hdd_info("Reassoc BSSID is same as currently associated AP bssid");
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304461 if (roaming_offload_enabled(hdd_ctx)) {
4462 hdd_wma_send_fastreassoc_cmd((int)adapter->sessionId,
Padma, Santhosh Kumaraf9f08c2016-10-21 21:26:29 +05304463 targetApBssid,
4464 pHddStaCtx->conn_info.operationChannel);
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304465 } else {
4466 sme_get_modify_profile_fields(hdd_ctx->hHal,
4467 adapter->sessionId,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004468 &modProfileFields);
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304469 sme_roam_reassoc(hdd_ctx->hHal, adapter->sessionId,
4470 NULL, modProfileFields, &roamId, 1);
4471 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004472 return 0;
4473 }
4474
Padma, Santhosh Kumaraf9f08c2016-10-21 21:26:29 +05304475 /* Check channel number is a valid channel number */
4476 if (QDF_STATUS_SUCCESS !=
4477 wlan_hdd_validate_operation_channel(adapter, channel)) {
4478 hdd_err("Invalid Channel [%d]", channel);
4479 return -EINVAL;
4480 }
4481
Varun Reddy Yeturud351a6c2016-03-16 14:01:00 -07004482 if (roaming_offload_enabled(hdd_ctx)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004483 hdd_wma_send_fastreassoc_cmd((int)adapter->sessionId,
4484 targetApBssid, (int)channel);
4485 goto exit;
4486 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004487 /* Proceed with reassoc */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004488 handoffInfo.channel = channel;
4489 handoffInfo.src = FASTREASSOC;
Varun Reddy Yeturua66f9c52016-02-17 09:58:40 -08004490 qdf_mem_copy(handoffInfo.bssid.bytes, targetApBssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004491 sizeof(tSirMacAddr));
4492 sme_handoff_request(hdd_ctx->hHal, adapter->sessionId,
4493 &handoffInfo);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004494exit:
4495 return ret;
4496}
4497
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004498static int drv_cmd_set_roam_scan_control(hdd_adapter_t *adapter,
4499 hdd_context_t *hdd_ctx,
4500 uint8_t *command,
4501 uint8_t command_len,
4502 hdd_priv_data_t *priv_data)
4503{
4504 int ret = 0;
4505 uint8_t *value = command;
4506 uint8_t roamScanControl = 0;
4507
4508 /* Move pointer to ahead of SETROAMSCANCONTROL<delimiter> */
4509 value = value + command_len + 1;
4510
4511 /* Convert the value from ascii to integer */
4512 ret = kstrtou8(value, 10, &roamScanControl);
4513 if (ret < 0) {
4514 /*
4515 * If the input value is greater than max value of datatype,
4516 * then also kstrtou8 fails
4517 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004518 hdd_err("kstrtou8 failed ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004519 ret = -EINVAL;
4520 goto exit;
4521 }
4522
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004523 hdd_info("Received Command to Set roam scan control = %d",
4524 roamScanControl);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004525
4526 if (0 != roamScanControl) {
4527 ret = 0; /* return success but ignore param value "true" */
4528 goto exit;
4529 }
4530
4531 sme_set_roam_scan_control(hdd_ctx->hHal,
4532 adapter->sessionId,
4533 roamScanControl);
4534
4535exit:
4536 return ret;
4537}
4538
4539static int drv_cmd_set_okc_mode(hdd_adapter_t *adapter,
4540 hdd_context_t *hdd_ctx,
4541 uint8_t *command,
4542 uint8_t command_len,
4543 hdd_priv_data_t *priv_data)
4544{
4545 int ret = 0;
4546 uint8_t *value = command;
4547 uint8_t okcMode = CFG_OKC_FEATURE_ENABLED_DEFAULT;
4548
4549 /*
4550 * Check if the features OKC/ESE/11R are supported simultaneously,
4551 * then this operation is not permitted (return FAILURE)
4552 */
4553 if (sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
4554 hdd_is_okc_mode_enabled(hdd_ctx) &&
4555 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004556 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004557 ret = -EPERM;
4558 goto exit;
4559 }
4560
4561 /* Move pointer to ahead of SETOKCMODE<delimiter> */
4562 value = value + command_len + 1;
4563
4564 /* Convert the value from ascii to integer */
4565 ret = kstrtou8(value, 10, &okcMode);
4566 if (ret < 0) {
4567 /*
4568 * If the input value is greater than max value of datatype,
4569 * then also kstrtou8 fails
4570 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004571 hdd_err("kstrtou8 failed range [%d - %d]",
4572 CFG_OKC_FEATURE_ENABLED_MIN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004573 CFG_OKC_FEATURE_ENABLED_MAX);
4574 ret = -EINVAL;
4575 goto exit;
4576 }
4577
4578 if ((okcMode < CFG_OKC_FEATURE_ENABLED_MIN) ||
4579 (okcMode > CFG_OKC_FEATURE_ENABLED_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004580 hdd_err("Okc mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004581 okcMode,
4582 CFG_OKC_FEATURE_ENABLED_MIN,
4583 CFG_OKC_FEATURE_ENABLED_MAX);
4584 ret = -EINVAL;
4585 goto exit;
4586 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004587 hdd_info("Received Command to change okc mode = %d",
4588 okcMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004589
4590 hdd_ctx->config->isOkcIniFeatureEnabled = okcMode;
4591
4592exit:
4593 return ret;
4594}
4595
4596static int drv_cmd_get_roam_scan_control(hdd_adapter_t *adapter,
4597 hdd_context_t *hdd_ctx,
4598 uint8_t *command,
4599 uint8_t command_len,
4600 hdd_priv_data_t *priv_data)
4601{
4602 int ret = 0;
4603 bool roamScanControl = sme_get_roam_scan_control(hdd_ctx->hHal);
4604 char extra[32];
4605 uint8_t len = 0;
4606
4607 len = scnprintf(extra, sizeof(extra), "%s %d",
4608 command, roamScanControl);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304609 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004610 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004611 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004612 ret = -EFAULT;
4613 }
4614
4615 return ret;
4616}
4617
4618static int drv_cmd_bt_coex_mode(hdd_adapter_t *adapter,
4619 hdd_context_t *hdd_ctx,
4620 uint8_t *command,
4621 uint8_t command_len,
4622 hdd_priv_data_t *priv_data)
4623{
4624 int ret = 0;
4625 char *bcMode;
4626
4627 bcMode = command + 11;
4628 if ('1' == *bcMode) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004629 hdd_debug("BTCOEXMODE %d", *bcMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004630 hdd_ctx->btCoexModeSet = true;
4631 ret = wlan_hdd_scan_abort(adapter);
4632 if (ret < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004633 hdd_err("Failed to abort existing scan status: %d",
4634 ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004635 }
4636 } else if ('2' == *bcMode) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004637 hdd_debug("BTCOEXMODE %d", *bcMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004638 hdd_ctx->btCoexModeSet = false;
4639 }
4640
4641 return ret;
4642}
4643
4644static int drv_cmd_scan_active(hdd_adapter_t *adapter,
4645 hdd_context_t *hdd_ctx,
4646 uint8_t *command,
4647 uint8_t command_len,
4648 hdd_priv_data_t *priv_data)
4649{
4650 hdd_ctx->ioctl_scan_mode = eSIR_ACTIVE_SCAN;
4651 return 0;
4652}
4653
4654static int drv_cmd_scan_passive(hdd_adapter_t *adapter,
4655 hdd_context_t *hdd_ctx,
4656 uint8_t *command,
4657 uint8_t command_len,
4658 hdd_priv_data_t *priv_data)
4659{
4660 hdd_ctx->ioctl_scan_mode = eSIR_PASSIVE_SCAN;
4661 return 0;
4662}
4663
4664static int drv_cmd_get_dwell_time(hdd_adapter_t *adapter,
4665 hdd_context_t *hdd_ctx,
4666 uint8_t *command,
4667 uint8_t command_len,
4668 hdd_priv_data_t *priv_data)
4669{
4670 int ret = 0;
4671 struct hdd_config *pCfg =
4672 (WLAN_HDD_GET_CTX(adapter))->config;
4673 char extra[32];
4674 uint8_t len = 0;
4675
4676 memset(extra, 0, sizeof(extra));
4677 ret = hdd_get_dwell_time(pCfg, command, extra, sizeof(extra), &len);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304678 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004679 if (ret != 0 || copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004680 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004681 ret = -EFAULT;
4682 goto exit;
4683 }
4684 ret = len;
4685exit:
4686 return ret;
4687}
4688
4689static int drv_cmd_set_dwell_time(hdd_adapter_t *adapter,
4690 hdd_context_t *hdd_ctx,
4691 uint8_t *command,
4692 uint8_t command_len,
4693 hdd_priv_data_t *priv_data)
4694{
4695 return hdd_set_dwell_time(adapter, command);
4696}
4697
4698static int drv_cmd_miracast(hdd_adapter_t *adapter,
4699 hdd_context_t *hdd_ctx,
4700 uint8_t *command,
4701 uint8_t command_len,
4702 hdd_priv_data_t *priv_data)
4703{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304704 QDF_STATUS ret_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004705 int ret = 0;
4706 tHalHandle hHal;
4707 uint8_t filterType = 0;
4708 hdd_context_t *pHddCtx = NULL;
4709 uint8_t *value;
4710
4711 pHddCtx = WLAN_HDD_GET_CTX(adapter);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05304712 if (wlan_hdd_validate_context(pHddCtx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004713 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004714
4715 hHal = pHddCtx->hHal;
4716 value = command + 9;
4717
4718 /* Convert the value from ascii to integer */
4719 ret = kstrtou8(value, 10, &filterType);
4720 if (ret < 0) {
4721 /*
4722 * If the input value is greater than max value of datatype,
4723 * then also kstrtou8 fails
4724 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004725 hdd_err("kstrtou8 failed range ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004726 ret = -EINVAL;
4727 goto exit;
4728 }
4729 if ((filterType < WLAN_HDD_DRIVER_MIRACAST_CFG_MIN_VAL)
4730 || (filterType >
4731 WLAN_HDD_DRIVER_MIRACAST_CFG_MAX_VAL)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004732 hdd_err("Accepted Values are 0 to 2. 0-Disabled, 1-Source, 2-Sink ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004733 ret = -EINVAL;
4734 goto exit;
4735 }
4736 /* Filtertype value should be either 0-Disabled, 1-Source, 2-sink */
4737 pHddCtx->miracast_value = filterType;
4738
4739 ret_status = sme_set_miracast(hHal, filterType);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304740 if (QDF_STATUS_SUCCESS != ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004741 hdd_err("Failed to set miracast");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004742 return -EBUSY;
4743 }
4744
Tushnim Bhattacharyyaca50b322015-12-28 17:14:36 -08004745 if (cds_is_mcc_in_24G())
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004746 return cds_set_mas(adapter, filterType);
4747
4748exit:
4749 return ret;
4750}
4751
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004752/* Function header is left blank intentionally */
4753static int hdd_parse_set_ibss_oui_data_command(uint8_t *command, uint8_t *ie,
4754 int32_t *oui_length, int32_t limit)
4755{
4756 uint8_t len;
4757 uint8_t data;
4758
4759 while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) {
4760 command++;
4761 limit--;
4762 }
4763
4764 len = 2;
4765
4766 while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) &&
4767 (limit > 1)) {
4768 sscanf(command, "%02x", (unsigned int *)&data);
4769 ie[len++] = data;
4770 command += 2;
4771 limit -= 2;
4772 }
4773
4774 *oui_length = len - 2;
4775
4776 while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) {
4777 command++;
4778 limit--;
4779 }
4780
4781 while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) &&
4782 (limit > 1)) {
4783 sscanf(command, "%02x", (unsigned int *)&data);
4784 ie[len++] = data;
4785 command += 2;
4786 limit -= 2;
4787 }
4788
4789 ie[0] = IE_EID_VENDOR;
4790 ie[1] = len - 2;
4791
4792 return len;
4793}
4794
4795/**
4796 * drv_cmd_set_ibss_beacon_oui_data() - set ibss oui data command
4797 * @adapter: Pointer to adapter
4798 * @hdd_ctx: Pointer to HDD context
4799 * @command: Pointer to command string
4800 * @command_len : Command length
4801 * @priv_data : Pointer to priv data
4802 *
4803 * Return:
4804 * int status code
4805 */
4806static int drv_cmd_set_ibss_beacon_oui_data(hdd_adapter_t *adapter,
4807 hdd_context_t *hdd_ctx,
4808 uint8_t *command,
4809 uint8_t command_len,
4810 hdd_priv_data_t *priv_data)
4811{
4812 int i = 0;
4813 int status;
4814 int ret = 0;
4815 uint8_t *ibss_ie;
4816 int32_t oui_length = 0;
4817 uint32_t ibss_ie_length;
4818 uint8_t *value = command;
4819 tSirModifyIE ibssModifyIE;
4820 tCsrRoamProfile *pRoamProfile;
4821 hdd_wext_state_t *pWextState;
4822
4823
Krunal Sonibe766b02016-03-10 13:00:44 -08004824 if (QDF_IBSS_MODE != adapter->device_mode) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004825 hdd_info("Device_mode %s(%d) not IBSS",
4826 hdd_device_mode_to_string(adapter->device_mode),
4827 adapter->device_mode);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004828 return ret;
4829 }
4830
4831 pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(adapter);
4832
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004833 hdd_info("received command %s", ((char *)value));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004834
4835
4836 /* validate argument of command */
4837 if (strlen(value) <= command_len) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004838 hdd_err("No arguments in command length %zu",
4839 strlen(value));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004840 ret = -EFAULT;
4841 goto exit;
4842 }
4843
4844 /* moving to arguments of commands */
4845 value = value + command_len;
4846 command_len = strlen(value);
4847
4848 /* oui_data can't be less than 3 bytes */
4849 if (command_len < (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004850 hdd_err("Invalid SETIBSSBEACONOUIDATA command length %d",
4851 command_len);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004852 ret = -EFAULT;
4853 goto exit;
4854 }
4855
4856 ibss_ie = qdf_mem_malloc(command_len);
4857 if (!ibss_ie) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004858 hdd_err("Could not allocate memory for command length %d",
4859 command_len);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004860 ret = -ENOMEM;
4861 goto exit;
4862 }
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004863
4864 ibss_ie_length = hdd_parse_set_ibss_oui_data_command(value, ibss_ie,
4865 &oui_length,
4866 command_len);
4867 if (ibss_ie_length <= (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004868 hdd_err("Could not parse command %s return length %d",
4869 value, ibss_ie_length);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004870 ret = -EFAULT;
4871 qdf_mem_free(ibss_ie);
4872 goto exit;
4873 }
4874
4875 pRoamProfile = &pWextState->roamProfile;
4876
4877 qdf_copy_macaddr(&ibssModifyIE.bssid,
4878 pRoamProfile->BSSIDs.bssid);
4879
4880 ibssModifyIE.smeSessionId = adapter->sessionId;
4881 ibssModifyIE.notify = true;
4882 ibssModifyIE.ieID = IE_EID_VENDOR;
4883 ibssModifyIE.ieIDLen = ibss_ie_length;
4884 ibssModifyIE.ieBufferlength = ibss_ie_length;
4885 ibssModifyIE.pIEBuffer = ibss_ie;
4886 ibssModifyIE.oui_length = oui_length;
4887
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004888 hdd_warn("ibss_ie length %d oui_length %d ibss_ie:",
4889 ibss_ie_length, oui_length);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004890 while (i < ibssModifyIE.ieBufferlength)
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004891 hdd_warn("0x%x", ibss_ie[i++]);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004892
4893 /* Probe Bcn modification */
4894 sme_modify_add_ie(WLAN_HDD_GET_HAL_CTX(adapter),
4895 &ibssModifyIE, eUPDATE_IE_PROBE_BCN);
4896
4897 /* Populating probe resp frame */
4898 sme_modify_add_ie(WLAN_HDD_GET_HAL_CTX(adapter),
4899 &ibssModifyIE, eUPDATE_IE_PROBE_RESP);
4900
4901 qdf_mem_free(ibss_ie);
4902
4903 status = sme_send_cesium_enable_ind((tHalHandle)(hdd_ctx->hHal),
4904 adapter->sessionId);
4905 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004906 hdd_err("Could not send cesium enable indication %d",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004907 status);
4908 ret = -EINVAL;
4909 goto exit;
4910 }
4911
4912exit:
4913 return ret;
4914}
4915
4916static int drv_cmd_set_rmc_enable(hdd_adapter_t *adapter,
4917 hdd_context_t *hdd_ctx,
4918 uint8_t *command,
4919 uint8_t command_len,
4920 hdd_priv_data_t *priv_data)
4921{
4922 int ret = 0;
4923 uint8_t *value = command;
4924 uint8_t ucRmcEnable = 0;
4925 int status;
4926
Krunal Sonibe766b02016-03-10 13:00:44 -08004927 if ((QDF_IBSS_MODE != adapter->device_mode) &&
4928 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004929 hdd_err("Received SETRMCENABLE cmd in invalid mode %s(%d)",
4930 hdd_device_mode_to_string(adapter->device_mode),
4931 adapter->device_mode);
4932 hdd_err("SETRMCENABLE cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004933 ret = -EINVAL;
4934 goto exit;
4935 }
4936
4937 status = hdd_parse_setrmcenable_command(value, &ucRmcEnable);
4938 if (status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004939 hdd_err("Invalid SETRMCENABLE command ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004940 ret = -EINVAL;
4941 goto exit;
4942 }
4943
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004944 hdd_info("ucRmcEnable %d ", ucRmcEnable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004945
4946 if (true == ucRmcEnable) {
4947 status = sme_enable_rmc((tHalHandle)
4948 (hdd_ctx->hHal),
4949 adapter->sessionId);
4950 } else if (false == ucRmcEnable) {
4951 status = sme_disable_rmc((tHalHandle)
4952 (hdd_ctx->hHal),
4953 adapter->sessionId);
4954 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004955 hdd_err("Invalid SETRMCENABLE command %d",
4956 ucRmcEnable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004957 ret = -EINVAL;
4958 goto exit;
4959 }
4960
4961 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004962 hdd_err("SETRMC %d failed status %d",
4963 ucRmcEnable, status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004964 ret = -EINVAL;
4965 goto exit;
4966 }
4967
4968exit:
4969 return ret;
4970}
4971
4972static int drv_cmd_set_rmc_action_period(hdd_adapter_t *adapter,
4973 hdd_context_t *hdd_ctx,
4974 uint8_t *command,
4975 uint8_t command_len,
4976 hdd_priv_data_t *priv_data)
4977{
4978 int ret = 0;
4979 uint8_t *value = command;
4980 uint32_t uActionPeriod = 0;
4981 int status;
4982
Krunal Sonibe766b02016-03-10 13:00:44 -08004983 if ((QDF_IBSS_MODE != adapter->device_mode) &&
4984 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004985 hdd_err("Received SETRMC cmd in invalid mode %s(%d)",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004986 hdd_device_mode_to_string(adapter->device_mode),
4987 adapter->device_mode);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004988 hdd_err("SETRMC cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004989 ret = -EINVAL;
4990 goto exit;
4991 }
4992
4993 status = hdd_parse_setrmcactionperiod_command(value, &uActionPeriod);
4994 if (status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004995 hdd_err("Invalid SETRMCACTIONPERIOD command ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004996 ret = -EINVAL;
4997 goto exit;
4998 }
4999
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005000 hdd_info("uActionPeriod %d ",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005001 uActionPeriod);
5002
5003 if (sme_cfg_set_int(hdd_ctx->hHal,
5004 WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY,
5005 uActionPeriod)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005006 hdd_err("Could not set SETRMCACTIONPERIOD %d",
5007 uActionPeriod);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005008 ret = -EINVAL;
5009 goto exit;
5010 }
5011
5012 status = sme_send_rmc_action_period((tHalHandle)(hdd_ctx->hHal),
5013 adapter->sessionId);
5014 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005015 hdd_err("Could not send cesium enable indication %d",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005016 status);
5017 ret = -EINVAL;
5018 goto exit;
5019 }
5020
5021exit:
5022 return ret;
5023}
5024
5025static int drv_cmd_get_ibss_peer_info_all(hdd_adapter_t *adapter,
5026 hdd_context_t *hdd_ctx,
5027 uint8_t *command,
5028 uint8_t command_len,
5029 hdd_priv_data_t *priv_data)
5030{
5031 int ret = 0;
5032 int status = QDF_STATUS_SUCCESS;
5033 hdd_station_ctx_t *pHddStaCtx = NULL;
5034 char *extra = NULL;
5035 int idx = 0;
5036 int length = 0;
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005037 uint8_t mac_addr[QDF_MAC_ADDR_SIZE];
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005038 uint32_t numOfBytestoPrint = 0;
5039
Krunal Sonibe766b02016-03-10 13:00:44 -08005040 if (QDF_IBSS_MODE != adapter->device_mode) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005041 hdd_warn("Unsupported in mode %s(%d)",
5042 hdd_device_mode_to_string(adapter->device_mode),
5043 adapter->device_mode);
5044 return -EINVAL;
5045 }
5046
5047 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005048 hdd_info("Received GETIBSSPEERINFOALL Command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005049
5050 /* Handle the command */
5051 status = hdd_cfg80211_get_ibss_peer_info_all(adapter);
5052 if (QDF_STATUS_SUCCESS == status) {
5053 /*
5054 * The variable extra needed to be allocated on the heap since
5055 * amount of memory required to copy the data for 32 devices
5056 * exceeds the size of 1024 bytes of default stack size. On
5057 * 64 bit devices, the default max stack size of 2048 bytes
5058 */
5059 extra = kmalloc(WLAN_MAX_BUF_SIZE, GFP_KERNEL);
5060
5061 if (NULL == extra) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005062 hdd_err("kmalloc failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005063 ret = -EINVAL;
5064 goto exit;
5065 }
5066
5067 /* Copy number of stations */
5068 length = scnprintf(extra, WLAN_MAX_BUF_SIZE, "%d ",
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005069 pHddStaCtx->ibss_peer_info.numPeers);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005070 numOfBytestoPrint = length;
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005071 for (idx = 0; idx < pHddStaCtx->ibss_peer_info.numPeers;
5072 idx++) {
5073 int8_t rssi;
5074 uint32_t tx_rate;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005075
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005076 qdf_mem_copy(mac_addr,
5077 pHddStaCtx->ibss_peer_info.peerInfoParams[idx].
5078 mac_addr, sizeof(mac_addr));
5079
5080 tx_rate =
5081 pHddStaCtx->ibss_peer_info.peerInfoParams[idx].
5082 txRate;
Sriram Madhvapathi85df7c72016-09-30 11:35:28 +05305083 /*
5084 * Only lower 3 bytes are rate info. Mask of the MSByte
5085 */
5086 tx_rate &= 0x00FFFFFF;
5087
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005088 rssi = pHddStaCtx->ibss_peer_info.peerInfoParams[idx].
5089 rssi;
5090
5091 length += scnprintf((extra + length),
5092 WLAN_MAX_BUF_SIZE - length,
5093 "%02x:%02x:%02x:%02x:%02x:%02x %d %d ",
5094 mac_addr[0], mac_addr[1], mac_addr[2],
5095 mac_addr[3], mac_addr[4], mac_addr[5],
5096 tx_rate, rssi);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005097 /*
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005098 * cdf_trace_msg has limitation of 512 bytes for the
5099 * print buffer. Hence printing the data in two chunks.
5100 * The first chunk will have the data for 16 devices
5101 * and the second chunk will have the rest.
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005102 */
5103 if (idx < NUM_OF_STA_DATA_TO_PRINT)
5104 numOfBytestoPrint = length;
5105 }
5106
5107 /*
5108 * Copy the data back into buffer, if the data to copy is
5109 * more than 512 bytes than we will split the data and do
5110 * it in two shots
5111 */
5112 if (copy_to_user(priv_data->buf, extra, numOfBytestoPrint)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005113 hdd_err("Copy into user data buffer failed ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005114 ret = -EFAULT;
5115 goto exit;
5116 }
5117
5118 priv_data->buf[numOfBytestoPrint] = '\0';
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005119 hdd_debug("%s", priv_data->buf);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005120
5121 if (length > numOfBytestoPrint) {
5122 if (copy_to_user
5123 (priv_data->buf + numOfBytestoPrint,
5124 extra + numOfBytestoPrint,
5125 length - numOfBytestoPrint + 1)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005126 hdd_err("Copy into user data buffer failed ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005127 ret = -EFAULT;
5128 goto exit;
5129 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005130 hdd_debug("%s", &priv_data->buf[numOfBytestoPrint]);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005131 }
5132
5133 /* Free temporary buffer */
5134 kfree(extra);
5135 } else {
5136 /* Command failed, log error */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005137 hdd_err("GETIBSSPEERINFOALL command failed with status code %d",
5138 status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005139 ret = -EINVAL;
5140 goto exit;
5141 }
5142 ret = 0;
5143
5144exit:
5145 return ret;
5146}
5147
5148/* Peer Info <Peer Addr> command */
5149static int drv_cmd_get_ibss_peer_info(hdd_adapter_t *adapter,
5150 hdd_context_t *hdd_ctx,
5151 uint8_t *command,
5152 uint8_t command_len,
5153 hdd_priv_data_t *priv_data)
5154{
5155 int ret = 0;
5156 uint8_t *value = command;
5157 QDF_STATUS status;
5158 hdd_station_ctx_t *pHddStaCtx = NULL;
5159 char extra[128] = { 0 };
5160 uint32_t length = 0;
5161 uint8_t staIdx = 0;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005162 struct qdf_mac_addr peerMacAddr;
5163
Krunal Sonibe766b02016-03-10 13:00:44 -08005164 if (QDF_IBSS_MODE != adapter->device_mode) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005165 hdd_warn("Unsupported in mode %s(%d)",
5166 hdd_device_mode_to_string(adapter->device_mode),
5167 adapter->device_mode);
5168 return -EINVAL;
5169 }
5170
5171 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5172
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005173 hdd_info("Received GETIBSSPEERINFO Command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005174
5175 /* if there are no peers, no need to continue with the command */
5176 if (eConnectionState_IbssConnected !=
5177 pHddStaCtx->conn_info.connState) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005178 hdd_info("No IBSS Peers coalesced");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005179 ret = -EINVAL;
5180 goto exit;
5181 }
5182
5183 /* Parse the incoming command buffer */
5184 status = hdd_parse_get_ibss_peer_info(value, &peerMacAddr);
5185 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005186 hdd_err("Invalid GETIBSSPEERINFO command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005187 ret = -EINVAL;
5188 goto exit;
5189 }
5190
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005191 /* Get station index for the peer mac address and sanitize it */
Deepak Dhamdhere5872c8c2016-06-02 15:51:47 -07005192 hdd_get_peer_sta_id(pHddStaCtx, &peerMacAddr, &staIdx);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005193
Naveen Rawatc45d1622016-07-05 12:20:09 -07005194 if (staIdx > MAX_PEERS) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005195 hdd_err("Invalid StaIdx %d returned", staIdx);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005196 ret = -EINVAL;
5197 goto exit;
5198 }
5199
5200 /* Handle the command */
5201 status = hdd_cfg80211_get_ibss_peer_info(adapter, staIdx);
5202 if (QDF_STATUS_SUCCESS == status) {
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005203 uint32_t txRate =
5204 pHddStaCtx->ibss_peer_info.peerInfoParams[0].txRate;
Sriram Madhvapathi85df7c72016-09-30 11:35:28 +05305205 /* Only lower 3 bytes are rate info. Mask of the MSByte */
5206 txRate &= 0x00FFFFFF;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005207
5208 length = scnprintf(extra, sizeof(extra), "%d %d",
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005209 (int)txRate,
5210 (int)pHddStaCtx->ibss_peer_info.
5211 peerInfoParams[0].rssi);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005212
5213 /* Copy the data back into buffer */
5214 if (copy_to_user(priv_data->buf, &extra, length + 1)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005215 hdd_err("copy data to user buffer failed GETIBSSPEERINFO command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005216 ret = -EFAULT;
5217 goto exit;
5218 }
5219 } else {
5220 /* Command failed, log error */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005221 hdd_err("GETIBSSPEERINFO command failed with status code %d",
5222 status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005223 ret = -EINVAL;
5224 goto exit;
5225 }
5226
5227 /* Success ! */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005228 hdd_debug("%s", priv_data->buf);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005229 ret = 0;
5230
5231exit:
5232 return ret;
5233}
5234
5235static int drv_cmd_set_rmc_tx_rate(hdd_adapter_t *adapter,
5236 hdd_context_t *hdd_ctx,
5237 uint8_t *command,
5238 uint8_t command_len,
5239 hdd_priv_data_t *priv_data)
5240{
5241 int ret = 0;
5242 uint8_t *value = command;
5243 uint32_t uRate = 0;
5244 tTxrateinfoflags txFlags = 0;
5245 tSirRateUpdateInd rateUpdateParams = {0};
5246 int status;
5247 struct hdd_config *pConfig = hdd_ctx->config;
5248
Krunal Sonibe766b02016-03-10 13:00:44 -08005249 if ((QDF_IBSS_MODE != adapter->device_mode) &&
5250 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005251 hdd_err("Received SETRMCTXRATE cmd in invalid mode %s(%d)",
5252 hdd_device_mode_to_string(adapter->device_mode),
5253 adapter->device_mode);
5254 hdd_err("SETRMCTXRATE cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005255 ret = -EINVAL;
5256 goto exit;
5257 }
5258
5259 status = hdd_parse_setrmcrate_command(value, &uRate, &txFlags);
5260 if (status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005261 hdd_err("Invalid SETRMCTXRATE command ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005262 ret = -EINVAL;
5263 goto exit;
5264 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005265 hdd_info("uRate %d ", uRate);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005266 /* -1 implies ignore this param */
5267 rateUpdateParams.ucastDataRate = -1;
5268
5269 /*
5270 * Fill the user specifieed RMC rate param
5271 * and the derived tx flags.
5272 */
5273 rateUpdateParams.nss = (pConfig->enable2x2 == 0) ? 0 : 1;
5274 rateUpdateParams.reliableMcastDataRate = uRate;
5275 rateUpdateParams.reliableMcastDataRateTxFlag = txFlags;
5276 rateUpdateParams.dev_mode = adapter->device_mode;
5277 rateUpdateParams.bcastDataRate = -1;
5278 memcpy(rateUpdateParams.bssid.bytes,
5279 adapter->macAddressCurrent.bytes,
5280 sizeof(rateUpdateParams.bssid));
5281 status = sme_send_rate_update_ind((tHalHandle) (hdd_ctx->hHal),
5282 &rateUpdateParams);
5283
5284exit:
5285 return ret;
5286}
5287
5288static int drv_cmd_set_ibss_tx_fail_event(hdd_adapter_t *adapter,
5289 hdd_context_t *hdd_ctx,
5290 uint8_t *command,
5291 uint8_t command_len,
5292 hdd_priv_data_t *priv_data)
5293{
5294 int ret = 0;
5295 char *value;
5296 uint8_t tx_fail_count = 0;
5297 uint16_t pid = 0;
5298
5299 value = command;
5300
5301 ret = hdd_parse_ibsstx_fail_event_params(value, &tx_fail_count, &pid);
5302
5303 if (0 != ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005304 hdd_info("Failed to parse SETIBSSTXFAILEVENT arguments");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005305 goto exit;
5306 }
5307
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005308 hdd_info("tx_fail_cnt=%hhu, pid=%hu", tx_fail_count, pid);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005309
5310 if (0 == tx_fail_count) {
5311 /* Disable TX Fail Indication */
5312 if (QDF_STATUS_SUCCESS ==
5313 sme_tx_fail_monitor_start_stop_ind(hdd_ctx->hHal,
5314 tx_fail_count,
5315 NULL)) {
5316 cesium_pid = 0;
5317 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005318 hdd_err("failed to disable TX Fail Event ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005319 ret = -EINVAL;
5320 }
5321 } else {
5322 if (QDF_STATUS_SUCCESS ==
5323 sme_tx_fail_monitor_start_stop_ind(hdd_ctx->hHal,
5324 tx_fail_count,
5325 (void *)hdd_tx_fail_ind_callback)) {
5326 cesium_pid = pid;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005327 hdd_info("Registered Cesium pid %u",
5328 cesium_pid);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005329 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005330 hdd_err("Failed to enable TX Fail Monitoring");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005331 ret = -EINVAL;
5332 }
5333 }
5334
5335exit:
5336 return ret;
5337}
5338
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08005339#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005340static int drv_cmd_set_ccx_roam_scan_channels(hdd_adapter_t *adapter,
5341 hdd_context_t *hdd_ctx,
5342 uint8_t *command,
5343 uint8_t command_len,
5344 hdd_priv_data_t *priv_data)
5345{
5346 int ret = 0;
5347 uint8_t *value = command;
5348 uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
5349 uint8_t numChannels = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305350 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005351
5352 ret = hdd_parse_channellist(value, ChannelList, &numChannels);
5353 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005354 hdd_err("Failed to parse channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005355 goto exit;
5356 }
5357 if (numChannels > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005358 hdd_err("number of channels (%d) supported exceeded max (%d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005359 numChannels,
5360 WNI_CFG_VALID_CHANNEL_LIST_LEN);
5361 ret = -EINVAL;
5362 goto exit;
5363 }
5364 status = sme_set_ese_roam_scan_channel_list(hdd_ctx->hHal,
5365 adapter->sessionId,
5366 ChannelList,
5367 numChannels);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305368 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005369 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005370 ret = -EINVAL;
5371 goto exit;
5372 }
5373
5374exit:
5375 return ret;
5376}
5377
5378static int drv_cmd_get_tsm_stats(hdd_adapter_t *adapter,
5379 hdd_context_t *hdd_ctx,
5380 uint8_t *command,
5381 uint8_t command_len,
5382 hdd_priv_data_t *priv_data)
5383{
5384 int ret = 0;
5385 uint8_t *value = command;
5386 char extra[128] = { 0 };
5387 int len = 0;
5388 uint8_t tid = 0;
5389 hdd_station_ctx_t *pHddStaCtx;
5390 tAniTrafStrmMetrics tsm_metrics;
5391
Krunal Sonibe766b02016-03-10 13:00:44 -08005392 if ((QDF_STA_MODE != adapter->device_mode) &&
5393 (QDF_P2P_CLIENT_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005394 hdd_warn("Unsupported in mode %s(%d)",
5395 hdd_device_mode_to_string(adapter->device_mode),
5396 adapter->device_mode);
5397 return -EINVAL;
5398 }
5399
5400 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5401
5402 /* if not associated, return error */
5403 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005404 hdd_err("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005405 ret = -EINVAL;
5406 goto exit;
5407 }
5408
5409 /* Move pointer to ahead of GETTSMSTATS<delimiter> */
5410 value = value + command_len + 1;
5411
5412 /* Convert the value from ascii to integer */
5413 ret = kstrtou8(value, 10, &tid);
5414 if (ret < 0) {
5415 /*
5416 * If the input value is greater than max value of datatype,
5417 * then also kstrtou8 fails
5418 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005419 hdd_err("kstrtou8 failed range [%d - %d]",
5420 TID_MIN_VALUE,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005421 TID_MAX_VALUE);
5422 ret = -EINVAL;
5423 goto exit;
5424 }
5425 if ((tid < TID_MIN_VALUE) || (tid > TID_MAX_VALUE)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005426 hdd_err("tid value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005427 tid, TID_MIN_VALUE, TID_MAX_VALUE);
5428 ret = -EINVAL;
5429 goto exit;
5430 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005431 hdd_info("Received Command to get tsm stats tid = %d",
5432 tid);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305433 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005434 hdd_get_tsm_stats(adapter, tid, &tsm_metrics)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005435 hdd_err("failed to get tsm stats");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005436 ret = -EFAULT;
5437 goto exit;
5438 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005439 hdd_info(
5440 "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 -08005441 tsm_metrics.UplinkPktQueueDly,
5442 tsm_metrics.UplinkPktQueueDlyHist[0],
5443 tsm_metrics.UplinkPktQueueDlyHist[1],
5444 tsm_metrics.UplinkPktQueueDlyHist[2],
5445 tsm_metrics.UplinkPktQueueDlyHist[3],
5446 tsm_metrics.UplinkPktTxDly,
5447 tsm_metrics.UplinkPktLoss,
5448 tsm_metrics.UplinkPktCount,
5449 tsm_metrics.RoamingCount,
5450 tsm_metrics.RoamingDly);
5451 /*
5452 * Output TSM stats is of the format
5453 * GETTSMSTATS [PktQueueDly]
5454 * [PktQueueDlyHist[0]]:[PktQueueDlyHist[1]] ...[RoamingDly]
5455 * eg., GETTSMSTATS 10 1:0:0:161 20 1 17 8 39800
5456 */
5457 len = scnprintf(extra,
5458 sizeof(extra),
5459 "%s %d %d:%d:%d:%d %u %d %d %d %d",
5460 command,
5461 tsm_metrics.UplinkPktQueueDly,
5462 tsm_metrics.UplinkPktQueueDlyHist[0],
5463 tsm_metrics.UplinkPktQueueDlyHist[1],
5464 tsm_metrics.UplinkPktQueueDlyHist[2],
5465 tsm_metrics.UplinkPktQueueDlyHist[3],
5466 tsm_metrics.UplinkPktTxDly,
5467 tsm_metrics.UplinkPktLoss,
5468 tsm_metrics.UplinkPktCount,
5469 tsm_metrics.RoamingCount,
5470 tsm_metrics.RoamingDly);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305471 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005472 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005473 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005474 ret = -EFAULT;
5475 goto exit;
5476 }
5477
5478exit:
5479 return ret;
5480}
5481
5482static int drv_cmd_set_cckm_ie(hdd_adapter_t *adapter,
5483 hdd_context_t *hdd_ctx,
5484 uint8_t *command,
5485 uint8_t command_len,
5486 hdd_priv_data_t *priv_data)
5487{
5488 int ret;
5489 uint8_t *value = command;
5490 uint8_t *cckmIe = NULL;
5491 uint8_t cckmIeLen = 0;
5492
5493 ret = hdd_parse_get_cckm_ie(value, &cckmIe, &cckmIeLen);
5494 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005495 hdd_err("Failed to parse cckm ie data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005496 goto exit;
5497 }
5498
5499 if (cckmIeLen > DOT11F_IE_RSN_MAX_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005500 hdd_err("CCKM Ie input length is more than max[%d]",
5501 DOT11F_IE_RSN_MAX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005502 if (NULL != cckmIe) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305503 qdf_mem_free(cckmIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005504 cckmIe = NULL;
5505 }
5506 ret = -EINVAL;
5507 goto exit;
5508 }
5509
5510 sme_set_cckm_ie(hdd_ctx->hHal, adapter->sessionId,
5511 cckmIe, cckmIeLen);
5512 if (NULL != cckmIe) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305513 qdf_mem_free(cckmIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005514 cckmIe = NULL;
5515 }
5516
5517exit:
5518 return ret;
5519}
5520
5521static int drv_cmd_ccx_beacon_req(hdd_adapter_t *adapter,
5522 hdd_context_t *hdd_ctx,
5523 uint8_t *command,
5524 uint8_t command_len,
5525 hdd_priv_data_t *priv_data)
5526{
5527 int ret;
5528 uint8_t *value = command;
5529 tCsrEseBeaconReq eseBcnReq;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305530 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005531
Krunal Sonibe766b02016-03-10 13:00:44 -08005532 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005533 hdd_warn("Unsupported in mode %s(%d)",
5534 hdd_device_mode_to_string(adapter->device_mode),
5535 adapter->device_mode);
5536 return -EINVAL;
5537 }
5538
5539 ret = hdd_parse_ese_beacon_req(value, &eseBcnReq);
5540 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005541 hdd_err("Failed to parse ese beacon req");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005542 goto exit;
5543 }
5544
5545 if (!hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005546 hdd_info("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005547 hdd_indicate_ese_bcn_report_no_results(adapter,
5548 eseBcnReq.bcnReq[0].measurementToken,
5549 0x02, /* BIT(1) set for measurement done */
5550 0); /* no BSS */
5551 goto exit;
5552 }
5553
5554 status = sme_set_ese_beacon_request(hdd_ctx->hHal,
5555 adapter->sessionId,
5556 &eseBcnReq);
5557
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305558 if (QDF_STATUS_E_RESOURCES == status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005559 hdd_info("sme_set_ese_beacon_request failed (%d), a request already in progress",
5560 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005561 ret = -EBUSY;
5562 goto exit;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305563 } else if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005564 hdd_err("sme_set_ese_beacon_request failed (%d)",
5565 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005566 ret = -EINVAL;
5567 goto exit;
5568 }
5569
5570exit:
5571 return ret;
5572}
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005573
5574/**
5575 * drv_cmd_ccx_plm_req() - Set ESE PLM request
5576 * @adapter: Pointer to the HDD adapter
5577 * @hdd_ctx: Pointer to the HDD context
5578 * @command: Driver command string
5579 * @command_len: Driver command string length
5580 * @priv_data: Private data coming with the driver command. Unused here
5581 *
5582 * This function handles driver command that sets the ESE PLM request
5583 *
5584 * Return: 0 on success; negative errno otherwise
5585 */
5586static int drv_cmd_ccx_plm_req(hdd_adapter_t *adapter,
5587 hdd_context_t *hdd_ctx,
5588 uint8_t *command,
5589 uint8_t command_len,
5590 hdd_priv_data_t *priv_data)
5591{
5592 int ret = 0;
5593 uint8_t *value = command;
5594 QDF_STATUS status = QDF_STATUS_SUCCESS;
5595 tpSirPlmReq pPlmRequest = NULL;
5596
5597 pPlmRequest = qdf_mem_malloc(sizeof(tSirPlmReq));
5598 if (NULL == pPlmRequest) {
5599 ret = -ENOMEM;
5600 goto exit;
5601 }
5602
5603 status = hdd_parse_plm_cmd(value, pPlmRequest);
5604 if (QDF_STATUS_SUCCESS != status) {
5605 qdf_mem_free(pPlmRequest);
5606 pPlmRequest = NULL;
5607 ret = -EINVAL;
5608 goto exit;
5609 }
5610 pPlmRequest->sessionId = adapter->sessionId;
5611
5612 status = sme_set_plm_request(hdd_ctx->hHal, pPlmRequest);
5613 if (QDF_STATUS_SUCCESS != status) {
5614 qdf_mem_free(pPlmRequest);
5615 pPlmRequest = NULL;
5616 ret = -EINVAL;
5617 goto exit;
5618 }
5619
5620exit:
5621 return ret;
5622}
5623
5624/**
5625 * drv_cmd_set_ccx_mode() - Set ESE mode
5626 * @adapter: Pointer to the HDD adapter
5627 * @hdd_ctx: Pointer to the HDD context
5628 * @command: Driver command string
5629 * @command_len: Driver command string length
5630 * @priv_data: Private data coming with the driver command. Unused here
5631 *
5632 * This function handles driver command that sets ESE mode
5633 *
5634 * Return: 0 on success; negative errno otherwise
5635 */
5636static int drv_cmd_set_ccx_mode(hdd_adapter_t *adapter,
5637 hdd_context_t *hdd_ctx,
5638 uint8_t *command,
5639 uint8_t command_len,
5640 hdd_priv_data_t *priv_data)
5641{
5642 int ret = 0;
5643 uint8_t *value = command;
5644 uint8_t eseMode = CFG_ESE_FEATURE_ENABLED_DEFAULT;
5645
5646 /*
5647 * Check if the features OKC/ESE/11R are supported simultaneously,
5648 * then this operation is not permitted (return FAILURE)
5649 */
5650 if (sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
5651 hdd_is_okc_mode_enabled(hdd_ctx) &&
5652 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
5653 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
5654 ret = -EPERM;
5655 goto exit;
5656 }
5657
Deepak Dhamdherea2785822016-11-17 01:17:45 -08005658 if (!adapter->fast_roaming_allowed) {
5659 hdd_warn("Fast roaming is not allowed on this device hence this operation is not permitted!");
5660 ret = -EPERM;
5661 goto exit;
5662 }
5663
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005664 /* Move pointer to ahead of SETCCXMODE<delimiter> */
5665 value = value + command_len + 1;
5666
5667 /* Convert the value from ascii to integer */
5668 ret = kstrtou8(value, 10, &eseMode);
5669 if (ret < 0) {
5670 /*
5671 * If the input value is greater than max value of datatype,
5672 * then also kstrtou8 fails
5673 */
5674 hdd_err("kstrtou8 failed range [%d - %d]",
5675 CFG_ESE_FEATURE_ENABLED_MIN,
5676 CFG_ESE_FEATURE_ENABLED_MAX);
5677 ret = -EINVAL;
5678 goto exit;
5679 }
5680
5681 if ((eseMode < CFG_ESE_FEATURE_ENABLED_MIN) ||
5682 (eseMode > CFG_ESE_FEATURE_ENABLED_MAX)) {
5683 hdd_err("Ese mode value %d is out of range (Min: %d Max: %d)",
5684 eseMode,
5685 CFG_ESE_FEATURE_ENABLED_MIN,
5686 CFG_ESE_FEATURE_ENABLED_MAX);
5687 ret = -EINVAL;
5688 goto exit;
5689 }
5690 hdd_info("Received Command to change ese mode = %d", eseMode);
5691
5692 hdd_ctx->config->isEseIniFeatureEnabled = eseMode;
5693 sme_update_is_ese_feature_enabled(hdd_ctx->hHal,
5694 adapter->sessionId,
5695 eseMode);
5696
5697exit:
5698 return ret;
5699}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08005700#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005701
5702static int drv_cmd_set_mc_rate(hdd_adapter_t *adapter,
5703 hdd_context_t *hdd_ctx,
5704 uint8_t *command,
5705 uint8_t command_len,
5706 hdd_priv_data_t *priv_data)
5707{
5708 int ret = 0;
5709 uint8_t *value = command;
5710 int targetRate;
5711
5712 /* input value is in units of hundred kbps */
5713
5714 /* Move pointer to ahead of SETMCRATE<delimiter> */
5715 value = value + command_len + 1;
5716
5717 /* Convert the value from ascii to integer, decimal base */
5718 ret = kstrtouint(value, 10, &targetRate);
5719
5720 ret = wlan_hdd_set_mc_rate(adapter, targetRate);
5721 return ret;
5722}
5723
5724static int drv_cmd_max_tx_power(hdd_adapter_t *adapter,
5725 hdd_context_t *hdd_ctx,
5726 uint8_t *command,
5727 uint8_t command_len,
5728 hdd_priv_data_t *priv_data)
5729{
5730 int ret = 0;
5731 int status;
5732 int txPower;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305733 QDF_STATUS qdf_status;
5734 QDF_STATUS smeStatus;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005735 uint8_t *value = command;
Anurag Chouhan6d760662016-02-20 16:05:43 +05305736 struct qdf_mac_addr bssid = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
5737 struct qdf_mac_addr selfMac = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005738 hdd_adapter_list_node_t *pAdapterNode = NULL;
5739 hdd_adapter_list_node_t *pNext = NULL;
5740
5741 status = hdd_parse_setmaxtxpower_command(value, &txPower);
5742 if (status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005743 hdd_err("Invalid MAXTXPOWER command ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005744 ret = -EINVAL;
5745 goto exit;
5746 }
5747
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305748 qdf_status = hdd_get_front_adapter(hdd_ctx, &pAdapterNode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005749 while (NULL != pAdapterNode
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305750 && QDF_STATUS_SUCCESS == qdf_status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005751 adapter = pAdapterNode->pAdapter;
5752 /* Assign correct self MAC address */
Anurag Chouhanc5548422016-02-24 18:33:27 +05305753 qdf_copy_macaddr(&bssid,
Srinivas Girigowda97215232015-09-24 12:26:28 -07005754 &adapter->macAddressCurrent);
Anurag Chouhanc5548422016-02-24 18:33:27 +05305755 qdf_copy_macaddr(&selfMac,
Srinivas Girigowda97215232015-09-24 12:26:28 -07005756 &adapter->macAddressCurrent);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005757
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005758 hdd_info("Device mode %d max tx power %d selfMac: "
5759 MAC_ADDRESS_STR " bssId: " MAC_ADDRESS_STR " ",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005760 adapter->device_mode, txPower,
Srinivas Girigowda97215232015-09-24 12:26:28 -07005761 MAC_ADDR_ARRAY(selfMac.bytes),
5762 MAC_ADDR_ARRAY(bssid.bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005763
Srinivas Girigowda97215232015-09-24 12:26:28 -07005764 smeStatus = sme_set_max_tx_power(hdd_ctx->hHal,
5765 bssid, selfMac, txPower);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305766 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005767 hdd_err("Set max tx power failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005768 ret = -EINVAL;
5769 goto exit;
5770 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005771 hdd_info("Set max tx power success");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305772 qdf_status = hdd_get_next_adapter(hdd_ctx, pAdapterNode,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005773 &pNext);
5774 pAdapterNode = pNext;
5775 }
5776
5777exit:
5778 return ret;
5779}
5780
5781static int drv_cmd_set_dfs_scan_mode(hdd_adapter_t *adapter,
5782 hdd_context_t *hdd_ctx,
5783 uint8_t *command,
5784 uint8_t command_len,
5785 hdd_priv_data_t *priv_data)
5786{
5787 int ret = 0;
5788 uint8_t *value = command;
5789 uint8_t dfsScanMode = CFG_ROAMING_DFS_CHANNEL_DEFAULT;
5790
5791 /* Move pointer to ahead of SETDFSSCANMODE<delimiter> */
5792 value = value + command_len + 1;
5793
5794 /* Convert the value from ascii to integer */
5795 ret = kstrtou8(value, 10, &dfsScanMode);
5796 if (ret < 0) {
5797 /*
5798 * If the input value is greater than max value of datatype,
5799 * then also kstrtou8 fails
5800 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005801 hdd_err("kstrtou8 failed range [%d - %d]",
5802 CFG_ROAMING_DFS_CHANNEL_MIN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005803 CFG_ROAMING_DFS_CHANNEL_MAX);
5804 ret = -EINVAL;
5805 goto exit;
5806 }
5807
5808 if ((dfsScanMode < CFG_ROAMING_DFS_CHANNEL_MIN) ||
5809 (dfsScanMode > CFG_ROAMING_DFS_CHANNEL_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005810 hdd_err("dfsScanMode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005811 dfsScanMode,
5812 CFG_ROAMING_DFS_CHANNEL_MIN,
5813 CFG_ROAMING_DFS_CHANNEL_MAX);
5814 ret = -EINVAL;
5815 goto exit;
5816 }
5817
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005818 hdd_info("Received Command to Set DFS Scan Mode = %d",
5819 dfsScanMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005820
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005821 /* When DFS scanning is disabled, the DFS channels need to be
5822 * removed from the operation of device.
5823 */
5824 ret = wlan_hdd_disable_dfs_chan_scan(hdd_ctx, adapter,
5825 (dfsScanMode == CFG_ROAMING_DFS_CHANNEL_DISABLED));
5826 if (ret < 0) {
5827 /* Some conditions prevented it from disabling DFS channels */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005828 hdd_err("disable/enable DFS channel request was denied");
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005829 goto exit;
5830 }
5831
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005832 hdd_ctx->config->allowDFSChannelRoam = dfsScanMode;
5833 sme_update_dfs_scan_mode(hdd_ctx->hHal, adapter->sessionId,
5834 dfsScanMode);
5835
5836exit:
5837 return ret;
5838}
5839
5840static int drv_cmd_get_dfs_scan_mode(hdd_adapter_t *adapter,
5841 hdd_context_t *hdd_ctx,
5842 uint8_t *command,
5843 uint8_t command_len,
5844 hdd_priv_data_t *priv_data)
5845{
5846 int ret = 0;
5847 uint8_t dfsScanMode = sme_get_dfs_scan_mode(hdd_ctx->hHal);
5848 char extra[32];
5849 uint8_t len = 0;
5850
5851 len = scnprintf(extra, sizeof(extra), "%s %d", command, dfsScanMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305852 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005853 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005854 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005855 ret = -EFAULT;
5856 }
5857
5858 return ret;
5859}
5860
5861static int drv_cmd_get_link_status(hdd_adapter_t *adapter,
5862 hdd_context_t *hdd_ctx,
5863 uint8_t *command,
5864 uint8_t command_len,
5865 hdd_priv_data_t *priv_data)
5866{
5867 int ret = 0;
5868 int value = wlan_hdd_get_link_status(adapter);
5869 char extra[32];
5870 uint8_t len;
5871
5872 len = scnprintf(extra, sizeof(extra), "%s %d", command, value);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305873 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005874 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005875 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005876 ret = -EFAULT;
5877 }
5878
5879 return ret;
5880}
5881
5882#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
5883static int drv_cmd_enable_ext_wow(hdd_adapter_t *adapter,
5884 hdd_context_t *hdd_ctx,
5885 uint8_t *command,
5886 uint8_t command_len,
5887 hdd_priv_data_t *priv_data)
5888{
5889 uint8_t *value = command;
5890 int set_value;
5891
5892 /* Move pointer to ahead of ENABLEEXTWOW */
5893 value = value + command_len;
5894
Anurag Chouhan43e0c752016-09-03 16:17:02 +05305895 if (!(sscanf(value, "%d", &set_value))) {
5896 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
5897 ("No input identified"));
5898 return -EINVAL;
5899 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005900
5901 return hdd_enable_ext_wow_parser(adapter,
5902 adapter->sessionId,
5903 set_value);
5904}
5905
5906static int drv_cmd_set_app1_params(hdd_adapter_t *adapter,
5907 hdd_context_t *hdd_ctx,
5908 uint8_t *command,
5909 uint8_t command_len,
5910 hdd_priv_data_t *priv_data)
5911{
5912 int ret;
5913 uint8_t *value = command;
5914
5915 /* Move pointer to ahead of SETAPP1PARAMS */
5916 value = value + command_len;
5917
5918 ret = hdd_set_app_type1_parser(adapter,
5919 value, strlen(value));
5920 if (ret >= 0)
5921 hdd_ctx->is_extwow_app_type1_param_set = true;
5922
5923 return ret;
5924}
5925
5926static int drv_cmd_set_app2_params(hdd_adapter_t *adapter,
5927 hdd_context_t *hdd_ctx,
5928 uint8_t *command,
5929 uint8_t command_len,
5930 hdd_priv_data_t *priv_data)
5931{
5932 int ret;
5933 uint8_t *value = command;
5934
5935 /* Move pointer to ahead of SETAPP2PARAMS */
5936 value = value + command_len;
5937
5938 ret = hdd_set_app_type2_parser(adapter, value, strlen(value));
5939 if (ret >= 0)
5940 hdd_ctx->is_extwow_app_type2_param_set = true;
5941
5942 return ret;
5943}
5944#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
5945
5946#ifdef FEATURE_WLAN_TDLS
5947/**
5948 * drv_cmd_tdls_secondary_channel_offset() - secondary tdls off channel offset
5949 * @adapter: Pointer to the HDD adapter
5950 * @hdd_ctx: Pointer to the HDD context
5951 * @command: Driver command string
5952 * @command_len: Driver command string length
5953 * @priv_data: Private data coming with the driver command. Unused here
5954 *
5955 * This function handles driver command that sets the secondary tdls off channel
5956 * offset
5957 *
5958 * Return: 0 on success; negative errno otherwise
5959 */
5960static int drv_cmd_tdls_secondary_channel_offset(hdd_adapter_t *adapter,
5961 hdd_context_t *hdd_ctx,
5962 uint8_t *command,
5963 uint8_t command_len,
5964 hdd_priv_data_t *priv_data)
5965{
5966 int ret;
5967 uint8_t *value = command;
5968 int set_value;
5969
5970 /* Move pointer to point the string */
5971 value += command_len;
5972
5973 ret = sscanf(value, "%d", &set_value);
5974 if (ret != 1)
5975 return -EINVAL;
5976
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005977 hdd_info("Tdls offchannel offset:%d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005978
5979 ret = hdd_set_tdls_secoffchanneloffset(hdd_ctx, set_value);
5980
5981 return ret;
5982}
5983
5984/**
5985 * drv_cmd_tdls_off_channel_mode() - set tdls off channel mode
5986 * @adapter: Pointer to the HDD adapter
5987 * @hdd_ctx: Pointer to the HDD context
5988 * @command: Driver command string
5989 * @command_len: Driver command string length
5990 * @priv_data: Private data coming with the driver command. Unused here
5991 *
5992 * This function handles driver command that sets tdls off channel mode
5993 *
5994 * Return: 0 on success; negative errno otherwise
5995 */
5996static int drv_cmd_tdls_off_channel_mode(hdd_adapter_t *adapter,
5997 hdd_context_t *hdd_ctx,
5998 uint8_t *command,
5999 uint8_t command_len,
6000 hdd_priv_data_t *priv_data)
6001{
6002 int ret;
6003 uint8_t *value = command;
6004 int set_value;
6005
6006 /* Move pointer to point the string */
6007 value += command_len;
6008
6009 ret = sscanf(value, "%d", &set_value);
6010 if (ret != 1)
6011 return -EINVAL;
6012
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006013 hdd_info("Tdls offchannel mode:%d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006014
6015 ret = hdd_set_tdls_offchannelmode(adapter, set_value);
6016
6017 return ret;
6018}
6019
6020/**
6021 * drv_cmd_tdls_off_channel() - set tdls off channel number
6022 * @adapter: Pointer to the HDD adapter
6023 * @hdd_ctx: Pointer to the HDD context
6024 * @command: Driver command string
6025 * @command_len: Driver command string length
6026 * @priv_data: Private data coming with the driver command. Unused here
6027 *
6028 * This function handles driver command that sets tdls off channel number
6029 *
6030 * Return: 0 on success; negative errno otherwise
6031 */
6032static int drv_cmd_tdls_off_channel(hdd_adapter_t *adapter,
6033 hdd_context_t *hdd_ctx,
6034 uint8_t *command,
6035 uint8_t command_len,
6036 hdd_priv_data_t *priv_data)
6037{
6038 int ret;
6039 uint8_t *value = command;
6040 int set_value;
6041
6042 /* Move pointer to point the string */
6043 value += command_len;
6044
6045 ret = sscanf(value, "%d", &set_value);
6046 if (ret != 1)
6047 return -EINVAL;
6048
Krishna Kumaar Natarajan4d090352015-10-26 18:30:53 -07006049 if (CDS_IS_DFS_CH(set_value)) {
6050 hdd_err("DFS channel %d is passed for hdd_set_tdls_offchannel",
6051 set_value);
6052 return -EINVAL;
6053 }
6054
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006055 hdd_info("Tdls offchannel num: %d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006056
6057 ret = hdd_set_tdls_offchannel(hdd_ctx, set_value);
6058
6059 return ret;
6060}
6061
6062/**
6063 * drv_cmd_tdls_scan() - set tdls scan type
6064 * @adapter: Pointer to the HDD adapter
6065 * @hdd_ctx: Pointer to the HDD context
6066 * @command: Driver command string
6067 * @command_len: Driver command string length
6068 * @priv_data: Private data coming with the driver command. Unused here
6069 *
6070 * This function handles driver command that sets tdls scan type
6071 *
6072 * Return: 0 on success; negative errno otherwise
6073 */
6074static int drv_cmd_tdls_scan(hdd_adapter_t *adapter,
6075 hdd_context_t *hdd_ctx,
6076 uint8_t *command,
6077 uint8_t command_len,
6078 hdd_priv_data_t *priv_data)
6079{
6080 int ret;
6081 uint8_t *value = command;
6082 int set_value;
6083
6084 /* Move pointer to point the string */
6085 value += command_len;
6086
6087 ret = sscanf(value, "%d", &set_value);
6088 if (ret != 1)
6089 return -EINVAL;
6090
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006091 hdd_info("Tdls scan type val: %d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006092
6093 ret = hdd_set_tdls_scan_type(hdd_ctx, set_value);
6094
6095 return ret;
6096}
6097#endif
6098
6099static int drv_cmd_get_rssi(hdd_adapter_t *adapter,
6100 hdd_context_t *hdd_ctx,
6101 uint8_t *command,
6102 uint8_t command_len,
6103 hdd_priv_data_t *priv_data)
6104{
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006105 int ret = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006106 int8_t rssi = 0;
6107 char extra[32];
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006108
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006109 uint8_t len = 0;
6110
6111 wlan_hdd_get_rssi(adapter, &rssi);
6112
6113 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
Anurag Chouhan6d760662016-02-20 16:05:43 +05306114 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006115
6116 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006117 hdd_err("Failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006118 ret = -EFAULT;
6119 }
6120
6121 return ret;
6122}
6123
6124static int drv_cmd_get_linkspeed(hdd_adapter_t *adapter,
6125 hdd_context_t *hdd_ctx,
6126 uint8_t *command,
6127 uint8_t command_len,
6128 hdd_priv_data_t *priv_data)
6129{
6130 int ret;
6131 uint32_t link_speed = 0;
6132 char extra[32];
6133 uint8_t len = 0;
6134
6135 ret = wlan_hdd_get_link_speed(adapter, &link_speed);
6136 if (0 != ret)
6137 return ret;
6138
6139 len = scnprintf(extra, sizeof(extra), "%s %d", command, link_speed);
Anurag Chouhan6d760662016-02-20 16:05:43 +05306140 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006141 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006142 hdd_err("Failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006143 ret = -EFAULT;
6144 }
6145
6146 return ret;
6147}
6148
6149#ifdef FEATURE_NAPI
6150/**
6151 * hdd_parse_napi() - helper functions to drv_cmd_napi
6152 * @str : source string to parse
6153 * @cmd : pointer to cmd part after parsing
6154 * @sub : pointer to subcmd part after parsing
6155 * @aux : pointer to optional aux part after parsing
6156 *
6157 * Example:
6158 * NAPI SCALE <n> +-- IN str
6159 * | | +------ OUT aux
6160 * | +------------ OUT subcmd
6161 * +----------------- OUT cmd
6162 *
6163 * Return: ==0: success; !=0: failure
6164 */
6165static int hdd_parse_napi(char **str, char **cmd, char **sub, char **aux)
6166{
6167 int rc;
6168 char *token, *lcmd = NULL, *lsub = NULL, *laux = NULL;
6169
6170 NAPI_DEBUG("-->\n");
6171
6172 token = strsep(str, " \t");
6173 if (NULL == token) {
6174 hdd_err("cannot parse cmd");
6175 goto parse_end;
6176 }
6177 lcmd = token;
6178
6179 token = strsep(str, " \t");
6180 if (NULL == token) {
6181 hdd_err("cannot parse subcmd");
6182 goto parse_end;
6183 }
6184 lsub = token;
6185
6186 token = strsep(str, " \t");
6187 if (NULL == token)
6188 hdd_warn("cannot parse aux\n");
6189 else
6190 laux = token;
6191
6192parse_end:
6193 if ((NULL == lcmd) || (NULL == lsub))
6194 rc = -EINVAL;
6195 else {
6196 rc = 0;
6197 *cmd = lcmd;
6198 *sub = lsub;
6199 if (NULL != aux)
6200 *aux = laux;
6201 }
6202 NAPI_DEBUG("<--[rc=%d]\n", rc);
6203 return rc;
6204}
6205
6206
6207/**
6208 * hdd_parse_stats() - print NAPI stats into a buffer
6209 * @buf : buffer to write stats into
6210 * @max : "size of buffer"
6211 * @idp : NULL: all stats, otherwise, ptr to the NAPI instance
6212 * @napid: binary structure to retrieve the stats from
6213 *
6214 * Return: number of bytes written into the buffer
6215 */
6216int hdd_napi_stats(char *buf,
6217 int max,
6218 char *indp,
6219 struct qca_napi_data *napid)
6220{
6221 int n = 0;
6222 int i, j, k; /* NAPI, CPU, bucket indices */
6223 int from, to;
6224 struct qca_napi_info *napii;
6225 struct qca_napi_stat *napis;
6226
6227 NAPI_DEBUG("-->\n");
6228
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006229 if (NULL == napid)
6230 return n;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006231 if (NULL == indp) {
6232 from = 0;
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006233 to = CE_COUNT_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006234 } else {
6235 if (0 > kstrtoint(indp, 10, &to)) {
6236 from = 0;
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006237 to = CE_COUNT_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006238 } else
6239 from = to;
6240 }
6241
6242 for (i = from; i < to; i++)
6243 if (napid->ce_map & (0x01 << i)) {
6244 napii = &(napid->napis[i]);
6245 for (j = 0; j < NR_CPUS; j++) {
6246 napis = &(napii->stats[j]);
6247 n += scnprintf(buf + n, max - n,
6248 "STATS: NAPI[%d] CPU: %d scheds: %d polls: %d completes: %d done: %d ",
6249 i, j,
6250 napis->napi_schedules,
6251 napis->napi_polls,
6252 napis->napi_completes,
6253 napis->napi_workdone);
6254
6255 for (k = 0; k < QCA_NAPI_NUM_BUCKETS; k++) {
6256 n += scnprintf(
6257 buf + n, max - n,
6258 " %d",
6259 napis->napi_budget_uses[k]);
6260 }
6261 n += scnprintf(buf+n, max - n, "\n");
6262 }
6263 }
6264
6265 NAPI_DEBUG("<--[n=%d]\n", n);
6266 return n;
6267}
6268
6269/**
6270 * napi_set_scale() - sets the scale attribute in all NAPI entries
6271 * @sc : scale to set
6272 *
6273 * Return: void
6274 */
6275static void napi_set_scale(uint8_t sc)
6276{
6277 uint32_t i;
6278 struct qca_napi_data *napi_data;
6279
6280 napi_data = hdd_napi_get_all();
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006281 if (likely(NULL != napi_data))
6282 for (i = 0; i < CE_COUNT_MAX; i++)
6283 if (napi_data->ce_map & (0x01 << i))
6284 napi_data->napis[i].scale = sc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006285
6286 return;
6287}
6288/**
6289 * drv_cmd_napi() - processes NAPI commands
6290 * @adapter : net_device
6291 * @hdd_ctx : HDD context
6292 * @command : command string from user command (including "NAPI")
6293 * @command_len: length of command
6294 * @priv_data : ifr_data
6295 *
6296 * Commands supported:
6297 * NAPI ENABLE : enables NAPI administratively. Note that this may not
6298 * enable NAPI functionally, as some other conditions
6299 * may not have been satisfied yet
6300 * NAPI DISABLE : reverse operation of "enable"
6301 * NAPI STATUS : get global status of NAPI instances
6302 * NAPI STATS [<n>] : get the stats for a given NAPI instance
6303 * NAPI SCALE <n> : set the scale factor
6304 *
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006305 * Return: 0: success; !0: failure
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006306 */
6307static int drv_cmd_napi(hdd_adapter_t *adapter,
6308 hdd_context_t *hdd_ctx,
6309 uint8_t *command,
6310 uint8_t command_len,
6311 hdd_priv_data_t *priv_data)
6312{
6313 int rc = 0;
6314 int n, l;
6315 char *cmd = NULL, *subcmd = NULL, *aux = NULL;
6316 char *synopsis = "NAPI ENABLE\n"
6317 "NAPI DISABLE\n"
6318 "NAPI STATUS\n"
6319 "NAPI STATS [<n>] -- if no <n> then all\n"
6320 "NAPI SCALE <n> -- set the scale\n";
6321 char *reply = NULL;
6322
6323 /* make a local copy, as strsep modifies the str in place */
6324 char *str = NULL;
6325
6326 NAPI_DEBUG("-->\n");
6327
6328 /**
6329 * NOTE TO MAINTAINER: from this point to the end of the function,
6330 * please do not return anywhere in the code except the very end
6331 * to avoid memory leakage (goto end_drv_napi instead)
6332 * or make sure that reply+str is freed
6333 */
6334 reply = kmalloc(MAX_USER_COMMAND_SIZE, GFP_KERNEL);
6335 if (NULL == reply) {
6336 hdd_err("could not allocate reply buffer");
6337 rc = -ENOMEM;
6338 goto end_drv_napi;
6339 }
6340
6341 str = kmalloc(strlen(command) + 1, GFP_KERNEL);
6342 if (NULL == str) {
6343 hdd_err("could not allocate copy of input buffer");
6344 rc = -ENOMEM;
6345 goto end_drv_napi;
6346 }
6347
6348 strlcpy(str, command, strlen(command) + 1);
6349 hdd_debug("parsing command into cmd=0x%p sub=0x%p aux=0x%p\n",
6350 cmd, subcmd, aux);
6351
6352
6353 rc = hdd_parse_napi(&str, &cmd, &subcmd, &aux);
6354
6355 if (0 != rc) {
6356 const char *msg = "unknown or badly formatted cmd\n%s";
Anurag Chouhan6d760662016-02-20 16:05:43 +05306357 l = QDF_MIN(MAX_USER_COMMAND_SIZE,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006358 strlen(msg)+strlen(synopsis));
6359 n = scnprintf(reply, l, msg, synopsis);
6360
6361 if (copy_to_user(priv_data->buf, reply,
Anurag Chouhan6d760662016-02-20 16:05:43 +05306362 QDF_MIN(priv_data->total_len, l)))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006363 hdd_err("failed to copy data to user buffer");
6364 hdd_debug("reply: %s", reply);
6365
6366 rc = -EINVAL;
6367 } else {
6368 hdd_debug("cmd=(%s) subcmd=(%s) aux=(%s)\n",
6369 cmd, subcmd, aux);
6370 if (!strcmp(subcmd, "ENABLE"))
6371 hdd_napi_event(NAPI_EVT_CMD_STATE, (void *)1);
6372 else if (!strcmp(subcmd, "DISABLE"))
6373 hdd_napi_event(NAPI_EVT_CMD_STATE, (void *)0);
6374 else if (!strcmp(subcmd, "STATUS")) {
6375 int n = 0;
6376 uint32_t i;
6377 struct qca_napi_data *napi_data;
6378
6379 napi_data = hdd_napi_get_all();
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006380 if (unlikely(NULL == napi_data))
6381 goto status_end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006382 n += scnprintf(reply+n, MAX_USER_COMMAND_SIZE - n,
6383 "NAPI state: 0x%08x map: 0x%08x\n",
6384 napi_data->state,
6385 napi_data->ce_map);
6386
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006387 for (i = 0; i < CE_COUNT_MAX; i++)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006388 if (napi_data->ce_map & (0x01 << i)) {
6389 n += scnprintf(
6390 reply + n,
6391 MAX_USER_COMMAND_SIZE - n,
6392 "#%d: id: %d, scale=%d\n",
6393 i,
6394 napi_data->napis[i].id,
6395 napi_data->napis[i].scale);
6396 }
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006397 status_end:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006398 hdd_info("wlan: STATUS DATA:\n%s", reply);
6399 if (copy_to_user(priv_data->buf, reply,
Anurag Chouhan6d760662016-02-20 16:05:43 +05306400 QDF_MIN(n, priv_data->total_len)))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006401 rc = -EINVAL;
6402 } else if (!strcmp(subcmd, "STATS")) {
6403 int n = 0;
6404 struct qca_napi_data *napi_data;
6405
6406 napi_data = hdd_napi_get_all();
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006407 if (NULL != napi_data) {
6408 n = hdd_napi_stats(reply, MAX_USER_COMMAND_SIZE,
6409 aux, napi_data);
6410 NAPI_DEBUG("STATS: returns %d\n", n);
6411 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006412 if (n > 0) {
6413 if (copy_to_user(priv_data->buf, reply,
Anurag Chouhan6d760662016-02-20 16:05:43 +05306414 QDF_MIN(priv_data->total_len,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006415 n)))
6416 rc = -EINVAL;
6417 hdd_info("wlan: STATS_DATA\n%s\n", reply);
6418 } else
6419 rc = -EINVAL;
6420 } else if (!strcmp(subcmd, "SCALE")) {
6421 if (NULL == aux) {
6422 rc = -EINVAL;
6423 hdd_err("wlan: SCALE cmd requires <n>");
6424 } else {
6425 uint8_t sc;
6426 rc = kstrtou8(aux, 10, &sc);
6427 if (rc) {
6428 hdd_err("wlan: bad scale (%s)", aux);
6429 rc = -EINVAL;
6430 } else
6431 napi_set_scale(sc);
6432 }
6433 } /* SCALE */
6434 }
6435end_drv_napi:
6436 if (NULL != str)
6437 kfree(str);
6438 if (NULL != reply)
6439 kfree(reply);
6440
6441 NAPI_DEBUG("<--[rc=%d]\n", rc);
6442 return rc;
6443}
6444#endif /* FEATURE_NAPI */
6445
6446/**
6447 * hdd_set_rx_filter() - set RX filter
6448 * @adapter: Pointer to adapter
6449 * @action: Filter action
6450 * @pattern: Address pattern
6451 *
6452 * Address pattern is most significant byte of address for example
6453 * 0x01 for IPV4 multicast address
6454 * 0x33 for IPV6 multicast address
6455 * 0xFF for broadcast address
6456 *
6457 * Return: 0 for success, non-zero for failure
6458 */
6459static int hdd_set_rx_filter(hdd_adapter_t *adapter, bool action,
6460 uint8_t pattern)
6461{
6462 int ret;
Frank Liuf95e8132016-09-29 19:01:30 +08006463 uint8_t i, j;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006464 tHalHandle handle;
6465 tSirRcvFltMcAddrList *filter;
6466 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
6467
6468 ret = wlan_hdd_validate_context(hdd_ctx);
6469 if (0 != ret)
6470 return ret;
6471
6472 handle = hdd_ctx->hHal;
6473
6474 if (NULL == handle) {
6475 hdd_err("HAL Handle is NULL");
6476 return -EINVAL;
6477 }
6478
Mukul Sharma3a1ab302017-01-15 19:02:37 +05306479 if (!hdd_ctx->config->fEnableMCAddrList) {
6480 hdd_notice("mc addr ini is disabled");
6481 return -EINVAL;
6482 }
6483
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006484 /*
6485 * If action is false it means start dropping packets
6486 * Set addr_filter_pattern which will be used when sending
6487 * MC/BC address list to target
6488 */
6489 if (!action)
6490 adapter->addr_filter_pattern = pattern;
6491 else
6492 adapter->addr_filter_pattern = 0;
6493
Krunal Sonibe766b02016-03-10 13:00:44 -08006494 if (((adapter->device_mode == QDF_STA_MODE) ||
6495 (adapter->device_mode == QDF_P2P_CLIENT_MODE)) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006496 adapter->mc_addr_list.mc_cnt &&
6497 hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
6498
6499
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306500 filter = qdf_mem_malloc(sizeof(*filter));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006501 if (NULL == filter) {
6502 hdd_err("Could not allocate Memory");
6503 return -ENOMEM;
6504 }
6505 filter->action = action;
Frank Liuf95e8132016-09-29 19:01:30 +08006506 for (i = 0, j = 0; i < adapter->mc_addr_list.mc_cnt; i++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006507 if (!memcmp(adapter->mc_addr_list.addr[i],
6508 &pattern, 1)) {
Frank Liuf95e8132016-09-29 19:01:30 +08006509 memcpy(filter->multicastAddr[j].bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006510 adapter->mc_addr_list.addr[i],
6511 sizeof(adapter->mc_addr_list.addr[i]));
Frank Liuf95e8132016-09-29 19:01:30 +08006512
Srinivas Girigowdaf2599dd2015-11-16 18:20:46 -08006513 hdd_info("%s RX filter : addr ="
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006514 MAC_ADDRESS_STR,
6515 action ? "setting" : "clearing",
Frank Liuf95e8132016-09-29 19:01:30 +08006516 MAC_ADDR_ARRAY(filter->multicastAddr[j].bytes));
6517 j++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006518 }
6519 }
Frank Liuf95e8132016-09-29 19:01:30 +08006520 filter->ulMulticastAddrCnt = j;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006521 /* Set rx filter */
6522 sme_8023_multicast_list(handle, adapter->sessionId, filter);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306523 qdf_mem_free(filter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006524 } else {
Srinivas Girigowdaf2599dd2015-11-16 18:20:46 -08006525 hdd_info("mode %d mc_cnt %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006526 adapter->device_mode, adapter->mc_addr_list.mc_cnt);
6527 }
6528
6529 return 0;
6530}
6531
6532/**
6533 * hdd_driver_rxfilter_comand_handler() - RXFILTER driver command handler
6534 * @command: Pointer to input string driver command
6535 * @adapter: Pointer to adapter
6536 * @action: Action to enable/disable filtering
6537 *
6538 * If action == false
6539 * Start filtering out data packets based on type
6540 * RXFILTER-REMOVE 0 -> Start filtering out unicast data packets
6541 * RXFILTER-REMOVE 1 -> Start filtering out broadcast data packets
6542 * RXFILTER-REMOVE 2 -> Start filtering out IPV4 mcast data packets
6543 * RXFILTER-REMOVE 3 -> Start filtering out IPV6 mcast data packets
6544 *
6545 * if action == true
6546 * Stop filtering data packets based on type
6547 * RXFILTER-ADD 0 -> Stop filtering unicast data packets
6548 * RXFILTER-ADD 1 -> Stop filtering broadcast data packets
6549 * RXFILTER-ADD 2 -> Stop filtering IPV4 mcast data packets
6550 * RXFILTER-ADD 3 -> Stop filtering IPV6 mcast data packets
6551 *
6552 * Current implementation only supports IPV4 address filtering by
6553 * selectively allowing IPV4 multicast data packest based on
6554 * address list received in .ndo_set_rx_mode
6555 *
6556 * Return: 0 for success, non-zero for failure
6557 */
6558static int hdd_driver_rxfilter_comand_handler(uint8_t *command,
6559 hdd_adapter_t *adapter,
6560 bool action)
6561{
6562 int ret = 0;
6563 uint8_t *value;
6564 uint8_t type;
6565
6566 value = command;
6567 /* Skip space after RXFILTER-REMOVE OR RXFILTER-ADD based on action */
6568 if (!action)
6569 value = command + 16;
6570 else
6571 value = command + 13;
6572 ret = kstrtou8(value, 10, &type);
6573 if (ret < 0) {
6574 hdd_err("kstrtou8 failed invalid input value %d", type);
6575 return -EINVAL;
6576 }
6577
6578 switch (type) {
6579 case 2:
6580 /* Set rx filter for IPV4 multicast data packets */
6581 ret = hdd_set_rx_filter(adapter, action, 0x01);
6582 break;
6583 default:
6584 hdd_info("Unsupported RXFILTER type %d", type);
6585 break;
6586 }
6587
6588 return ret;
6589}
6590
6591/**
6592 * drv_cmd_rx_filter_remove() - RXFILTER REMOVE driver command handler
6593 * @adapter: Pointer to network adapter
6594 * @hdd_ctx: Pointer to hdd context
6595 * @command: Pointer to input command
6596 * @command_len: Command length
6597 * @priv_data: Pointer to private data in command
6598 */
6599static int drv_cmd_rx_filter_remove(hdd_adapter_t *adapter,
6600 hdd_context_t *hdd_ctx,
6601 uint8_t *command,
6602 uint8_t command_len,
6603 hdd_priv_data_t *priv_data)
6604{
6605 return hdd_driver_rxfilter_comand_handler(command, adapter, false);
6606}
6607
6608/**
6609 * drv_cmd_rx_filter_add() - RXFILTER ADD driver command handler
6610 * @adapter: Pointer to network adapter
6611 * @hdd_ctx: Pointer to hdd context
6612 * @command: Pointer to input command
6613 * @command_len: Command length
6614 * @priv_data: Pointer to private data in command
6615 */
6616static int drv_cmd_rx_filter_add(hdd_adapter_t *adapter,
6617 hdd_context_t *hdd_ctx,
6618 uint8_t *command,
6619 uint8_t command_len,
6620 hdd_priv_data_t *priv_data)
6621{
6622 return hdd_driver_rxfilter_comand_handler(command, adapter, true);
6623}
6624
Archana Ramachandran393f3792015-11-13 17:13:21 -08006625/**
6626 * hdd_parse_setantennamode_command() - HDD Parse SETANTENNAMODE
6627 * command
6628 * @value: Pointer to SETANTENNAMODE command
6629 * @mode: Pointer to antenna mode
6630 * @reason: Pointer to reason for set antenna mode
6631 *
6632 * This function parses the SETANTENNAMODE command passed in the format
6633 * SETANTENNAMODE<space>mode
6634 *
6635 * Return: 0 for success non-zero for failure
6636 */
6637static int hdd_parse_setantennamode_command(const uint8_t *value)
6638{
6639 const uint8_t *in_ptr = value;
6640 int tmp, v;
6641 char arg1[32];
6642
6643 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
6644
6645 /* no argument after the command */
6646 if (NULL == in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006647 hdd_err("No argument after the command");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006648 return -EINVAL;
6649 }
6650
6651 /* no space after the command */
6652 if (SPACE_ASCII_VALUE != *in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006653 hdd_err("No space after the command");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006654 return -EINVAL;
6655 }
6656
6657 /* remove empty spaces */
6658 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
6659 in_ptr++;
6660
6661 /* no argument followed by spaces */
6662 if ('\0' == *in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006663 hdd_err("No argument followed by spaces");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006664 return -EINVAL;
6665 }
6666
6667 /* get the argument i.e. antenna mode */
6668 v = sscanf(in_ptr, "%31s ", arg1);
6669 if (1 != v) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006670 hdd_err("argument retrieval from cmd string failed");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006671 return -EINVAL;
6672 }
6673
6674 v = kstrtos32(arg1, 10, &tmp);
6675 if (v < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006676 hdd_err("argument string to int conversion failed");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006677 return -EINVAL;
6678 }
6679
6680 return tmp;
6681}
6682
6683/**
6684 * hdd_is_supported_chain_mask_2x2() - Verify if supported chain
6685 * mask is 2x2 mode
6686 * @hdd_ctx: Pointer to hdd contex
6687 *
6688 * Return: true if supported chain mask 2x2 else false
6689 */
6690static bool hdd_is_supported_chain_mask_2x2(hdd_context_t *hdd_ctx)
6691{
6692 /*
6693 * Revisit and the update logic to determine the number
6694 * of TX/RX chains supported in the system when
6695 * antenna sharing per band chain mask support is
6696 * brought in
6697 */
6698 return (hdd_ctx->config->enable2x2 == 0x01) ? true : false;
6699}
6700
6701/**
6702 * hdd_is_supported_chain_mask_1x1() - Verify if the supported
6703 * chain mask is 1x1
6704 * @hdd_ctx: Pointer to hdd contex
6705 *
6706 * Return: true if supported chain mask 1x1 else false
6707 */
6708static bool hdd_is_supported_chain_mask_1x1(hdd_context_t *hdd_ctx)
6709{
6710 /*
6711 * Revisit and update the logic to determine the number
6712 * of TX/RX chains supported in the system when
6713 * antenna sharing per band chain mask support is
6714 * brought in
6715 */
6716 return (!hdd_ctx->config->enable2x2) ? true : false;
6717}
6718
6719/**
6720 * drv_cmd_set_antenna_mode() - SET ANTENNA MODE driver command
6721 * handler
6722 * @adapter: Pointer to network adapter
6723 * @hdd_ctx: Pointer to hdd context
6724 * @command: Pointer to input command
6725 * @command_len: Command length
6726 * @priv_data: Pointer to private data in command
6727 */
6728static int drv_cmd_set_antenna_mode(hdd_adapter_t *adapter,
6729 hdd_context_t *hdd_ctx,
6730 uint8_t *command,
6731 uint8_t command_len,
6732 hdd_priv_data_t *priv_data)
6733{
6734 struct sir_antenna_mode_param params;
6735 QDF_STATUS status;
6736 int ret = 0;
6737 int mode;
6738 uint8_t *value = command;
6739 uint8_t smps_mode;
6740 uint8_t smps_enable;
6741
6742 if (((1 << QDF_STA_MODE) != hdd_ctx->concurrency_mode) ||
6743 (hdd_ctx->no_of_active_sessions[QDF_STA_MODE] > 1)) {
6744 hdd_err("Operation invalid in non sta or concurrent mode");
6745 ret = -EPERM;
6746 goto exit;
6747 }
6748
6749 mode = hdd_parse_setantennamode_command(value);
6750 if (mode < 0) {
6751 hdd_err("Invalid SETANTENNA command");
6752 ret = mode;
6753 goto exit;
6754 }
6755
6756 hdd_info("Processing antenna mode switch to: %d", mode);
6757
6758 if (hdd_ctx->current_antenna_mode == mode) {
6759 hdd_err("System already in the requested mode");
6760 ret = 0;
6761 goto exit;
6762 }
6763
6764 if ((HDD_ANTENNA_MODE_2X2 == mode) &&
6765 (!hdd_is_supported_chain_mask_2x2(hdd_ctx))) {
6766 hdd_err("System does not support 2x2 mode");
6767 ret = -EPERM;
6768 goto exit;
6769 }
6770
6771 if ((HDD_ANTENNA_MODE_1X1 == mode) &&
6772 hdd_is_supported_chain_mask_1x1(hdd_ctx)) {
6773 hdd_err("System only supports 1x1 mode");
6774 ret = 0;
6775 goto exit;
6776 }
6777
6778 switch (mode) {
6779 case HDD_ANTENNA_MODE_1X1:
6780 params.num_rx_chains = 1;
6781 params.num_tx_chains = 1;
6782 break;
6783 case HDD_ANTENNA_MODE_2X2:
6784 params.num_rx_chains = 2;
6785 params.num_tx_chains = 2;
6786 break;
6787 default:
6788 hdd_err("unsupported antenna mode");
6789 ret = -EINVAL;
6790 goto exit;
6791 }
6792
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006793 /* Check TDLS status and update antenna mode */
6794 if ((QDF_STA_MODE == adapter->device_mode) &&
Kabilan Kannan32eb5022016-10-04 12:24:50 -07006795 cds_is_sta_active_connection_exists()) {
Archana Ramachandran2ad7de22016-04-22 16:53:25 -07006796 ret = wlan_hdd_tdls_antenna_switch(hdd_ctx, adapter,
6797 mode);
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006798 if (0 != ret)
6799 goto exit;
6800 }
6801
Archana Ramachandran393f3792015-11-13 17:13:21 -08006802 params.set_antenna_mode_resp =
6803 (void *)wlan_hdd_soc_set_antenna_mode_cb;
6804 hdd_info("Set antenna mode rx chains: %d tx chains: %d",
6805 params.num_rx_chains,
6806 params.num_tx_chains);
6807
6808
6809 INIT_COMPLETION(hdd_ctx->set_antenna_mode_cmpl);
6810 status = sme_soc_set_antenna_mode(hdd_ctx->hHal, &params);
6811 if (QDF_STATUS_SUCCESS != status) {
6812 hdd_err("set antenna mode failed status : %d", status);
6813 ret = -EFAULT;
6814 goto exit;
6815 }
6816
6817 ret = wait_for_completion_timeout(
6818 &hdd_ctx->set_antenna_mode_cmpl,
6819 msecs_to_jiffies(WLAN_WAIT_TIME_ANTENNA_MODE_REQ));
6820 if (!ret) {
6821 ret = -EFAULT;
6822 hdd_err("send set antenna mode timed out");
6823 goto exit;
6824 }
6825
6826 /* Update SME SMPS config */
6827 if (HDD_ANTENNA_MODE_1X1 == mode) {
6828 smps_enable = true;
6829 smps_mode = HDD_SMPS_MODE_STATIC;
6830 } else {
6831 smps_enable = false;
6832 smps_mode = HDD_SMPS_MODE_DISABLED;
6833 }
6834
6835 hdd_info("Update SME SMPS enable: %d mode: %d",
6836 smps_enable, smps_mode);
6837 status = sme_update_mimo_power_save(
6838 hdd_ctx->hHal, smps_enable, smps_mode, false);
6839 if (QDF_STATUS_SUCCESS != status) {
6840 hdd_err("Update SMPS config failed enable: %d mode: %d status: %d",
6841 smps_enable, smps_mode, status);
6842 ret = -EFAULT;
6843 goto exit;
6844 }
6845
Archana Ramachandran393f3792015-11-13 17:13:21 -08006846 hdd_ctx->current_antenna_mode = mode;
Archana Ramachandran5041b252016-04-25 14:29:25 -07006847 /* Update the user requested nss in the mac context.
6848 * This will be used in tdls protocol engine to form tdls
6849 * Management frames.
6850 */
6851 sme_update_user_configured_nss(
6852 hdd_ctx->hHal,
6853 hdd_ctx->current_antenna_mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006854
Archana Ramachandran5041b252016-04-25 14:29:25 -07006855 hdd_info("Successfully switched to mode: %d x %d",
6856 hdd_ctx->current_antenna_mode,
6857 hdd_ctx->current_antenna_mode);
6858 ret = 0;
Archana Ramachandran393f3792015-11-13 17:13:21 -08006859exit:
Kabilan Kannanff89f742016-08-15 18:14:10 -07006860#ifdef FEATURE_WLAN_TDLS
6861 /* Reset tdls NSS flags */
6862 if (hdd_ctx->tdls_nss_switch_in_progress &&
6863 hdd_ctx->tdls_nss_teardown_complete) {
6864 hdd_ctx->tdls_nss_switch_in_progress = false;
6865 hdd_ctx->tdls_nss_teardown_complete = false;
6866 }
6867 hdd_info("tdls_nss_switch_in_progress: %d tdls_nss_teardown_complete: %d",
6868 hdd_ctx->tdls_nss_switch_in_progress,
6869 hdd_ctx->tdls_nss_teardown_complete);
6870#endif
Archana Ramachandran393f3792015-11-13 17:13:21 -08006871 hdd_info("Set antenna status: %d current mode: %d",
6872 ret, hdd_ctx->current_antenna_mode);
6873 return ret;
6874
6875}
6876
6877/**
6878 * drv_cmd_get_antenna_mode() - GET ANTENNA MODE driver command
6879 * handler
6880 * @adapter: Pointer to hdd adapter
6881 * @hdd_ctx: Pointer to hdd context
6882 * @command: Pointer to input command
6883 * @command_len: length of the command
6884 * @priv_data: private data coming with the driver command
6885 *
6886 * Return: 0 for success non-zero for failure
6887 */
6888static inline int drv_cmd_get_antenna_mode(hdd_adapter_t *adapter,
6889 hdd_context_t *hdd_ctx,
6890 uint8_t *command,
6891 uint8_t command_len,
6892 hdd_priv_data_t *priv_data)
6893{
6894 uint32_t antenna_mode = 0;
6895 char extra[32];
6896 uint8_t len = 0;
6897
6898 antenna_mode = hdd_ctx->current_antenna_mode;
6899 len = scnprintf(extra, sizeof(extra), "%s %d", command,
6900 antenna_mode);
6901 len = QDF_MIN(priv_data->total_len, len + 1);
6902 if (copy_to_user(priv_data->buf, &extra, len)) {
6903 hdd_err("Failed to copy data to user buffer");
6904 return -EFAULT;
6905 }
6906
6907 hdd_info("Get antenna mode: %d", antenna_mode);
6908
6909 return 0;
6910}
6911
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006912/*
6913 * dummy (no-op) hdd driver command handler
6914 */
6915static int drv_cmd_dummy(hdd_adapter_t *adapter,
6916 hdd_context_t *hdd_ctx,
6917 uint8_t *command,
6918 uint8_t command_len,
6919 hdd_priv_data_t *priv_data)
6920{
6921 hdd_info("%s: Ignoring driver command \"%s\"",
6922 adapter->dev->name, command);
6923 return 0;
6924}
6925
6926/*
6927 * handler for any unsupported wlan hdd driver command
6928 */
6929static int drv_cmd_invalid(hdd_adapter_t *adapter,
6930 hdd_context_t *hdd_ctx,
6931 uint8_t *command,
6932 uint8_t command_len,
6933 hdd_priv_data_t *priv_data)
6934{
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306935 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006936 TRACE_CODE_HDD_UNSUPPORTED_IOCTL,
6937 adapter->sessionId, 0));
6938
6939 hdd_warn("%s: Unsupported driver command \"%s\"",
6940 adapter->dev->name, command);
6941
6942 return -ENOTSUPP;
6943}
6944
6945/**
6946 * drv_cmd_set_fcc_channel() - handle fcc constraint request
6947 * @adapter: HDD adapter
6948 * @hdd_ctx: HDD context
6949 * @command: command ptr, SET_FCC_CHANNEL 0/1 is the command
6950 * @command_len: command len
6951 * @priv_data: private data
6952 *
6953 * Return: status
6954 */
6955static int drv_cmd_set_fcc_channel(hdd_adapter_t *adapter,
6956 hdd_context_t *hdd_ctx,
6957 uint8_t *command,
6958 uint8_t command_len,
6959 hdd_priv_data_t *priv_data)
6960{
6961 uint8_t *value;
6962 uint8_t fcc_constraint;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306963 QDF_STATUS status;
Amar Singhal83a047a2016-05-19 15:56:11 -07006964 bool scan_pending;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006965 int ret = 0;
6966
6967 /*
6968 * this command would be called by user-space when it detects WLAN
6969 * ON after airplane mode is set. When APM is set, WLAN turns off.
6970 * But it can be turned back on. Otherwise; when APM is turned back
6971 * off, WLAN would turn back on. So at that point the command is
6972 * expected to come down. 0 means disable, 1 means enable. The
6973 * constraint is removed when parameter 1 is set or different
6974 * country code is set
6975 */
6976
6977 value = command + command_len + 1;
6978
6979 ret = kstrtou8(value, 10, &fcc_constraint);
6980 if ((ret < 0) || (fcc_constraint > 1)) {
6981 /*
6982 * If the input value is greater than max value of datatype,
6983 * then also it is a failure
6984 */
6985 hdd_err("value out of range");
6986 return -EINVAL;
6987 }
6988
Amar Singhal83a047a2016-05-19 15:56:11 -07006989 scan_pending = !qdf_list_empty(&hdd_ctx->hdd_scan_req_q);
6990 status = sme_handle_set_fcc_channel(hdd_ctx->hHal, !fcc_constraint,
6991 scan_pending);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306992 if (status != QDF_STATUS_SUCCESS) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006993 hdd_err("sme disable fn. returned err");
6994 ret = -EPERM;
6995 }
6996
6997 return ret;
6998}
6999
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307000/**
7001 * hdd_parse_set_channel_switch_command() - Parse and validate CHANNEL_SWITCH
7002 * command
7003 * @value: Pointer to the command
7004 * @chan_number: Pointer to the channel number
7005 * @chan_bw: Pointer to the channel bandwidth
7006 *
7007 * Parses and provides the channel number and channel width from the input
7008 * command which is expected to be of the format: CHANNEL_SWITCH <CH> <BW>
7009 * <CH> is channel number to move (where 1 = channel 1, 149 = channel 149, ...)
7010 * <BW> is bandwidth to move (where 20 = BW 20, 40 = BW 40, 80 = BW 80)
7011 *
7012 * Return: 0 for success, non-zero for failure
7013 */
7014static int hdd_parse_set_channel_switch_command(uint8_t *value,
7015 uint32_t *chan_number,
7016 uint32_t *chan_bw)
7017{
7018 const uint8_t *in_ptr = value;
7019 int ret;
7020
7021 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
7022
7023 /* no argument after the command */
7024 if (NULL == in_ptr) {
7025 hdd_err("No argument after the command");
7026 return -EINVAL;
7027 }
7028
7029 /* no space after the command */
7030 if (SPACE_ASCII_VALUE != *in_ptr) {
7031 hdd_err("No space after the command ");
7032 return -EINVAL;
7033 }
7034
7035 /* remove empty spaces and move the next argument */
7036 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
7037 in_ptr++;
7038
7039 /* no argument followed by spaces */
7040 if ('\0' == *in_ptr) {
7041 hdd_err("No argument followed by spaces");
7042 return -EINVAL;
7043 }
7044
7045 /* get the two arguments: channel number and bandwidth */
7046 ret = sscanf(in_ptr, "%u %u", chan_number, chan_bw);
7047 if (ret != 2) {
7048 hdd_err("Arguments retrieval from cmd string failed");
7049 return -EINVAL;
7050 }
7051
7052 return 0;
7053}
7054
7055/**
7056 * drv_cmd_set_channel_switch() - Switch SAP/P2P-GO operating channel
7057 * @adapter: HDD adapter
7058 * @hdd_ctx: HDD context
7059 * @command: Pointer to the input command CHANNEL_SWITCH
7060 * @command_len: Command len
7061 * @priv_data: Private data
7062 *
7063 * Handles private IOCTL CHANNEL_SWITCH command to switch the operating channel
7064 * of SAP/P2P-GO
7065 *
7066 * Return: 0 for success, non-zero for failure
7067 */
7068static int drv_cmd_set_channel_switch(hdd_adapter_t *adapter,
7069 hdd_context_t *hdd_ctx,
7070 uint8_t *command,
7071 uint8_t command_len,
7072 hdd_priv_data_t *priv_data)
7073{
7074 struct net_device *dev = adapter->dev;
7075 int status;
7076 uint32_t chan_number = 0, chan_bw = 0;
7077 uint8_t *value = command;
Kiran Kumar Lokere13644672016-02-29 15:40:10 -08007078 enum phy_ch_width width;
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307079
Krunal Sonibe766b02016-03-10 13:00:44 -08007080 if ((adapter->device_mode != QDF_P2P_GO_MODE) &&
7081 (adapter->device_mode != QDF_SAP_MODE)) {
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307082 hdd_err("IOCTL CHANNEL_SWITCH not supported for mode %d",
7083 adapter->device_mode);
7084 return -EINVAL;
7085 }
7086
7087 status = hdd_parse_set_channel_switch_command(value,
7088 &chan_number, &chan_bw);
7089 if (status) {
7090 hdd_err("Invalid CHANNEL_SWITCH command");
7091 return status;
7092 }
7093
7094 if ((chan_bw != 20) && (chan_bw != 40) && (chan_bw != 80)) {
7095 hdd_err("BW %d is not allowed for CHANNEL_SWITCH", chan_bw);
7096 return -EINVAL;
7097 }
7098
7099 if (chan_bw == 80)
7100 width = CH_WIDTH_80MHZ;
7101 else if (chan_bw == 40)
7102 width = CH_WIDTH_40MHZ;
7103 else
7104 width = CH_WIDTH_20MHZ;
7105
7106 hdd_info("CH:%d BW:%d", chan_number, chan_bw);
7107
7108 status = hdd_softap_set_channel_change(dev, chan_number, width);
7109 if (status) {
7110 hdd_err("Set channel change fail");
7111 return status;
7112 }
7113
7114 return 0;
7115}
7116
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007117/*
7118 * The following table contains all supported WLAN HDD
7119 * IOCTL driver commands and the handler for each of them.
7120 */
7121static const hdd_drv_cmd_t hdd_drv_cmds[] = {
7122 {"P2P_DEV_ADDR", drv_cmd_p2p_dev_addr},
7123 {"P2P_SET_NOA", drv_cmd_p2p_set_noa},
7124 {"P2P_SET_PS", drv_cmd_p2p_set_ps},
7125 {"SETBAND", drv_cmd_set_band},
7126 {"SETWMMPS", drv_cmd_set_wmmps},
7127 {"COUNTRY", drv_cmd_country},
7128 {"SETSUSPENDMODE", drv_cmd_dummy},
7129 {"SET_AP_WPS_P2P_IE", drv_cmd_dummy},
7130 {"BTCOEXSCAN", drv_cmd_dummy},
7131 {"RXFILTER", drv_cmd_dummy},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007132 {"SETROAMTRIGGER", drv_cmd_set_roam_trigger},
7133 {"GETROAMTRIGGER", drv_cmd_get_roam_trigger},
7134 {"SETROAMSCANPERIOD", drv_cmd_set_roam_scan_period},
7135 {"GETROAMSCANPERIOD", drv_cmd_get_roam_scan_period},
7136 {"SETROAMSCANREFRESHPERIOD", drv_cmd_set_roam_scan_refresh_period},
7137 {"GETROAMSCANREFRESHPERIOD", drv_cmd_get_roam_scan_refresh_period},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007138 {"SETROAMMODE", drv_cmd_set_roam_mode},
7139 {"GETROAMMODE", drv_cmd_get_roam_mode},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007140 {"SETROAMDELTA", drv_cmd_set_roam_delta},
7141 {"GETROAMDELTA", drv_cmd_get_roam_delta},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007142 {"GETBAND", drv_cmd_get_band},
7143 {"SETROAMSCANCHANNELS", drv_cmd_set_roam_scan_channels},
7144 {"GETROAMSCANCHANNELS", drv_cmd_get_roam_scan_channels},
7145 {"GETCCXMODE", drv_cmd_get_ccx_mode},
7146 {"GETOKCMODE", drv_cmd_get_okc_mode},
7147 {"GETFASTROAM", drv_cmd_get_fast_roam},
7148 {"GETFASTTRANSITION", drv_cmd_get_fast_transition},
7149 {"SETROAMSCANCHANNELMINTIME", drv_cmd_set_roam_scan_channel_min_time},
7150 {"SENDACTIONFRAME", drv_cmd_send_action_frame},
7151 {"GETROAMSCANCHANNELMINTIME", drv_cmd_get_roam_scan_channel_min_time},
7152 {"SETSCANCHANNELTIME", drv_cmd_set_scan_channel_time},
7153 {"GETSCANCHANNELTIME", drv_cmd_get_scan_channel_time},
7154 {"SETSCANHOMETIME", drv_cmd_set_scan_home_time},
7155 {"GETSCANHOMETIME", drv_cmd_get_scan_home_time},
7156 {"SETROAMINTRABAND", drv_cmd_set_roam_intra_band},
7157 {"GETROAMINTRABAND", drv_cmd_get_roam_intra_band},
7158 {"SETSCANNPROBES", drv_cmd_set_scan_n_probes},
7159 {"GETSCANNPROBES", drv_cmd_get_scan_n_probes},
7160 {"SETSCANHOMEAWAYTIME", drv_cmd_set_scan_home_away_time},
7161 {"GETSCANHOMEAWAYTIME", drv_cmd_get_scan_home_away_time},
7162 {"REASSOC", drv_cmd_reassoc},
7163 {"SETWESMODE", drv_cmd_set_wes_mode},
7164 {"GETWESMODE", drv_cmd_get_wes_mode},
7165 {"SETOPPORTUNISTICRSSIDIFF", drv_cmd_set_opportunistic_rssi_diff},
7166 {"GETOPPORTUNISTICRSSIDIFF", drv_cmd_get_opportunistic_rssi_diff},
7167 {"SETROAMRESCANRSSIDIFF", drv_cmd_set_roam_rescan_rssi_diff},
7168 {"GETROAMRESCANRSSIDIFF", drv_cmd_get_roam_rescan_rssi_diff},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007169 {"SETFASTROAM", drv_cmd_set_fast_roam},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007170 {"SETFASTTRANSITION", drv_cmd_set_fast_transition},
7171 {"FASTREASSOC", drv_cmd_fast_reassoc},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007172 {"SETROAMSCANCONTROL", drv_cmd_set_roam_scan_control},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007173 {"SETOKCMODE", drv_cmd_set_okc_mode},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007174 {"GETROAMSCANCONTROL", drv_cmd_get_roam_scan_control},
7175 {"BTCOEXMODE", drv_cmd_bt_coex_mode},
7176 {"SCAN-ACTIVE", drv_cmd_scan_active},
7177 {"SCAN-PASSIVE", drv_cmd_scan_passive},
7178 {"GETDWELLTIME", drv_cmd_get_dwell_time},
7179 {"SETDWELLTIME", drv_cmd_set_dwell_time},
7180 {"MIRACAST", drv_cmd_miracast},
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08007181 {"SETIBSSBEACONOUIDATA", drv_cmd_set_ibss_beacon_oui_data},
7182 {"SETRMCENABLE", drv_cmd_set_rmc_enable},
7183 {"SETRMCACTIONPERIOD", drv_cmd_set_rmc_action_period},
7184 {"GETIBSSPEERINFOALL", drv_cmd_get_ibss_peer_info_all},
7185 {"GETIBSSPEERINFO", drv_cmd_get_ibss_peer_info},
7186 {"SETRMCTXRATE", drv_cmd_set_rmc_tx_rate},
7187 {"SETIBSSTXFAILEVENT", drv_cmd_set_ibss_tx_fail_event},
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08007188#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007189 {"SETCCXROAMSCANCHANNELS", drv_cmd_set_ccx_roam_scan_channels},
7190 {"GETTSMSTATS", drv_cmd_get_tsm_stats},
7191 {"SETCCKMIE", drv_cmd_set_cckm_ie},
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07007192 {"CCXBEACONREQ", drv_cmd_ccx_beacon_req},
7193 {"CCXPLMREQ", drv_cmd_ccx_plm_req},
7194 {"SETCCXMODE", drv_cmd_set_ccx_mode},
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08007195#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007196 {"SETMCRATE", drv_cmd_set_mc_rate},
7197 {"MAXTXPOWER", drv_cmd_max_tx_power},
7198 {"SETDFSSCANMODE", drv_cmd_set_dfs_scan_mode},
7199 {"GETDFSSCANMODE", drv_cmd_get_dfs_scan_mode},
7200 {"GETLINKSTATUS", drv_cmd_get_link_status},
7201#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
7202 {"ENABLEEXTWOW", drv_cmd_enable_ext_wow},
7203 {"SETAPP1PARAMS", drv_cmd_set_app1_params},
7204 {"SETAPP2PARAMS", drv_cmd_set_app2_params},
7205#endif
7206#ifdef FEATURE_WLAN_TDLS
7207 {"TDLSSECONDARYCHANNELOFFSET", drv_cmd_tdls_secondary_channel_offset},
7208 {"TDLSOFFCHANNELMODE", drv_cmd_tdls_off_channel_mode},
7209 {"TDLSOFFCHANNEL", drv_cmd_tdls_off_channel},
7210 {"TDLSSCAN", drv_cmd_tdls_scan},
7211#endif
7212 {"RSSI", drv_cmd_get_rssi},
7213 {"LINKSPEED", drv_cmd_get_linkspeed},
7214#ifdef FEATURE_NAPI
7215 {"NAPI", drv_cmd_napi},
7216#endif /* FEATURE_NAPI */
7217 {"RXFILTER-REMOVE", drv_cmd_rx_filter_remove},
7218 {"RXFILTER-ADD", drv_cmd_rx_filter_add},
7219 {"SET_FCC_CHANNEL", drv_cmd_set_fcc_channel},
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307220 {"CHANNEL_SWITCH", drv_cmd_set_channel_switch},
Archana Ramachandran393f3792015-11-13 17:13:21 -08007221 {"SETANTENNAMODE", drv_cmd_set_antenna_mode},
7222 {"GETANTENNAMODE", drv_cmd_get_antenna_mode},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007223};
7224
7225/**
7226 * hdd_drv_cmd_process() - chooses and runs the proper
7227 * handler based on the input command
7228 * @adapter: Pointer to the hdd adapter
7229 * @cmd: Pointer to the driver command
7230 * @priv_data: Pointer to the data associated with the command
7231 *
7232 * This function parses the input hdd driver command and runs
7233 * the proper handler
7234 *
7235 * Return: 0 for success non-zero for failure
7236 */
7237static int hdd_drv_cmd_process(hdd_adapter_t *adapter,
7238 uint8_t *cmd,
7239 hdd_priv_data_t *priv_data)
7240{
7241 hdd_context_t *hdd_ctx;
7242 int i;
7243 const int cmd_num_total = ARRAY_SIZE(hdd_drv_cmds);
7244 uint8_t *cmd_i = NULL;
7245 hdd_drv_cmd_handler_t handler = NULL;
7246 int len = 0;
7247
7248 if (!adapter || !cmd || !priv_data) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007249 hdd_err("at least 1 param is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007250 return -EINVAL;
7251 }
7252
7253 hdd_ctx = (hdd_context_t *)adapter->pHddCtx;
7254
7255 for (i = 0; i < cmd_num_total; i++) {
7256
7257 cmd_i = (uint8_t *)hdd_drv_cmds[i].cmd;
7258 handler = hdd_drv_cmds[i].handler;
7259 len = strlen(cmd_i);
7260
7261 if (!handler) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007262 hdd_err("no. %d handler is NULL", i);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007263 return -EINVAL;
7264 }
7265
7266 if (strncasecmp(cmd, cmd_i, len) == 0)
7267 return handler(adapter, hdd_ctx,
7268 cmd, len, priv_data);
7269 }
7270
7271 return drv_cmd_invalid(adapter, hdd_ctx, cmd, len, priv_data);
7272}
7273
7274/**
7275 * hdd_driver_command() - top level wlan hdd driver command handler
7276 * @adapter: Pointer to the hdd adapter
7277 * @priv_data: Pointer to the raw command data
7278 *
7279 * This function is the top level wlan hdd driver command handler. It
7280 * handles the command with the help of hdd_drv_cmd_process()
7281 *
7282 * Return: 0 for success non-zero for failure
7283 */
7284static int hdd_driver_command(hdd_adapter_t *adapter,
7285 hdd_priv_data_t *priv_data)
7286{
7287 uint8_t *command = NULL;
7288 int ret = 0;
7289
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307290 ENTER();
7291
Anurag Chouhan6d760662016-02-20 16:05:43 +05307292 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007293 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007294 return -EINVAL;
7295 }
7296
7297 /*
7298 * Note that valid pointers are provided by caller
7299 */
7300
7301 /* copy to local struct to avoid numerous changes to legacy code */
7302 if (priv_data->total_len <= 0 ||
7303 priv_data->total_len > WLAN_PRIV_DATA_MAX_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007304 hdd_warn("Invalid priv_data.total_len(%d)!!!",
7305 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007306 ret = -EINVAL;
7307 goto exit;
7308 }
7309
7310 /* Allocate +1 for '\0' */
7311 command = kmalloc(priv_data->total_len + 1, GFP_KERNEL);
7312 if (!command) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007313 hdd_err("failed to allocate memory");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007314 ret = -ENOMEM;
7315 goto exit;
7316 }
7317
7318 if (copy_from_user(command, priv_data->buf, priv_data->total_len)) {
7319 ret = -EFAULT;
7320 goto exit;
7321 }
7322
7323 /* Make sure the command is NUL-terminated */
7324 command[priv_data->total_len] = '\0';
7325
7326 hdd_info("%s: %s", adapter->dev->name, command);
7327 ret = hdd_drv_cmd_process(adapter, command, priv_data);
7328
7329exit:
7330 if (command)
7331 kfree(command);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307332 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007333 return ret;
7334}
7335
7336#ifdef CONFIG_COMPAT
7337static int hdd_driver_compat_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
7338{
7339 struct {
7340 compat_uptr_t buf;
7341 int used_len;
7342 int total_len;
7343 } compat_priv_data;
7344 hdd_priv_data_t priv_data;
7345 int ret = 0;
7346
7347 /*
7348 * Note that adapter and ifr have already been verified by caller,
7349 * and HDD context has also been validated
7350 */
7351 if (copy_from_user(&compat_priv_data, ifr->ifr_data,
7352 sizeof(compat_priv_data))) {
7353 ret = -EFAULT;
7354 goto exit;
7355 }
7356 priv_data.buf = compat_ptr(compat_priv_data.buf);
7357 priv_data.used_len = compat_priv_data.used_len;
7358 priv_data.total_len = compat_priv_data.total_len;
7359 ret = hdd_driver_command(adapter, &priv_data);
7360exit:
7361 return ret;
7362}
7363#else /* CONFIG_COMPAT */
7364static int hdd_driver_compat_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
7365{
7366 /* will never be invoked */
7367 return 0;
7368}
7369#endif /* CONFIG_COMPAT */
7370
7371static int hdd_driver_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
7372{
7373 hdd_priv_data_t priv_data;
7374 int ret = 0;
7375
7376 /*
7377 * Note that adapter and ifr have already been verified by caller,
7378 * and HDD context has also been validated
7379 */
7380 if (copy_from_user(&priv_data, ifr->ifr_data, sizeof(priv_data)))
7381 ret = -EFAULT;
7382 else
7383 ret = hdd_driver_command(adapter, &priv_data);
7384
7385 return ret;
7386}
7387
7388/**
7389 * __hdd_ioctl() - ioctl handler for wlan network interfaces
7390 * @dev: device upon which the ioctl was received
7391 * @ifr: ioctl request information
7392 * @cmd: ioctl command
7393 *
7394 * This function does initial processing of wlan device ioctls.
7395 * Currently two flavors of ioctls are supported. The primary ioctl
7396 * that is supported is the (SIOCDEVPRIVATE + 1) ioctl which is used
7397 * for Android "DRIVER" commands. The other ioctl that is
7398 * conditionally supported is the SIOCIOCTLTX99 ioctl which is used
7399 * for FTM on some platforms. This function simply verifies that the
7400 * driver is in a sane state, and that the ioctl is one of the
7401 * supported flavors, in which case flavor-specific handlers are
7402 * dispatched.
7403 *
7404 * Return: 0 on success, non-zero on error
7405 */
7406static int __hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7407{
7408 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
7409 hdd_context_t *hdd_ctx;
7410 int ret;
7411
Jeff Johnson3c3994a2016-02-11 08:12:30 -08007412 ENTER_DEV(dev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307413
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007414 if (dev != adapter->dev) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007415 hdd_alert("HDD adapter/dev inconsistency");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007416 ret = -ENODEV;
7417 goto exit;
7418 }
7419
7420 if ((!ifr) || (!ifr->ifr_data)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007421 hdd_err("invalid data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007422 ret = -EINVAL;
7423 goto exit;
7424 }
7425#if defined(QCA_WIFI_FTM) && defined(LINUX_QCMBR)
Anurag Chouhan6d760662016-02-20 16:05:43 +05307426 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007427 if (SIOCIOCTLTX99 == cmd) {
7428 ret = wlan_hdd_qcmbr_unified_ioctl(adapter, ifr);
7429 goto exit;
7430 }
7431 }
7432#endif
7433
7434 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
7435 ret = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307436 if (ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007437 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007438
7439 switch (cmd) {
7440 case (SIOCDEVPRIVATE + 1):
7441 if (is_compat_task())
7442 ret = hdd_driver_compat_ioctl(adapter, ifr);
7443 else
7444 ret = hdd_driver_ioctl(adapter, ifr);
7445 break;
7446 default:
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007447 hdd_err("unknown ioctl %d", cmd);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007448 ret = -EINVAL;
7449 break;
7450 }
7451exit:
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307452 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007453 return ret;
7454}
7455
7456/**
7457 * hdd_ioctl() - ioctl handler (wrapper) for wlan network interfaces
7458 * @dev: device upon which the ioctl was received
7459 * @ifr: ioctl request information
7460 * @cmd: ioctl command
7461 *
7462 * This function acts as an SSR-protecting wrapper to __hdd_ioctl()
7463 * which is where the ioctls are really handled.
7464 *
7465 * Return: 0 on success, non-zero on error
7466 */
7467int hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7468{
7469 int ret;
7470
7471 cds_ssr_protect(__func__);
7472 ret = __hdd_ioctl(dev, ifr, cmd);
7473 cds_ssr_unprotect(__func__);
7474 return ret;
7475}