blob: 6f7acb74517935cf56dc841b716c44185d6ccc03 [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{
Jeff Johnson68755312017-02-10 11:46:55 -08002248 int ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002249
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;
Jeff Johnson68755312017-02-10 11:46:55 -08002260 }
2261 if (strncmp(command, "GETDWELLTIME ACTIVE MIN", 23) == 0) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002262 *len = scnprintf(extra, n, "GETDWELLTIME ACTIVE MIN %u\n",
2263 (int)pCfg->nActiveMinChnTime);
2264 return ret;
Jeff Johnson68755312017-02-10 11:46:55 -08002265 }
2266 if (strncmp(command, "GETDWELLTIME PASSIVE MAX", 24) == 0) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002267 *len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MAX %u\n",
2268 (int)pCfg->nPassiveMaxChnTime);
2269 return ret;
Jeff Johnson68755312017-02-10 11:46:55 -08002270 }
2271 if (strncmp(command, "GETDWELLTIME PASSIVE MIN", 24) == 0) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002272 *len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MIN %u\n",
2273 (int)pCfg->nPassiveMinChnTime);
2274 return ret;
Jeff Johnson68755312017-02-10 11:46:55 -08002275 }
2276 if (strncmp(command, "GETDWELLTIME", 12) == 0) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002277 *len = scnprintf(extra, n, "GETDWELLTIME %u \n",
2278 (int)pCfg->nActiveMaxChnTime);
2279 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002280 }
Jeff Johnson68755312017-02-10 11:46:55 -08002281 ret = -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002282
2283 return ret;
2284}
2285
2286static int hdd_set_dwell_time(hdd_adapter_t *adapter, uint8_t *command)
2287{
2288 tHalHandle hHal;
2289 struct hdd_config *pCfg;
2290 uint8_t *value = command;
2291 tSmeConfigParams smeConfig;
2292 int val = 0, temp = 0;
2293
2294 pCfg = (WLAN_HDD_GET_CTX(adapter))->config;
2295 hHal = WLAN_HDD_GET_HAL_CTX(adapter);
2296 if (!pCfg || !hHal) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002297 hdd_err("argument passed for SETDWELLTIME is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002298 return -EINVAL;
2299 }
2300
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302301 qdf_mem_zero(&smeConfig, sizeof(smeConfig));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002302 sme_get_config_param(hHal, &smeConfig);
2303
2304 if (strncmp(command, "SETDWELLTIME ACTIVE MAX", 23) == 0) {
2305 value = value + 24;
2306 temp = kstrtou32(value, 10, &val);
2307 if (temp != 0 || val < CFG_ACTIVE_MAX_CHANNEL_TIME_MIN ||
2308 val > CFG_ACTIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002309 hdd_err("argument passed for SETDWELLTIME ACTIVE MAX is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002310 return -EFAULT;
2311 }
2312 pCfg->nActiveMaxChnTime = val;
2313 smeConfig.csrConfig.nActiveMaxChnTime = val;
2314 sme_update_config(hHal, &smeConfig);
2315 } else if (strncmp(command, "SETDWELLTIME ACTIVE MIN", 23) == 0) {
2316 value = value + 24;
2317 temp = kstrtou32(value, 10, &val);
2318 if (temp != 0 || val < CFG_ACTIVE_MIN_CHANNEL_TIME_MIN ||
2319 val > CFG_ACTIVE_MIN_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002320 hdd_err("argument passed for SETDWELLTIME ACTIVE MIN is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002321 return -EFAULT;
2322 }
2323 pCfg->nActiveMinChnTime = val;
2324 smeConfig.csrConfig.nActiveMinChnTime = val;
2325 sme_update_config(hHal, &smeConfig);
2326 } else if (strncmp(command, "SETDWELLTIME PASSIVE MAX", 24) == 0) {
2327 value = value + 25;
2328 temp = kstrtou32(value, 10, &val);
2329 if (temp != 0 || val < CFG_PASSIVE_MAX_CHANNEL_TIME_MIN ||
2330 val > CFG_PASSIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002331 hdd_err("argument passed for SETDWELLTIME PASSIVE MAX is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002332 return -EFAULT;
2333 }
2334 pCfg->nPassiveMaxChnTime = val;
2335 smeConfig.csrConfig.nPassiveMaxChnTime = val;
2336 sme_update_config(hHal, &smeConfig);
2337 } else if (strncmp(command, "SETDWELLTIME PASSIVE MIN", 24) == 0) {
2338 value = value + 25;
2339 temp = kstrtou32(value, 10, &val);
2340 if (temp != 0 || val < CFG_PASSIVE_MIN_CHANNEL_TIME_MIN ||
2341 val > CFG_PASSIVE_MIN_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002342 hdd_err("argument passed for SETDWELLTIME PASSIVE MIN is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002343 return -EFAULT;
2344 }
2345 pCfg->nPassiveMinChnTime = val;
2346 smeConfig.csrConfig.nPassiveMinChnTime = val;
2347 sme_update_config(hHal, &smeConfig);
2348 } else if (strncmp(command, "SETDWELLTIME", 12) == 0) {
2349 value = value + 13;
2350 temp = kstrtou32(value, 10, &val);
2351 if (temp != 0 || val < CFG_ACTIVE_MAX_CHANNEL_TIME_MIN ||
2352 val > CFG_ACTIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002353 hdd_err("argument passed for SETDWELLTIME is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002354 return -EFAULT;
2355 }
2356 pCfg->nActiveMaxChnTime = val;
2357 smeConfig.csrConfig.nActiveMaxChnTime = val;
2358 sme_update_config(hHal, &smeConfig);
2359 } else {
2360 return -EINVAL;
2361 }
2362
2363 return 0;
2364}
2365
2366static void hdd_get_link_status_cb(uint8_t status, void *context)
2367{
2368 struct statsContext *pLinkContext;
2369 hdd_adapter_t *adapter;
2370
2371 if (NULL == context) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002372 hdd_err("Bad context [%p]", context);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002373 return;
2374 }
2375
2376 pLinkContext = context;
2377 adapter = pLinkContext->pAdapter;
2378
2379 spin_lock(&hdd_context_lock);
2380
2381 if ((NULL == adapter) ||
2382 (LINK_STATUS_MAGIC != pLinkContext->magic)) {
2383 /*
2384 * the caller presumably timed out so there is
2385 * nothing we can do
2386 */
2387 spin_unlock(&hdd_context_lock);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002388 hdd_warn("Invalid context, adapter [%p] magic [%08x]",
2389 adapter, pLinkContext->magic);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002390 return;
2391 }
2392
2393 /* context is valid so caller is still waiting */
2394
2395 /* paranoia: invalidate the magic */
2396 pLinkContext->magic = 0;
2397
2398 /* copy over the status */
2399 adapter->linkStatus = status;
2400
2401 /* notify the caller */
2402 complete(&pLinkContext->completion);
2403
2404 /* serialization is complete */
2405 spin_unlock(&hdd_context_lock);
2406}
2407
2408/**
2409 * wlan_hdd_get_link_status() - get link status
2410 * @pAdapter: pointer to the adapter
2411 *
2412 * This function sends a request to query the link status and waits
2413 * on a timer to invoke the callback. if the callback is invoked then
2414 * latest link status shall be returned or otherwise cached value
2415 * will be returned.
2416 *
2417 * Return: On success, link status shall be returned.
2418 * On error or not associated, link status 0 will be returned.
2419 */
2420static int wlan_hdd_get_link_status(hdd_adapter_t *adapter)
2421{
2422
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002423 hdd_station_ctx_t *pHddStaCtx =
2424 WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Houston Hoffman59c097f2016-11-09 15:50:25 -08002425 static struct statsContext context;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302426 QDF_STATUS hstatus;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002427 unsigned long rc;
2428
Prashanth Bhatta9e143052015-12-04 11:56:47 -08002429 if (cds_is_driver_recovering()) {
2430 hdd_warn("Recovery in Progress. State: 0x%x Ignore!!!",
2431 cds_get_driver_state());
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002432 return 0;
2433 }
2434
Krunal Sonibe766b02016-03-10 13:00:44 -08002435 if ((QDF_STA_MODE != adapter->device_mode) &&
2436 (QDF_P2P_CLIENT_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002437 hdd_warn("Unsupported in mode %s(%d)",
2438 hdd_device_mode_to_string(adapter->device_mode),
2439 adapter->device_mode);
2440 return 0;
2441 }
2442
2443 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
2444 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
2445 /* If not associated, then expected link status return
2446 * value is 0
2447 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002448 hdd_info("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002449 return 0;
2450 }
2451
2452 init_completion(&context.completion);
2453 context.pAdapter = adapter;
2454 context.magic = LINK_STATUS_MAGIC;
2455 hstatus = sme_get_link_status(WLAN_HDD_GET_HAL_CTX(adapter),
2456 hdd_get_link_status_cb,
2457 &context, adapter->sessionId);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302458 if (QDF_STATUS_SUCCESS != hstatus) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002459 hdd_err("Unable to retrieve link status");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002460 /* return a cached value */
2461 } else {
2462 /* request is sent -- wait for the response */
2463 rc = wait_for_completion_timeout(&context.completion,
2464 msecs_to_jiffies(WLAN_WAIT_TIME_LINK_STATUS));
2465 if (!rc)
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002466 hdd_err("SME timed out while retrieving link status");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002467 }
2468
2469 spin_lock(&hdd_context_lock);
2470 context.magic = 0;
2471 spin_unlock(&hdd_context_lock);
2472
2473 /* either callback updated adapter stats or it has cached data */
2474 return adapter->linkStatus;
2475}
2476
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002477static void hdd_tx_fail_ind_callback(uint8_t *MacAddr, uint8_t seqNo)
2478{
2479 int payload_len;
2480 struct sk_buff *skb;
2481 struct nlmsghdr *nlh;
2482 uint8_t *data;
2483
2484 payload_len = ETH_ALEN;
2485
Ryan Hsu5e2e2052016-04-28 10:19:38 -07002486 if (0 == cesium_pid || cesium_nl_srv_sock == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002487 hdd_err("cesium process not registered");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002488 return;
2489 }
2490
2491 skb = nlmsg_new(payload_len, GFP_ATOMIC);
2492 if (skb == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002493 hdd_err("nlmsg_new() failed for msg size[%d]",
2494 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002495 return;
2496 }
2497
2498 nlh = nlmsg_put(skb, cesium_pid, seqNo, 0, payload_len, NLM_F_REQUEST);
2499
2500 if (NULL == nlh) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002501 hdd_err("nlmsg_put() failed for msg size[%d]",
2502 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002503
2504 kfree_skb(skb);
2505 return;
2506 }
2507
2508 data = nlmsg_data(nlh);
2509 memcpy(data, MacAddr, ETH_ALEN);
2510
2511 if (nlmsg_unicast(cesium_nl_srv_sock, skb, cesium_pid) < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002512 hdd_err("nlmsg_unicast() failed for msg size[%d]",
2513 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002514 }
2515
2516 return;
2517}
2518
2519
2520/**
2521 * hdd_ParseuserParams - return a pointer to the next argument
2522 * @pValue: Input argument string
2523 * @ppArg: Output pointer to the next argument
2524 *
2525 * This function parses argument stream and finds the pointer
2526 * to the next argument
2527 *
2528 * Return: 0 if the next argument found; -EINVAL otherwise
2529 */
2530static int hdd_parse_user_params(uint8_t *pValue, uint8_t **ppArg)
2531{
2532 uint8_t *pVal;
2533
2534 pVal = strnchr(pValue, strlen(pValue), ' ');
2535
2536 if (NULL == pVal) {
2537 /* no argument remains */
2538 return -EINVAL;
2539 } else if (SPACE_ASCII_VALUE != *pVal) {
2540 /* no space after the current argument */
2541 return -EINVAL;
2542 }
2543
2544 pVal++;
2545
2546 /* remove empty spaces */
2547 while ((SPACE_ASCII_VALUE == *pVal) && ('\0' != *pVal)) {
2548 pVal++;
2549 }
2550
2551 /* no argument followed by spaces */
2552 if ('\0' == *pVal) {
2553 return -EINVAL;
2554 }
2555
2556 *ppArg = pVal;
2557
2558 return 0;
2559}
2560
2561/**
2562 * hdd_parse_ibsstx_fail_event_params - Parse params
2563 * for SETIBSSTXFAILEVENT
2564 * @pValue: Input ibss tx fail event argument
2565 * @tx_fail_count: (Output parameter) Tx fail counter
2566 * @pid: (Output parameter) PID
2567 *
2568 * Return: 0 if the parsing succeeds; -EINVAL otherwise
2569 */
2570static int hdd_parse_ibsstx_fail_event_params(uint8_t *pValue,
2571 uint8_t *tx_fail_count,
2572 uint16_t *pid)
2573{
2574 uint8_t *param = NULL;
2575 int ret;
2576
2577 ret = hdd_parse_user_params(pValue, &param);
2578
2579 if (0 == ret && NULL != param) {
2580 if (1 != sscanf(param, "%hhu", tx_fail_count)) {
2581 ret = -EINVAL;
2582 goto done;
2583 }
2584 } else {
2585 goto done;
2586 }
2587
2588 if (0 == *tx_fail_count) {
2589 *pid = 0;
2590 goto done;
2591 }
2592
2593 pValue = param;
2594 pValue++;
2595
2596 ret = hdd_parse_user_params(pValue, &param);
2597
2598 if (0 == ret) {
2599 if (1 != sscanf(param, "%hu", pid)) {
2600 ret = -EINVAL;
2601 goto done;
2602 }
2603 } else {
2604 goto done;
2605 }
2606
2607done:
2608 return ret;
2609}
2610
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08002611#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002612/**
2613 * hdd_parse_ese_beacon_req() - Parse ese beacon request
2614 * @pValue: Pointer to data
2615 * @pEseBcnReq: Output pointer to store parsed ie information
2616 *
2617 * This function parses the ese beacon request passed in the format
2618 * CCXBEACONREQ<space><Number of fields><space><Measurement token>
2619 * <space>Channel 1<space>Scan Mode <space>Meas Duration<space>Channel N
2620 * <space>Scan Mode N<space>Meas Duration N
2621 *
2622 * If the Number of bcn req fields (N) does not match with the
2623 * actual number of fields passed then take N.
2624 * <Meas Token><Channel><Scan Mode> and <Meas Duration> are treated
2625 * as one pair. For example, CCXBEACONREQ 2 1 1 1 30 2 44 0 40.
2626 * This function does not take care of removing duplicate channels from the
2627 * list
2628 *
2629 * Return: 0 for success non-zero for failure
2630 */
2631static int hdd_parse_ese_beacon_req(uint8_t *pValue,
2632 tCsrEseBeaconReq *pEseBcnReq)
2633{
2634 uint8_t *inPtr = pValue;
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002635 uint8_t input = 0;
2636 uint32_t tempInt = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002637 int j = 0, i = 0, v = 0;
2638 char buf[32];
2639
2640 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2641 /* no argument after the command */
2642 if (NULL == inPtr) {
2643 return -EINVAL;
2644 }
2645 /* no space after the command */
2646 else if (SPACE_ASCII_VALUE != *inPtr) {
2647 return -EINVAL;
2648 }
2649
2650 /* remove empty spaces */
2651 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2652 inPtr++;
2653
2654 /* no argument followed by spaces */
2655 if ('\0' == *inPtr)
2656 return -EINVAL;
2657
Srinivas Girigowda476deeb2016-07-19 16:21:29 -07002658 /* Getting the first argument ie Number of IE fields */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002659 v = sscanf(inPtr, "%31s ", buf);
2660 if (1 != v)
2661 return -EINVAL;
2662
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002663 v = kstrtou8(buf, 10, &input);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002664 if (v < 0)
2665 return -EINVAL;
2666
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002667 input = QDF_MIN(input, SIR_ESE_MAX_MEAS_IE_REQS);
2668 pEseBcnReq->numBcnReqIe = input;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002669
Srinivas Girigowda476deeb2016-07-19 16:21:29 -07002670 hdd_info("Number of Bcn Req Ie fields: %d", pEseBcnReq->numBcnReqIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002671
2672 for (j = 0; j < (pEseBcnReq->numBcnReqIe); j++) {
2673 for (i = 0; i < 4; i++) {
2674 /*
2675 * inPtr pointing to the beginning of 1st space
2676 * after number of ie fields
2677 */
2678 inPtr = strpbrk(inPtr, " ");
2679 /* no ie data after the number of ie fields argument */
2680 if (NULL == inPtr)
2681 return -EINVAL;
2682
2683 /* remove empty space */
2684 while ((SPACE_ASCII_VALUE == *inPtr)
2685 && ('\0' != *inPtr))
2686 inPtr++;
2687
2688 /*
2689 * no ie data after the number of ie fields
2690 * argument and spaces
2691 */
2692 if ('\0' == *inPtr)
2693 return -EINVAL;
2694
2695 v = sscanf(inPtr, "%31s ", buf);
2696 if (1 != v)
2697 return -EINVAL;
2698
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002699 v = kstrtou32(buf, 10, &tempInt);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002700 if (v < 0)
2701 return -EINVAL;
2702
2703 switch (i) {
2704 case 0: /* Measurement token */
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002705 if (!tempInt) {
2706 hdd_err("Invalid Measurement Token: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002707 tempInt);
2708 return -EINVAL;
2709 }
2710 pEseBcnReq->bcnReq[j].measurementToken =
2711 tempInt;
2712 break;
2713
2714 case 1: /* Channel number */
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002715 if (!tempInt ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002716 (tempInt >
2717 WNI_CFG_CURRENT_CHANNEL_STAMAX)) {
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002718 hdd_err("Invalid Channel Number: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002719 tempInt);
2720 return -EINVAL;
2721 }
2722 pEseBcnReq->bcnReq[j].channel = tempInt;
2723 break;
2724
2725 case 2: /* Scan mode */
2726 if ((tempInt < eSIR_PASSIVE_SCAN)
2727 || (tempInt > eSIR_BEACON_TABLE)) {
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002728 hdd_err("Invalid Scan Mode: %u Expected{0|1|2}",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002729 tempInt);
2730 return -EINVAL;
2731 }
2732 pEseBcnReq->bcnReq[j].scanMode = tempInt;
2733 break;
2734
2735 case 3: /* Measurement duration */
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002736 if ((!tempInt
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002737 && (pEseBcnReq->bcnReq[j].scanMode !=
2738 eSIR_BEACON_TABLE)) ||
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002739 (pEseBcnReq->bcnReq[j].scanMode ==
2740 eSIR_BEACON_TABLE)) {
2741 hdd_err("Invalid Measurement Duration: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002742 tempInt);
2743 return -EINVAL;
2744 }
2745 pEseBcnReq->bcnReq[j].measurementDuration =
2746 tempInt;
2747 break;
2748 }
2749 }
2750 }
2751
2752 for (j = 0; j < pEseBcnReq->numBcnReqIe; j++) {
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002753 hdd_info("Index: %d Measurement Token: %u Channel: %u Scan Mode: %u Measurement Duration: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002754 j,
2755 pEseBcnReq->bcnReq[j].measurementToken,
2756 pEseBcnReq->bcnReq[j].channel,
2757 pEseBcnReq->bcnReq[j].scanMode,
2758 pEseBcnReq->bcnReq[j].measurementDuration);
2759 }
2760
2761 return 0;
2762}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002763
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002764/**
2765 * hdd_parse_get_cckm_ie() - HDD Parse and fetch the CCKM IE
2766 * @pValue: Pointer to input data
2767 * @pCckmIe: Pointer to output cckm Ie
2768 * @pCckmIeLen: Pointer to output cckm ie length
2769 *
2770 * This function parses the SETCCKM IE command
2771 * SETCCKMIE<space><ie data>
2772 *
2773 * Return: 0 for success non-zero for failure
2774 */
2775static int hdd_parse_get_cckm_ie(uint8_t *pValue, uint8_t **pCckmIe,
2776 uint8_t *pCckmIeLen)
2777{
2778 uint8_t *inPtr = pValue;
2779 uint8_t *dataEnd;
2780 int j = 0;
2781 int i = 0;
2782 uint8_t tempByte = 0;
2783 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2784 /* no argument after the command */
2785 if (NULL == inPtr) {
2786 return -EINVAL;
2787 }
2788 /* no space after the command */
2789 else if (SPACE_ASCII_VALUE != *inPtr) {
2790 return -EINVAL;
2791 }
2792 /* remove empty spaces */
2793 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2794 inPtr++;
2795 /* no argument followed by spaces */
2796 if ('\0' == *inPtr) {
2797 return -EINVAL;
2798 }
2799 /* find the length of data */
2800 dataEnd = inPtr;
2801 while (('\0' != *dataEnd)) {
2802 dataEnd++;
2803 ++(*pCckmIeLen);
2804 }
2805 if (*pCckmIeLen <= 0)
2806 return -EINVAL;
2807 /*
2808 * Allocate the number of bytes based on the number of input characters
2809 * whether it is even or odd.
2810 * if the number of input characters are even, then we need N / 2 byte.
2811 * if the number of input characters are odd, then we need do
2812 * (N + 1) / 2 to compensate rounding off.
2813 * For example, if N = 18, then (18 + 1) / 2 = 9 bytes are enough.
2814 * If N = 19, then we need 10 bytes, hence (19 + 1) / 2 = 10 bytes
2815 */
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302816 *pCckmIe = qdf_mem_malloc((*pCckmIeLen + 1) / 2);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002817 if (NULL == *pCckmIe) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002818 hdd_err("qdf_mem_malloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002819 return -ENOMEM;
2820 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002821 /*
2822 * the buffer received from the upper layer is character buffer,
2823 * we need to prepare the buffer taking 2 characters in to a U8 hex
2824 * decimal number for example 7f0000f0...form a buffer to contain
2825 * 7f in 0th location, 00 in 1st and f0 in 3rd location
2826 */
2827 for (i = 0, j = 0; j < *pCckmIeLen; j += 2) {
2828 tempByte = (hex_to_bin(inPtr[j]) << 4) |
2829 (hex_to_bin(inPtr[j + 1]));
2830 (*pCckmIe)[i++] = tempByte;
2831 }
2832 *pCckmIeLen = i;
2833 return 0;
2834}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08002835#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002836
2837int wlan_hdd_set_mc_rate(hdd_adapter_t *pAdapter, int targetRate)
2838{
2839 tSirRateUpdateInd rateUpdate = {0};
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302840 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002841 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
2842 struct hdd_config *pConfig = NULL;
2843
2844 if (pHddCtx == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002845 hdd_err("HDD context is null");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002846 return -EINVAL;
2847 }
Krunal Sonibe766b02016-03-10 13:00:44 -08002848 if ((QDF_IBSS_MODE != pAdapter->device_mode) &&
2849 (QDF_SAP_MODE != pAdapter->device_mode) &&
2850 (QDF_STA_MODE != pAdapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002851 hdd_err("Received SETMCRATE cmd in invalid mode %s(%d)",
2852 hdd_device_mode_to_string(pAdapter->device_mode),
2853 pAdapter->device_mode);
2854 hdd_err("SETMCRATE cmd is allowed only in STA, IBSS or SOFTAP mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002855 return -EINVAL;
2856 }
2857 pConfig = pHddCtx->config;
2858 rateUpdate.nss = (pConfig->enable2x2 == 0) ? 0 : 1;
2859 rateUpdate.dev_mode = pAdapter->device_mode;
2860 rateUpdate.mcastDataRate24GHz = targetRate;
2861 rateUpdate.mcastDataRate24GHzTxFlag = 1;
2862 rateUpdate.mcastDataRate5GHz = targetRate;
2863 rateUpdate.bcastDataRate = -1;
Anurag Chouhanc5548422016-02-24 18:33:27 +05302864 qdf_copy_macaddr(&rateUpdate.bssid, &pAdapter->macAddressCurrent);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002865 hdd_info("MC Target rate %d, mac = %pM, dev_mode %s(%d)",
2866 rateUpdate.mcastDataRate24GHz, rateUpdate.bssid.bytes,
2867 hdd_device_mode_to_string(pAdapter->device_mode),
2868 pAdapter->device_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002869 status = sme_send_rate_update_ind(pHddCtx->hHal, &rateUpdate);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302870 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002871 hdd_err("SETMCRATE failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002872 return -EFAULT;
2873 }
2874 return 0;
2875}
2876
2877static int drv_cmd_p2p_dev_addr(hdd_adapter_t *adapter,
2878 hdd_context_t *hdd_ctx,
2879 uint8_t *command,
2880 uint8_t command_len,
2881 hdd_priv_data_t *priv_data)
2882{
2883 int ret = 0;
2884
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302885 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002886 TRACE_CODE_HDD_P2P_DEV_ADDR_IOCTL,
2887 adapter->sessionId,
2888 (unsigned)(*(hdd_ctx->p2pDeviceAddress.bytes + 2)
2889 << 24 | *(hdd_ctx->p2pDeviceAddress.bytes
2890 + 3) << 16 | *(hdd_ctx->
2891 p2pDeviceAddress.bytes + 4) << 8 |
2892 *(hdd_ctx->p2pDeviceAddress.bytes +
2893 5))));
2894
2895 if (copy_to_user(priv_data->buf, hdd_ctx->p2pDeviceAddress.bytes,
2896 sizeof(tSirMacAddr))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002897 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002898 ret = -EFAULT;
2899 }
2900
2901 return ret;
2902}
2903
2904/**
2905 * drv_cmd_p2p_set_noa() - Handler for P2P_SET_NOA driver command
2906 * @adapter: Adapter on which the command was received
2907 * @hdd_ctx: HDD global context
2908 * @command: Entire driver command received from userspace
2909 * @command_len: Length of @command
2910 * @priv_data: Pointer to ioctl private data structure
2911 *
2912 * This is a trivial command hander function which simply forwards the
2913 * command to the actual command processor within the P2P module.
2914 *
2915 * Return: 0 on success, non-zero on failure
2916 */
2917static int drv_cmd_p2p_set_noa(hdd_adapter_t *adapter,
2918 hdd_context_t *hdd_ctx,
2919 uint8_t *command,
2920 uint8_t command_len,
2921 hdd_priv_data_t *priv_data)
2922{
2923 return hdd_set_p2p_noa(adapter->dev, command);
2924}
2925
2926/**
2927 * drv_cmd_p2p_set_ps() - Handler for P2P_SET_PS driver command
2928 * @adapter: Adapter on which the command was received
2929 * @hdd_ctx: HDD global context
2930 * @command: Entire driver command received from userspace
2931 * @command_len: Length of @command
2932 * @priv_data: Pointer to ioctl private data structure
2933 *
2934 * This is a trivial command hander function which simply forwards the
2935 * command to the actual command processor within the P2P module.
2936 *
2937 * Return: 0 on success, non-zero on failure
2938 */
2939static int drv_cmd_p2p_set_ps(hdd_adapter_t *adapter,
2940 hdd_context_t *hdd_ctx,
2941 uint8_t *command,
2942 uint8_t command_len,
2943 hdd_priv_data_t *priv_data)
2944{
2945 return hdd_set_p2p_opps(adapter->dev, command);
2946}
2947
2948static int drv_cmd_set_band(hdd_adapter_t *adapter,
2949 hdd_context_t *hdd_ctx,
2950 uint8_t *command,
2951 uint8_t command_len,
2952 hdd_priv_data_t *priv_data)
2953{
2954 int ret = 0;
2955
2956 uint8_t *ptr = command;
2957
2958 /* Change band request received */
2959
2960 /*
2961 * First 8 bytes will have "SETBAND " and
2962 * 9 byte will have band setting value
2963 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002964 hdd_info("SetBandCommand Info comm %s UL %d, TL %d",
2965 command, priv_data->used_len,
2966 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002967
2968 /* Change band request received */
2969 ret = hdd_set_band_helper(adapter->dev, ptr);
2970
2971 return ret;
2972}
2973
2974static int drv_cmd_set_wmmps(hdd_adapter_t *adapter,
2975 hdd_context_t *hdd_ctx,
2976 uint8_t *command,
2977 uint8_t command_len,
2978 hdd_priv_data_t *priv_data)
2979{
2980 return hdd_wmmps_helper(adapter, command);
2981}
2982
2983static int drv_cmd_country(hdd_adapter_t *adapter,
2984 hdd_context_t *hdd_ctx,
2985 uint8_t *command,
2986 uint8_t command_len,
2987 hdd_priv_data_t *priv_data)
2988{
2989 int ret = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302990 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002991 unsigned long rc;
2992 char *country_code;
2993
2994 country_code = command + 8;
2995
2996 INIT_COMPLETION(adapter->change_country_code);
2997
2998 status = sme_change_country_code(hdd_ctx->hHal,
2999 wlan_hdd_change_country_code_callback,
3000 country_code,
3001 adapter,
3002 hdd_ctx->pcds_context,
3003 eSIR_TRUE,
3004 eSIR_TRUE);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303005 if (status == QDF_STATUS_SUCCESS) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003006 rc = wait_for_completion_timeout(
3007 &adapter->change_country_code,
3008 msecs_to_jiffies(WLAN_WAIT_TIME_COUNTRY));
3009 if (!rc)
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003010 hdd_err("SME while setting country code timed out");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003011 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003012 hdd_err("SME Change Country code fail, status %d",
3013 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003014 ret = -EINVAL;
3015 }
3016
3017 return ret;
3018}
3019
3020static int drv_cmd_set_roam_trigger(hdd_adapter_t *adapter,
3021 hdd_context_t *hdd_ctx,
3022 uint8_t *command,
3023 uint8_t command_len,
3024 hdd_priv_data_t *priv_data)
3025{
3026 int ret = 0;
3027 uint8_t *value = command;
3028 int8_t rssi = 0;
3029 uint8_t lookUpThreshold = CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_DEFAULT;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303030 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003031
3032 /* Move pointer to ahead of SETROAMTRIGGER<delimiter> */
3033 value = value + command_len + 1;
3034
3035 /* Convert the value from ascii to integer */
3036 ret = kstrtos8(value, 10, &rssi);
3037 if (ret < 0) {
3038 /*
3039 * If the input value is greater than max value of datatype,
3040 * then also kstrtou8 fails
3041 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003042 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
3043 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN,
3044 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003045 ret = -EINVAL;
3046 goto exit;
3047 }
3048
3049 lookUpThreshold = abs(rssi);
3050
3051 if ((lookUpThreshold < CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN)
3052 || (lookUpThreshold > CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003053 hdd_err("Neighbor lookup threshold value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003054 lookUpThreshold,
3055 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN,
3056 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX);
3057 ret = -EINVAL;
3058 goto exit;
3059 }
3060
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303061 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003062 TRACE_CODE_HDD_SETROAMTRIGGER_IOCTL,
3063 adapter->sessionId, lookUpThreshold));
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003064 hdd_info("Received Command to Set Roam trigger (Neighbor lookup threshold) = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003065 lookUpThreshold);
3066
3067 hdd_ctx->config->nNeighborLookupRssiThreshold = lookUpThreshold;
3068 status = sme_set_neighbor_lookup_rssi_threshold(hdd_ctx->hHal,
3069 adapter->sessionId,
3070 lookUpThreshold);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303071 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003072 hdd_err("Failed to set roam trigger, try again");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003073 ret = -EPERM;
3074 goto exit;
3075 }
3076
3077exit:
3078 return ret;
3079}
3080
3081static int drv_cmd_get_roam_trigger(hdd_adapter_t *adapter,
3082 hdd_context_t *hdd_ctx,
3083 uint8_t *command,
3084 uint8_t command_len,
3085 hdd_priv_data_t *priv_data)
3086{
3087 int ret = 0;
3088 uint8_t lookUpThreshold =
3089 sme_get_neighbor_lookup_rssi_threshold(hdd_ctx->hHal);
3090 int rssi = (-1) * lookUpThreshold;
3091 char extra[32];
3092 uint8_t len = 0;
3093
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303094 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003095 TRACE_CODE_HDD_GETROAMTRIGGER_IOCTL,
3096 adapter->sessionId, lookUpThreshold));
3097
3098 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303099 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003100 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003101 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003102 ret = -EFAULT;
3103 }
3104
3105 return ret;
3106}
3107
3108static int drv_cmd_set_roam_scan_period(hdd_adapter_t *adapter,
3109 hdd_context_t *hdd_ctx,
3110 uint8_t *command,
3111 uint8_t command_len,
3112 hdd_priv_data_t *priv_data)
3113{
3114 int ret = 0;
3115 uint8_t *value = command;
3116 uint8_t roamScanPeriod = 0;
3117 uint16_t neighborEmptyScanRefreshPeriod =
3118 CFG_EMPTY_SCAN_REFRESH_PERIOD_DEFAULT;
3119
3120 /* input refresh period is in terms of seconds */
3121
3122 /* Move pointer to ahead of SETROAMSCANPERIOD<delimiter> */
3123 value = value + command_len + 1;
3124
3125 /* Convert the value from ascii to integer */
3126 ret = kstrtou8(value, 10, &roamScanPeriod);
3127 if (ret < 0) {
3128 /*
3129 * If the input value is greater than max value of datatype,
3130 * then also kstrtou8 fails
3131 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003132 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
3133 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000),
3134 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003135 ret = -EINVAL;
3136 goto exit;
3137 }
3138
3139 if ((roamScanPeriod < (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000))
3140 || (roamScanPeriod > (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003141 hdd_err("Roam scan period value %d is out of range (Min: %d Max: %d)",
3142 roamScanPeriod,
3143 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000),
3144 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003145 ret = -EINVAL;
3146 goto exit;
3147 }
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303148 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003149 TRACE_CODE_HDD_SETROAMSCANPERIOD_IOCTL,
3150 adapter->sessionId, roamScanPeriod));
3151 neighborEmptyScanRefreshPeriod = roamScanPeriod * 1000;
3152
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003153 hdd_info("Received Command to Set roam scan period (Empty Scan refresh period) = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003154 roamScanPeriod);
3155
3156 hdd_ctx->config->nEmptyScanRefreshPeriod =
3157 neighborEmptyScanRefreshPeriod;
3158 sme_update_empty_scan_refresh_period(hdd_ctx->hHal,
3159 adapter->sessionId,
3160 neighborEmptyScanRefreshPeriod);
3161
3162exit:
3163 return ret;
3164}
3165
3166static int drv_cmd_get_roam_scan_period(hdd_adapter_t *adapter,
3167 hdd_context_t *hdd_ctx,
3168 uint8_t *command,
3169 uint8_t command_len,
3170 hdd_priv_data_t *priv_data)
3171{
3172 int ret = 0;
3173 uint16_t nEmptyScanRefreshPeriod =
3174 sme_get_empty_scan_refresh_period(hdd_ctx->hHal);
3175 char extra[32];
3176 uint8_t len = 0;
3177
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303178 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003179 TRACE_CODE_HDD_GETROAMSCANPERIOD_IOCTL,
3180 adapter->sessionId,
3181 nEmptyScanRefreshPeriod));
3182 len = scnprintf(extra, sizeof(extra), "%s %d",
3183 "GETROAMSCANPERIOD",
3184 (nEmptyScanRefreshPeriod / 1000));
3185 /* Returned value is in units of seconds */
Anurag Chouhan6d760662016-02-20 16:05:43 +05303186 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003187 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003188 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003189 ret = -EFAULT;
3190 }
3191
3192 return ret;
3193}
3194
3195static int drv_cmd_set_roam_scan_refresh_period(hdd_adapter_t *adapter,
3196 hdd_context_t *hdd_ctx,
3197 uint8_t *command,
3198 uint8_t command_len,
3199 hdd_priv_data_t *priv_data)
3200{
3201 int ret = 0;
3202 uint8_t *value = command;
3203 uint8_t roamScanRefreshPeriod = 0;
3204 uint16_t neighborScanRefreshPeriod =
3205 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_DEFAULT;
3206
3207 /* input refresh period is in terms of seconds */
3208 /* Move pointer to ahead of SETROAMSCANREFRESHPERIOD<delimiter> */
3209 value = value + command_len + 1;
3210
3211 /* Convert the value from ascii to integer */
3212 ret = kstrtou8(value, 10, &roamScanRefreshPeriod);
3213 if (ret < 0) {
3214 /*
3215 * If the input value is greater than max value of datatype,
3216 * then also kstrtou8 fails
3217 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003218 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
3219 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN / 1000,
3220 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX / 1000);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003221 ret = -EINVAL;
3222 goto exit;
3223 }
3224
3225 if ((roamScanRefreshPeriod <
3226 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN / 1000))
3227 || (roamScanRefreshPeriod >
3228 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX / 1000))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003229 hdd_err("Neighbor scan results refresh period value %d is out of range (Min: %d Max: %d)",
3230 roamScanRefreshPeriod,
3231 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN
3232 / 1000),
3233 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX
3234 / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003235 ret = -EINVAL;
3236 goto exit;
3237 }
3238 neighborScanRefreshPeriod = roamScanRefreshPeriod * 1000;
3239
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003240 hdd_info("Received Command to Set roam scan refresh period (Scan refresh period) = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003241 roamScanRefreshPeriod);
3242
3243 hdd_ctx->config->nNeighborResultsRefreshPeriod =
3244 neighborScanRefreshPeriod;
3245 sme_set_neighbor_scan_refresh_period(hdd_ctx->hHal,
3246 adapter->sessionId,
3247 neighborScanRefreshPeriod);
3248
3249exit:
3250 return ret;
3251}
3252
3253static int drv_cmd_get_roam_scan_refresh_period(hdd_adapter_t *adapter,
3254 hdd_context_t *hdd_ctx,
3255 uint8_t *command,
3256 uint8_t command_len,
3257 hdd_priv_data_t *priv_data)
3258{
3259 int ret = 0;
3260 uint16_t value =
3261 sme_get_neighbor_scan_refresh_period(hdd_ctx->hHal);
3262 char extra[32];
3263 uint8_t len = 0;
3264
3265 len = scnprintf(extra, sizeof(extra), "%s %d",
3266 "GETROAMSCANREFRESHPERIOD",
3267 (value / 1000));
3268 /* Returned value is in units of seconds */
Anurag Chouhan6d760662016-02-20 16:05:43 +05303269 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003270 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003271 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003272 ret = -EFAULT;
3273 }
3274
3275 return ret;
3276}
3277
3278static int drv_cmd_set_roam_mode(hdd_adapter_t *adapter,
3279 hdd_context_t *hdd_ctx,
3280 uint8_t *command,
3281 uint8_t command_len,
3282 hdd_priv_data_t *priv_data)
3283{
3284 int ret = 0;
3285 uint8_t *value = command;
3286 uint8_t roamMode = CFG_LFR_FEATURE_ENABLED_DEFAULT;
3287
Deepak Dhamdherea2785822016-11-17 01:17:45 -08003288 if (!adapter->fast_roaming_allowed) {
3289 hdd_err("Roaming is always disabled on this interface");
3290 goto exit;
3291 }
3292
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003293 /* Move pointer to ahead of SETROAMMODE<delimiter> */
3294 value = value + SIZE_OF_SETROAMMODE + 1;
3295
3296 /* Convert the value from ascii to integer */
3297 ret = kstrtou8(value, SIZE_OF_SETROAMMODE, &roamMode);
3298 if (ret < 0) {
3299 /*
3300 * If the input value is greater than max value of datatype,
3301 * then also kstrtou8 fails
3302 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003303 hdd_err("kstrtou8 failed range [%d - %d]",
3304 CFG_LFR_FEATURE_ENABLED_MIN,
3305 CFG_LFR_FEATURE_ENABLED_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003306 ret = -EINVAL;
3307 goto exit;
3308 }
3309 if ((roamMode < CFG_LFR_FEATURE_ENABLED_MIN) ||
3310 (roamMode > CFG_LFR_FEATURE_ENABLED_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003311 hdd_err("Roam Mode value %d is out of range (Min: %d Max: %d)",
3312 roamMode,
3313 CFG_LFR_FEATURE_ENABLED_MIN,
3314 CFG_LFR_FEATURE_ENABLED_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003315 ret = -EINVAL;
3316 goto exit;
3317 }
3318
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003319 hdd_debug("Received Command to Set Roam Mode = %d",
3320 roamMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003321 /*
3322 * Note that
3323 * SETROAMMODE 0 is to enable LFR while
3324 * SETROAMMODE 1 is to disable LFR, but
3325 * notify_is_fast_roam_ini_feature_enabled 0/1 is to
3326 * enable/disable. So, we have to invert the value
3327 * to call sme_update_is_fast_roam_ini_feature_enabled.
3328 */
3329 if (CFG_LFR_FEATURE_ENABLED_MIN == roamMode)
3330 roamMode = CFG_LFR_FEATURE_ENABLED_MAX; /* Roam enable */
3331 else
3332 roamMode = CFG_LFR_FEATURE_ENABLED_MIN; /* Roam disable */
3333
3334 hdd_ctx->config->isFastRoamIniFeatureEnabled = roamMode;
3335 if (roamMode) {
3336 hdd_ctx->config->isRoamOffloadScanEnabled = roamMode;
3337 sme_update_roam_scan_offload_enabled(
3338 (tHalHandle)(hdd_ctx->hHal),
3339 hdd_ctx->config->isRoamOffloadScanEnabled);
3340 sme_update_is_fast_roam_ini_feature_enabled(
3341 hdd_ctx->hHal,
3342 adapter->sessionId,
3343 roamMode);
3344 } else {
3345 sme_update_is_fast_roam_ini_feature_enabled(
3346 hdd_ctx->hHal,
3347 adapter->sessionId,
3348 roamMode);
3349 hdd_ctx->config->isRoamOffloadScanEnabled = roamMode;
3350 sme_update_roam_scan_offload_enabled(
3351 (tHalHandle)(hdd_ctx->hHal),
3352 hdd_ctx->config->isRoamOffloadScanEnabled);
3353 }
3354
3355
3356exit:
3357 return ret;
3358}
3359
3360static int drv_cmd_get_roam_mode(hdd_adapter_t *adapter,
3361 hdd_context_t *hdd_ctx,
3362 uint8_t *command,
3363 uint8_t command_len,
3364 hdd_priv_data_t *priv_data)
3365{
3366 int ret = 0;
3367 bool roamMode = sme_get_is_lfr_feature_enabled(hdd_ctx->hHal);
3368 char extra[32];
3369 uint8_t len = 0;
3370
3371 /*
3372 * roamMode value shall be inverted because the sementics is different.
3373 */
3374 if (CFG_LFR_FEATURE_ENABLED_MIN == roamMode)
3375 roamMode = CFG_LFR_FEATURE_ENABLED_MAX;
3376 else
3377 roamMode = CFG_LFR_FEATURE_ENABLED_MIN;
3378
3379 len = scnprintf(extra, sizeof(extra), "%s %d", command, roamMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303380 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003381 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003382 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003383 ret = -EFAULT;
3384 }
3385
3386 return ret;
3387}
3388
3389static int drv_cmd_set_roam_delta(hdd_adapter_t *adapter,
3390 hdd_context_t *hdd_ctx,
3391 uint8_t *command,
3392 uint8_t command_len,
3393 hdd_priv_data_t *priv_data)
3394{
3395 int ret = 0;
3396 uint8_t *value = command;
3397 uint8_t roamRssiDiff = CFG_ROAM_RSSI_DIFF_DEFAULT;
3398
3399 /* Move pointer to ahead of SETROAMDELTA<delimiter> */
3400 value = value + command_len + 1;
3401
3402 /* Convert the value from ascii to integer */
3403 ret = kstrtou8(value, 10, &roamRssiDiff);
3404 if (ret < 0) {
3405 /*
3406 * If the input value is greater than max value of datatype,
3407 * then also kstrtou8 fails
3408 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003409 hdd_err("kstrtou8 failed range [%d - %d]",
3410 CFG_ROAM_RSSI_DIFF_MIN,
3411 CFG_ROAM_RSSI_DIFF_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003412 ret = -EINVAL;
3413 goto exit;
3414 }
3415
3416 if ((roamRssiDiff < CFG_ROAM_RSSI_DIFF_MIN) ||
3417 (roamRssiDiff > CFG_ROAM_RSSI_DIFF_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003418 hdd_err("Roam rssi diff value %d is out of range (Min: %d Max: %d)",
3419 roamRssiDiff,
3420 CFG_ROAM_RSSI_DIFF_MIN,
3421 CFG_ROAM_RSSI_DIFF_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003422 ret = -EINVAL;
3423 goto exit;
3424 }
3425
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003426 hdd_info("Received Command to Set roam rssi diff = %d",
3427 roamRssiDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003428
3429 hdd_ctx->config->RoamRssiDiff = roamRssiDiff;
3430 sme_update_roam_rssi_diff(hdd_ctx->hHal,
3431 adapter->sessionId,
3432 roamRssiDiff);
3433
3434exit:
3435 return ret;
3436}
3437
3438static int drv_cmd_get_roam_delta(hdd_adapter_t *adapter,
3439 hdd_context_t *hdd_ctx,
3440 uint8_t *command,
3441 uint8_t command_len,
3442 hdd_priv_data_t *priv_data)
3443{
3444 int ret = 0;
3445 uint8_t roamRssiDiff =
3446 sme_get_roam_rssi_diff(hdd_ctx->hHal);
3447 char extra[32];
3448 uint8_t len = 0;
3449
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303450 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003451 TRACE_CODE_HDD_GETROAMDELTA_IOCTL,
3452 adapter->sessionId, roamRssiDiff));
3453
3454 len = scnprintf(extra, sizeof(extra), "%s %d",
3455 command, roamRssiDiff);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303456 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003457
3458 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003459 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003460 ret = -EFAULT;
3461 }
3462
3463 return ret;
3464}
3465
3466static int drv_cmd_get_band(hdd_adapter_t *adapter,
3467 hdd_context_t *hdd_ctx,
3468 uint8_t *command,
3469 uint8_t command_len,
3470 hdd_priv_data_t *priv_data)
3471{
3472 int ret = 0;
3473 int band = -1;
3474 char extra[32];
3475 uint8_t len = 0;
3476
3477 hdd_get_band_helper(hdd_ctx, &band);
3478
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303479 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003480 TRACE_CODE_HDD_GETBAND_IOCTL,
3481 adapter->sessionId, band));
3482
3483 len = scnprintf(extra, sizeof(extra), "%s %d", command, band);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303484 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003485
3486 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003487 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003488 ret = -EFAULT;
3489 }
3490
3491 return ret;
3492}
3493
3494static int drv_cmd_set_roam_scan_channels(hdd_adapter_t *adapter,
3495 hdd_context_t *hdd_ctx,
3496 uint8_t *command,
3497 uint8_t command_len,
3498 hdd_priv_data_t *priv_data)
3499{
3500 return hdd_parse_set_roam_scan_channels(adapter, command);
3501}
3502
3503static int drv_cmd_get_roam_scan_channels(hdd_adapter_t *adapter,
3504 hdd_context_t *hdd_ctx,
3505 uint8_t *command,
3506 uint8_t command_len,
3507 hdd_priv_data_t *priv_data)
3508{
3509 int ret = 0;
3510 uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
3511 uint8_t numChannels = 0;
3512 uint8_t j = 0;
3513 char extra[128] = { 0 };
3514 int len;
3515
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303516 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003517 sme_get_roam_scan_channel_list(hdd_ctx->hHal,
3518 ChannelList,
3519 &numChannels,
3520 adapter->sessionId)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003521 hdd_alert("failed to get roam scan channel list");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003522 ret = -EFAULT;
3523 goto exit;
3524 }
3525
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303526 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003527 TRACE_CODE_HDD_GETROAMSCANCHANNELS_IOCTL,
3528 adapter->sessionId, numChannels));
3529 /*
3530 * output channel list is of the format
3531 * [Number of roam scan channels][Channel1][Channel2]...
3532 * copy the number of channels in the 0th index
3533 */
3534 len = scnprintf(extra, sizeof(extra), "%s %d", command,
3535 numChannels);
Selvaraj, Sridhar5cc4af42016-10-19 10:41:59 +05303536 for (j = 0; (j < numChannels) && len <= sizeof(extra); j++)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003537 len += scnprintf(extra + len, sizeof(extra) - len,
3538 " %d", ChannelList[j]);
3539
Anurag Chouhan6d760662016-02-20 16:05:43 +05303540 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003541 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003542 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003543 ret = -EFAULT;
3544 goto exit;
3545 }
3546
3547exit:
3548 return ret;
3549}
3550
3551static int drv_cmd_get_ccx_mode(hdd_adapter_t *adapter,
3552 hdd_context_t *hdd_ctx,
3553 uint8_t *command,
3554 uint8_t command_len,
3555 hdd_priv_data_t *priv_data)
3556{
3557 int ret = 0;
3558 bool eseMode = sme_get_is_ese_feature_enabled(hdd_ctx->hHal);
3559 char extra[32];
3560 uint8_t len = 0;
3561
3562 /*
3563 * Check if the features OKC/ESE/11R are supported simultaneously,
3564 * then this operation is not permitted (return FAILURE)
3565 */
3566 if (eseMode &&
3567 hdd_is_okc_mode_enabled(hdd_ctx) &&
3568 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003569 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003570 ret = -EPERM;
3571 goto exit;
3572 }
3573
3574 len = scnprintf(extra, sizeof(extra), "%s %d",
3575 "GETCCXMODE", eseMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303576 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003577 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003578 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003579 ret = -EFAULT;
3580 goto exit;
3581 }
3582
3583exit:
3584 return ret;
3585}
3586
3587static int drv_cmd_get_okc_mode(hdd_adapter_t *adapter,
3588 hdd_context_t *hdd_ctx,
3589 uint8_t *command,
3590 uint8_t command_len,
3591 hdd_priv_data_t *priv_data)
3592{
3593 int ret = 0;
3594 bool okcMode = hdd_is_okc_mode_enabled(hdd_ctx);
3595 char extra[32];
3596 uint8_t len = 0;
3597
3598 /*
3599 * Check if the features OKC/ESE/11R are supported simultaneously,
3600 * then this operation is not permitted (return FAILURE)
3601 */
3602 if (okcMode &&
3603 sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
3604 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003605 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003606 ret = -EPERM;
3607 goto exit;
3608 }
3609
3610 len = scnprintf(extra, sizeof(extra), "%s %d",
3611 "GETOKCMODE", okcMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303612 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003613
3614 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003615 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003616 ret = -EFAULT;
3617 goto exit;
3618 }
3619
3620exit:
3621 return ret;
3622}
3623
3624static int drv_cmd_get_fast_roam(hdd_adapter_t *adapter,
3625 hdd_context_t *hdd_ctx,
3626 uint8_t *command,
3627 uint8_t command_len,
3628 hdd_priv_data_t *priv_data)
3629{
3630 int ret = 0;
3631 bool lfrMode = sme_get_is_lfr_feature_enabled(hdd_ctx->hHal);
3632 char extra[32];
3633 uint8_t len = 0;
3634
3635 len = scnprintf(extra, sizeof(extra), "%s %d",
3636 "GETFASTROAM", lfrMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303637 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003638
3639 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003640 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003641 ret = -EFAULT;
3642 }
3643
3644 return ret;
3645}
3646
3647static int drv_cmd_get_fast_transition(hdd_adapter_t *adapter,
3648 hdd_context_t *hdd_ctx,
3649 uint8_t *command,
3650 uint8_t command_len,
3651 hdd_priv_data_t *priv_data)
3652{
3653 int ret = 0;
3654 bool ft = sme_get_is_ft_feature_enabled(hdd_ctx->hHal);
3655 char extra[32];
3656 uint8_t len = 0;
3657
3658 len = scnprintf(extra, sizeof(extra), "%s %d",
3659 "GETFASTTRANSITION", ft);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303660 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003661
3662 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003663 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003664 ret = -EFAULT;
3665 }
3666
3667 return ret;
3668}
3669
3670static int drv_cmd_set_roam_scan_channel_min_time(hdd_adapter_t *adapter,
3671 hdd_context_t *hdd_ctx,
3672 uint8_t *command,
3673 uint8_t command_len,
3674 hdd_priv_data_t *priv_data)
3675{
3676 int ret = 0;
3677 uint8_t *value = command;
3678 uint8_t minTime = CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_DEFAULT;
3679
3680 /* Move pointer to ahead of SETROAMSCANCHANNELMINTIME<delimiter> */
3681 value = value + command_len + 1;
3682
3683 /* Convert the value from ascii to integer */
3684 ret = kstrtou8(value, 10, &minTime);
3685 if (ret < 0) {
3686 /*
3687 * If the input value is greater than max value of datatype,
3688 * then also kstrtou8 fails
3689 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003690 hdd_err("kstrtou8 failed range [%d - %d]",
3691 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN,
3692 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003693 ret = -EINVAL;
3694 goto exit;
3695 }
3696
3697 if ((minTime < CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN) ||
3698 (minTime > CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003699 hdd_err("scan min channel time value %d is out of range (Min: %d Max: %d)",
3700 minTime,
3701 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN,
3702 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003703 ret = -EINVAL;
3704 goto exit;
3705 }
3706
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303707 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003708 TRACE_CODE_HDD_SETROAMSCANCHANNELMINTIME_IOCTL,
3709 adapter->sessionId, minTime));
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003710 hdd_info("Received Command to change channel min time = %d",
3711 minTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003712
3713 hdd_ctx->config->nNeighborScanMinChanTime = minTime;
3714 sme_set_neighbor_scan_min_chan_time(hdd_ctx->hHal,
3715 minTime,
3716 adapter->sessionId);
3717
3718exit:
3719 return ret;
3720}
3721
3722static int drv_cmd_send_action_frame(hdd_adapter_t *adapter,
3723 hdd_context_t *hdd_ctx,
3724 uint8_t *command,
3725 uint8_t command_len,
3726 hdd_priv_data_t *priv_data)
3727{
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07003728 return hdd_parse_sendactionframe(adapter, command,
3729 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003730}
3731
3732static int drv_cmd_get_roam_scan_channel_min_time(hdd_adapter_t *adapter,
3733 hdd_context_t *hdd_ctx,
3734 uint8_t *command,
3735 uint8_t command_len,
3736 hdd_priv_data_t *priv_data)
3737{
3738 int ret = 0;
3739 uint16_t val = sme_get_neighbor_scan_min_chan_time(hdd_ctx->hHal,
3740 adapter->sessionId);
3741 char extra[32];
3742 uint8_t len = 0;
3743
3744 /* value is interms of msec */
3745 len = scnprintf(extra, sizeof(extra), "%s %d",
3746 "GETROAMSCANCHANNELMINTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303747 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003748
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303749 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003750 TRACE_CODE_HDD_GETROAMSCANCHANNELMINTIME_IOCTL,
3751 adapter->sessionId, val));
3752
3753 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003754 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003755 ret = -EFAULT;
3756 }
3757
3758 return ret;
3759}
3760
3761static int drv_cmd_set_scan_channel_time(hdd_adapter_t *adapter,
3762 hdd_context_t *hdd_ctx,
3763 uint8_t *command,
3764 uint8_t command_len,
3765 hdd_priv_data_t *priv_data)
3766{
3767 int ret = 0;
3768 uint8_t *value = command;
3769 uint16_t maxTime = CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_DEFAULT;
3770
3771 /* Move pointer to ahead of SETSCANCHANNELTIME<delimiter> */
3772 value = value + command_len + 1;
3773
3774 /* Convert the value from ascii to integer */
3775 ret = kstrtou16(value, 10, &maxTime);
3776 if (ret < 0) {
3777 /*
3778 * If the input value is greater than max value of datatype,
3779 * then also kstrtou8 fails
3780 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003781 hdd_err("kstrtou16 failed range [%d - %d]",
3782 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN,
3783 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003784 ret = -EINVAL;
3785 goto exit;
3786 }
3787
3788 if ((maxTime < CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN) ||
3789 (maxTime > CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003790 hdd_err("lfr mode value %d is out of range (Min: %d Max: %d)",
3791 maxTime,
3792 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN,
3793 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003794 ret = -EINVAL;
3795 goto exit;
3796 }
3797
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003798 hdd_info("Received Command to change channel max time = %d",
3799 maxTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003800
3801 hdd_ctx->config->nNeighborScanMaxChanTime = maxTime;
3802 sme_set_neighbor_scan_max_chan_time(hdd_ctx->hHal,
3803 adapter->sessionId,
3804 maxTime);
3805
3806exit:
3807 return ret;
3808}
3809
3810static int drv_cmd_get_scan_channel_time(hdd_adapter_t *adapter,
3811 hdd_context_t *hdd_ctx,
3812 uint8_t *command,
3813 uint8_t command_len,
3814 hdd_priv_data_t *priv_data)
3815{
3816 int ret = 0;
3817 uint16_t val = sme_get_neighbor_scan_max_chan_time(hdd_ctx->hHal,
3818 adapter->sessionId);
3819 char extra[32];
3820 uint8_t len = 0;
3821
3822 /* value is interms of msec */
3823 len = scnprintf(extra, sizeof(extra), "%s %d",
3824 "GETSCANCHANNELTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303825 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003826
3827 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003828 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003829 ret = -EFAULT;
3830 }
3831
3832 return ret;
3833}
3834
3835static int drv_cmd_set_scan_home_time(hdd_adapter_t *adapter,
3836 hdd_context_t *hdd_ctx,
3837 uint8_t *command,
3838 uint8_t command_len,
3839 hdd_priv_data_t *priv_data)
3840{
3841 int ret = 0;
3842 uint8_t *value = command;
3843 uint16_t val = CFG_NEIGHBOR_SCAN_TIMER_PERIOD_DEFAULT;
3844
3845 /* Move pointer to ahead of SETSCANHOMETIME<delimiter> */
3846 value = value + command_len + 1;
3847
3848 /* Convert the value from ascii to integer */
3849 ret = kstrtou16(value, 10, &val);
3850 if (ret < 0) {
3851 /*
3852 * If the input value is greater than max value of datatype,
3853 * then also kstrtou8 fails
3854 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003855 hdd_err("kstrtou16 failed range [%d - %d]",
3856 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN,
3857 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003858 ret = -EINVAL;
3859 goto exit;
3860 }
3861
3862 if ((val < CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN) ||
3863 (val > CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003864 hdd_err("scan home time value %d is out of range (Min: %d Max: %d)",
3865 val,
3866 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN,
3867 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003868 ret = -EINVAL;
3869 goto exit;
3870 }
3871
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003872 hdd_info("Received Command to change scan home time = %d",
3873 val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003874
3875 hdd_ctx->config->nNeighborScanPeriod = val;
3876 sme_set_neighbor_scan_period(hdd_ctx->hHal,
3877 adapter->sessionId, val);
3878
3879exit:
3880 return ret;
3881}
3882
3883static int drv_cmd_get_scan_home_time(hdd_adapter_t *adapter,
3884 hdd_context_t *hdd_ctx,
3885 uint8_t *command,
3886 uint8_t command_len,
3887 hdd_priv_data_t *priv_data)
3888{
3889 int ret = 0;
3890 uint16_t val = sme_get_neighbor_scan_period(hdd_ctx->hHal,
3891 adapter->
3892 sessionId);
3893 char extra[32];
3894 uint8_t len = 0;
3895
3896 /* value is interms of msec */
3897 len = scnprintf(extra, sizeof(extra), "%s %d",
3898 "GETSCANHOMETIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303899 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003900
3901 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003902 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003903 ret = -EFAULT;
3904 }
3905
3906 return ret;
3907}
3908
3909static int drv_cmd_set_roam_intra_band(hdd_adapter_t *adapter,
3910 hdd_context_t *hdd_ctx,
3911 uint8_t *command,
3912 uint8_t command_len,
3913 hdd_priv_data_t *priv_data)
3914{
3915 int ret = 0;
3916 uint8_t *value = command;
3917 uint8_t val = CFG_ROAM_INTRA_BAND_DEFAULT;
3918
3919 /* Move pointer to ahead of SETROAMINTRABAND<delimiter> */
3920 value = value + command_len + 1;
3921
3922 /* Convert the value from ascii to integer */
3923 ret = kstrtou8(value, 10, &val);
3924 if (ret < 0) {
3925 /*
3926 * If the input value is greater than max value of datatype,
3927 * then also kstrtou8 fails
3928 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003929 hdd_err("kstrtou8 failed range [%d - %d]",
3930 CFG_ROAM_INTRA_BAND_MIN,
3931 CFG_ROAM_INTRA_BAND_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003932 ret = -EINVAL;
3933 goto exit;
3934 }
3935
3936 if ((val < CFG_ROAM_INTRA_BAND_MIN) ||
3937 (val > CFG_ROAM_INTRA_BAND_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003938 hdd_err("intra band mode value %d is out of range (Min: %d Max: %d)",
3939 val,
3940 CFG_ROAM_INTRA_BAND_MIN,
3941 CFG_ROAM_INTRA_BAND_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003942 ret = -EINVAL;
3943 goto exit;
3944 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003945 hdd_info("Received Command to change intra band = %d",
3946 val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003947
3948 hdd_ctx->config->nRoamIntraBand = val;
3949 sme_set_roam_intra_band(hdd_ctx->hHal, val);
3950
3951exit:
3952 return ret;
3953}
3954
3955static int drv_cmd_get_roam_intra_band(hdd_adapter_t *adapter,
3956 hdd_context_t *hdd_ctx,
3957 uint8_t *command,
3958 uint8_t command_len,
3959 hdd_priv_data_t *priv_data)
3960{
3961 int ret = 0;
3962 uint16_t val = sme_get_roam_intra_band(hdd_ctx->hHal);
3963 char extra[32];
3964 uint8_t len = 0;
3965
3966 /* value is interms of msec */
3967 len = scnprintf(extra, sizeof(extra), "%s %d",
3968 "GETROAMINTRABAND", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303969 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003970 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003971 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003972 ret = -EFAULT;
3973 }
3974
3975 return ret;
3976}
3977
3978static int drv_cmd_set_scan_n_probes(hdd_adapter_t *adapter,
3979 hdd_context_t *hdd_ctx,
3980 uint8_t *command,
3981 uint8_t command_len,
3982 hdd_priv_data_t *priv_data)
3983{
3984 int ret = 0;
3985 uint8_t *value = command;
3986 uint8_t nProbes = CFG_ROAM_SCAN_N_PROBES_DEFAULT;
3987
3988 /* Move pointer to ahead of SETSCANNPROBES<delimiter> */
3989 value = value + command_len + 1;
3990
3991 /* Convert the value from ascii to integer */
3992 ret = kstrtou8(value, 10, &nProbes);
3993 if (ret < 0) {
3994 /*
3995 * If the input value is greater than max value of datatype,
3996 * then also kstrtou8 fails
3997 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003998 hdd_err("kstrtou8 failed range [%d - %d]",
3999 CFG_ROAM_SCAN_N_PROBES_MIN,
4000 CFG_ROAM_SCAN_N_PROBES_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004001 ret = -EINVAL;
4002 goto exit;
4003 }
4004
4005 if ((nProbes < CFG_ROAM_SCAN_N_PROBES_MIN) ||
4006 (nProbes > CFG_ROAM_SCAN_N_PROBES_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004007 hdd_err("NProbes value %d is out of range (Min: %d Max: %d)",
4008 nProbes,
4009 CFG_ROAM_SCAN_N_PROBES_MIN,
4010 CFG_ROAM_SCAN_N_PROBES_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004011 ret = -EINVAL;
4012 goto exit;
4013 }
4014
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004015 hdd_info("Received Command to Set nProbes = %d",
4016 nProbes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004017
4018 hdd_ctx->config->nProbes = nProbes;
4019 sme_update_roam_scan_n_probes(hdd_ctx->hHal,
4020 adapter->sessionId, nProbes);
4021
4022exit:
4023 return ret;
4024}
4025
4026static int drv_cmd_get_scan_n_probes(hdd_adapter_t *adapter,
4027 hdd_context_t *hdd_ctx,
4028 uint8_t *command,
4029 uint8_t command_len,
4030 hdd_priv_data_t *priv_data)
4031{
4032 int ret = 0;
4033 uint8_t val = sme_get_roam_scan_n_probes(hdd_ctx->hHal);
4034 char extra[32];
4035 uint8_t len = 0;
4036
4037 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304038 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004039 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004040 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004041 ret = -EFAULT;
4042 }
4043
4044 return ret;
4045}
4046
4047static int drv_cmd_set_scan_home_away_time(hdd_adapter_t *adapter,
4048 hdd_context_t *hdd_ctx,
4049 uint8_t *command,
4050 uint8_t command_len,
4051 hdd_priv_data_t *priv_data)
4052{
4053 int ret = 0;
4054 uint8_t *value = command;
4055 uint16_t homeAwayTime = CFG_ROAM_SCAN_HOME_AWAY_TIME_DEFAULT;
4056
4057 /* input value is in units of msec */
4058
4059 /* Move pointer to ahead of SETSCANHOMEAWAYTIME<delimiter> */
4060 value = value + command_len + 1;
4061
4062 /* Convert the value from ascii to integer */
4063 ret = kstrtou16(value, 10, &homeAwayTime);
4064 if (ret < 0) {
4065 /*
4066 * If the input value is greater than max value of datatype,
4067 * then also kstrtou8 fails
4068 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004069 hdd_err("kstrtou8 failed range [%d - %d]",
4070 CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN,
4071 CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004072 ret = -EINVAL;
4073 goto exit;
4074 }
4075
4076 if ((homeAwayTime < CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN) ||
4077 (homeAwayTime > CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004078 hdd_err("homeAwayTime value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004079 homeAwayTime,
4080 CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN,
4081 CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX);
4082 ret = -EINVAL;
4083 goto exit;
4084 }
4085
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004086 hdd_info("Received Command to Set scan away time = %d",
4087 homeAwayTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004088
4089 if (hdd_ctx->config->nRoamScanHomeAwayTime !=
4090 homeAwayTime) {
4091 hdd_ctx->config->nRoamScanHomeAwayTime = homeAwayTime;
4092 sme_update_roam_scan_home_away_time(hdd_ctx->hHal,
4093 adapter->sessionId,
4094 homeAwayTime,
4095 true);
4096 }
4097
4098exit:
4099 return ret;
4100}
4101
4102static int drv_cmd_get_scan_home_away_time(hdd_adapter_t *adapter,
4103 hdd_context_t *hdd_ctx,
4104 uint8_t *command,
4105 uint8_t command_len,
4106 hdd_priv_data_t *priv_data)
4107{
4108 int ret = 0;
4109 uint16_t val = sme_get_roam_scan_home_away_time(hdd_ctx->hHal);
4110 char extra[32];
4111 uint8_t len = 0;
4112
4113 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304114 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004115
4116 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004117 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004118 ret = -EFAULT;
4119 }
4120
4121 return ret;
4122}
4123
4124static int drv_cmd_reassoc(hdd_adapter_t *adapter,
4125 hdd_context_t *hdd_ctx,
4126 uint8_t *command,
4127 uint8_t command_len,
4128 hdd_priv_data_t *priv_data)
4129{
4130 return hdd_parse_reassoc(adapter, command);
4131}
4132
4133static int drv_cmd_set_wes_mode(hdd_adapter_t *adapter,
4134 hdd_context_t *hdd_ctx,
4135 uint8_t *command,
4136 uint8_t command_len,
4137 hdd_priv_data_t *priv_data)
4138{
4139 int ret = 0;
4140 uint8_t *value = command;
4141 uint8_t wesMode = CFG_ENABLE_WES_MODE_NAME_DEFAULT;
4142
4143 /* Move pointer to ahead of SETWESMODE<delimiter> */
4144 value = value + command_len + 1;
4145
4146 /* Convert the value from ascii to integer */
4147 ret = kstrtou8(value, 10, &wesMode);
4148 if (ret < 0) {
4149 /*
4150 * If the input value is greater than max value of datatype,
4151 * then also kstrtou8 fails
4152 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004153 hdd_err("kstrtou8 failed range [%d - %d]",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004154 CFG_ENABLE_WES_MODE_NAME_MIN,
4155 CFG_ENABLE_WES_MODE_NAME_MAX);
4156 ret = -EINVAL;
4157 goto exit;
4158 }
4159
4160 if ((wesMode < CFG_ENABLE_WES_MODE_NAME_MIN) ||
4161 (wesMode > CFG_ENABLE_WES_MODE_NAME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004162 hdd_err("WES Mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004163 wesMode,
4164 CFG_ENABLE_WES_MODE_NAME_MIN,
4165 CFG_ENABLE_WES_MODE_NAME_MAX);
4166 ret = -EINVAL;
4167 goto exit;
4168 }
4169
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004170 hdd_info("Received Command to Set WES Mode rssi diff = %d",
4171 wesMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004172
4173 hdd_ctx->config->isWESModeEnabled = wesMode;
4174 sme_update_wes_mode(hdd_ctx->hHal, wesMode, adapter->sessionId);
4175
4176exit:
4177 return ret;
4178}
4179
4180static int drv_cmd_get_wes_mode(hdd_adapter_t *adapter,
4181 hdd_context_t *hdd_ctx,
4182 uint8_t *command,
4183 uint8_t command_len,
4184 hdd_priv_data_t *priv_data)
4185{
4186 int ret = 0;
4187 bool wesMode = sme_get_wes_mode(hdd_ctx->hHal);
4188 char extra[32];
4189 uint8_t len = 0;
4190
4191 len = scnprintf(extra, sizeof(extra), "%s %d", command, wesMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304192 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004193 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004194 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004195 ret = -EFAULT;
4196 }
4197
4198 return ret;
4199}
4200
4201static int drv_cmd_set_opportunistic_rssi_diff(hdd_adapter_t *adapter,
4202 hdd_context_t *hdd_ctx,
4203 uint8_t *command,
4204 uint8_t command_len,
4205 hdd_priv_data_t *priv_data)
4206{
4207 int ret = 0;
4208 uint8_t *value = command;
4209 uint8_t nOpportunisticThresholdDiff =
4210 CFG_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF_DEFAULT;
4211
4212 /* Move pointer to ahead of SETOPPORTUNISTICRSSIDIFF<delimiter> */
4213 value = value + command_len + 1;
4214
4215 /* Convert the value from ascii to integer */
4216 ret = kstrtou8(value, 10, &nOpportunisticThresholdDiff);
4217 if (ret < 0) {
4218 /*
4219 * If the input value is greater than max value of datatype,
4220 * then also kstrtou8 fails
4221 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004222 hdd_err("kstrtou8 failed.");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004223 ret = -EINVAL;
4224 goto exit;
4225 }
4226
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004227 hdd_info("Received Command to Set Opportunistic Threshold diff = %d",
4228 nOpportunisticThresholdDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004229
4230 sme_set_roam_opportunistic_scan_threshold_diff(hdd_ctx->hHal,
4231 adapter->sessionId,
4232 nOpportunisticThresholdDiff);
4233
4234exit:
4235 return ret;
4236}
4237
4238static int drv_cmd_get_opportunistic_rssi_diff(hdd_adapter_t *adapter,
4239 hdd_context_t *hdd_ctx,
4240 uint8_t *command,
4241 uint8_t command_len,
4242 hdd_priv_data_t *priv_data)
4243{
4244 int ret = 0;
4245 int8_t val = sme_get_roam_opportunistic_scan_threshold_diff(
4246 hdd_ctx->hHal);
4247 char extra[32];
4248 uint8_t len = 0;
4249
4250 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304251 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004252 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004253 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004254 ret = -EFAULT;
4255 }
4256
4257 return ret;
4258}
4259
4260static int drv_cmd_set_roam_rescan_rssi_diff(hdd_adapter_t *adapter,
4261 hdd_context_t *hdd_ctx,
4262 uint8_t *command,
4263 uint8_t command_len,
4264 hdd_priv_data_t *priv_data)
4265{
4266 int ret = 0;
4267 uint8_t *value = command;
4268 uint8_t nRoamRescanRssiDiff = CFG_ROAM_RESCAN_RSSI_DIFF_DEFAULT;
4269
4270 /* Move pointer to ahead of SETROAMRESCANRSSIDIFF<delimiter> */
4271 value = value + command_len + 1;
4272
4273 /* Convert the value from ascii to integer */
4274 ret = kstrtou8(value, 10, &nRoamRescanRssiDiff);
4275 if (ret < 0) {
4276 /*
4277 * If the input value is greater than max value of datatype,
4278 * then also kstrtou8 fails
4279 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004280 hdd_err("kstrtou8 failed.");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004281 ret = -EINVAL;
4282 goto exit;
4283 }
4284
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004285 hdd_info("Received Command to Set Roam Rescan RSSI Diff = %d",
4286 nRoamRescanRssiDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004287
4288 sme_set_roam_rescan_rssi_diff(hdd_ctx->hHal,
4289 adapter->sessionId,
4290 nRoamRescanRssiDiff);
4291
4292exit:
4293 return ret;
4294}
4295
4296static int drv_cmd_get_roam_rescan_rssi_diff(hdd_adapter_t *adapter,
4297 hdd_context_t *hdd_ctx,
4298 uint8_t *command,
4299 uint8_t command_len,
4300 hdd_priv_data_t *priv_data)
4301{
4302 int ret = 0;
4303 uint8_t val = sme_get_roam_rescan_rssi_diff(hdd_ctx->hHal);
4304 char extra[32];
4305 uint8_t len = 0;
4306
4307 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304308 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004309 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004310 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004311 ret = -EFAULT;
4312 }
4313
4314 return ret;
4315}
4316
4317static int drv_cmd_set_fast_roam(hdd_adapter_t *adapter,
4318 hdd_context_t *hdd_ctx,
4319 uint8_t *command,
4320 uint8_t command_len,
4321 hdd_priv_data_t *priv_data)
4322{
4323 int ret = 0;
4324 uint8_t *value = command;
4325 uint8_t lfrMode = CFG_LFR_FEATURE_ENABLED_DEFAULT;
4326
Deepak Dhamdherea2785822016-11-17 01:17:45 -08004327 if (!adapter->fast_roaming_allowed) {
4328 hdd_err("Roaming is always disabled on this interface");
4329 goto exit;
4330 }
4331
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004332 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4333 value = value + command_len + 1;
4334
4335 /* Convert the value from ascii to integer */
4336 ret = kstrtou8(value, 10, &lfrMode);
4337 if (ret < 0) {
4338 /*
4339 * If the input value is greater than max value of datatype,
4340 * then also kstrtou8 fails
4341 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004342 hdd_err("kstrtou8 failed range [%d - %d]",
4343 CFG_LFR_FEATURE_ENABLED_MIN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004344 CFG_LFR_FEATURE_ENABLED_MAX);
4345 ret = -EINVAL;
4346 goto exit;
4347 }
4348
4349 if ((lfrMode < CFG_LFR_FEATURE_ENABLED_MIN) ||
4350 (lfrMode > CFG_LFR_FEATURE_ENABLED_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004351 hdd_err("lfr mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004352 lfrMode,
4353 CFG_LFR_FEATURE_ENABLED_MIN,
4354 CFG_LFR_FEATURE_ENABLED_MAX);
4355 ret = -EINVAL;
4356 goto exit;
4357 }
4358
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004359 hdd_info("Received Command to change lfr mode = %d",
4360 lfrMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004361
4362 hdd_ctx->config->isFastRoamIniFeatureEnabled = lfrMode;
4363 sme_update_is_fast_roam_ini_feature_enabled(hdd_ctx->hHal,
4364 adapter->
4365 sessionId,
4366 lfrMode);
4367
4368exit:
4369 return ret;
4370}
4371
4372static int drv_cmd_set_fast_transition(hdd_adapter_t *adapter,
4373 hdd_context_t *hdd_ctx,
4374 uint8_t *command,
4375 uint8_t command_len,
4376 hdd_priv_data_t *priv_data)
4377{
4378 int ret = 0;
4379 uint8_t *value = command;
4380 uint8_t ft = CFG_FAST_TRANSITION_ENABLED_NAME_DEFAULT;
4381
4382 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4383 value = value + command_len + 1;
4384
4385 /* Convert the value from ascii to integer */
4386 ret = kstrtou8(value, 10, &ft);
4387 if (ret < 0) {
4388 /*
4389 * If the input value is greater than max value of datatype,
4390 * then also kstrtou8 fails
4391 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004392 hdd_err("kstrtou8 failed range [%d - %d]",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004393 CFG_FAST_TRANSITION_ENABLED_NAME_MIN,
4394 CFG_FAST_TRANSITION_ENABLED_NAME_MAX);
4395 ret = -EINVAL;
4396 goto exit;
4397 }
4398
4399 if ((ft < CFG_FAST_TRANSITION_ENABLED_NAME_MIN) ||
4400 (ft > CFG_FAST_TRANSITION_ENABLED_NAME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004401 hdd_err("ft mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004402 ft,
4403 CFG_FAST_TRANSITION_ENABLED_NAME_MIN,
4404 CFG_FAST_TRANSITION_ENABLED_NAME_MAX);
4405 ret = -EINVAL;
4406 goto exit;
4407 }
4408
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004409 hdd_info("Received Command to change ft mode = %d", ft);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004410
4411 hdd_ctx->config->isFastTransitionEnabled = ft;
4412 sme_update_fast_transition_enabled(hdd_ctx->hHal, ft);
4413
4414exit:
4415 return ret;
4416}
4417
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004418static int drv_cmd_fast_reassoc(hdd_adapter_t *adapter,
4419 hdd_context_t *hdd_ctx,
4420 uint8_t *command,
4421 uint8_t command_len,
4422 hdd_priv_data_t *priv_data)
4423{
4424 int ret = 0;
4425 uint8_t *value = command;
4426 uint8_t channel = 0;
4427 tSirMacAddr targetApBssid;
4428 uint32_t roamId = 0;
4429 tCsrRoamModifyProfileFields modProfileFields;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004430 tCsrHandoffRequest handoffInfo;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004431 hdd_station_ctx_t *pHddStaCtx;
4432
Krunal Sonibe766b02016-03-10 13:00:44 -08004433 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004434 hdd_warn("Unsupported in mode %s(%d)",
4435 hdd_device_mode_to_string(adapter->device_mode),
4436 adapter->device_mode);
4437 return -EINVAL;
4438 }
4439
4440 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
4441
4442 /* if not associated, no need to proceed with reassoc */
4443 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004444 hdd_info("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004445 ret = -EINVAL;
4446 goto exit;
4447 }
4448
4449 ret = hdd_parse_reassoc_command_v1_data(value, targetApBssid,
4450 &channel);
4451 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004452 hdd_err("Failed to parse reassoc command data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004453 goto exit;
4454 }
4455
4456 /*
4457 * if the target bssid is same as currently associated AP,
4458 * issue reassoc to same AP
4459 */
Ankit Guptaa5076012016-09-14 11:32:19 -07004460 if (!qdf_mem_cmp(targetApBssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004461 pHddStaCtx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05304462 QDF_MAC_ADDR_SIZE)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004463 hdd_info("Reassoc BSSID is same as currently associated AP bssid");
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304464 if (roaming_offload_enabled(hdd_ctx)) {
4465 hdd_wma_send_fastreassoc_cmd((int)adapter->sessionId,
Padma, Santhosh Kumaraf9f08c2016-10-21 21:26:29 +05304466 targetApBssid,
4467 pHddStaCtx->conn_info.operationChannel);
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304468 } else {
4469 sme_get_modify_profile_fields(hdd_ctx->hHal,
4470 adapter->sessionId,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004471 &modProfileFields);
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304472 sme_roam_reassoc(hdd_ctx->hHal, adapter->sessionId,
4473 NULL, modProfileFields, &roamId, 1);
4474 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004475 return 0;
4476 }
4477
Padma, Santhosh Kumaraf9f08c2016-10-21 21:26:29 +05304478 /* Check channel number is a valid channel number */
4479 if (QDF_STATUS_SUCCESS !=
4480 wlan_hdd_validate_operation_channel(adapter, channel)) {
4481 hdd_err("Invalid Channel [%d]", channel);
4482 return -EINVAL;
4483 }
4484
Varun Reddy Yeturud351a6c2016-03-16 14:01:00 -07004485 if (roaming_offload_enabled(hdd_ctx)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004486 hdd_wma_send_fastreassoc_cmd((int)adapter->sessionId,
4487 targetApBssid, (int)channel);
4488 goto exit;
4489 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004490 /* Proceed with reassoc */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004491 handoffInfo.channel = channel;
4492 handoffInfo.src = FASTREASSOC;
Varun Reddy Yeturua66f9c52016-02-17 09:58:40 -08004493 qdf_mem_copy(handoffInfo.bssid.bytes, targetApBssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004494 sizeof(tSirMacAddr));
4495 sme_handoff_request(hdd_ctx->hHal, adapter->sessionId,
4496 &handoffInfo);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004497exit:
4498 return ret;
4499}
4500
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004501static int drv_cmd_set_roam_scan_control(hdd_adapter_t *adapter,
4502 hdd_context_t *hdd_ctx,
4503 uint8_t *command,
4504 uint8_t command_len,
4505 hdd_priv_data_t *priv_data)
4506{
4507 int ret = 0;
4508 uint8_t *value = command;
4509 uint8_t roamScanControl = 0;
4510
4511 /* Move pointer to ahead of SETROAMSCANCONTROL<delimiter> */
4512 value = value + command_len + 1;
4513
4514 /* Convert the value from ascii to integer */
4515 ret = kstrtou8(value, 10, &roamScanControl);
4516 if (ret < 0) {
4517 /*
4518 * If the input value is greater than max value of datatype,
4519 * then also kstrtou8 fails
4520 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004521 hdd_err("kstrtou8 failed ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004522 ret = -EINVAL;
4523 goto exit;
4524 }
4525
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004526 hdd_info("Received Command to Set roam scan control = %d",
4527 roamScanControl);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004528
4529 if (0 != roamScanControl) {
4530 ret = 0; /* return success but ignore param value "true" */
4531 goto exit;
4532 }
4533
4534 sme_set_roam_scan_control(hdd_ctx->hHal,
4535 adapter->sessionId,
4536 roamScanControl);
4537
4538exit:
4539 return ret;
4540}
4541
4542static int drv_cmd_set_okc_mode(hdd_adapter_t *adapter,
4543 hdd_context_t *hdd_ctx,
4544 uint8_t *command,
4545 uint8_t command_len,
4546 hdd_priv_data_t *priv_data)
4547{
4548 int ret = 0;
4549 uint8_t *value = command;
4550 uint8_t okcMode = CFG_OKC_FEATURE_ENABLED_DEFAULT;
4551
4552 /*
4553 * Check if the features OKC/ESE/11R are supported simultaneously,
4554 * then this operation is not permitted (return FAILURE)
4555 */
4556 if (sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
4557 hdd_is_okc_mode_enabled(hdd_ctx) &&
4558 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004559 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004560 ret = -EPERM;
4561 goto exit;
4562 }
4563
4564 /* Move pointer to ahead of SETOKCMODE<delimiter> */
4565 value = value + command_len + 1;
4566
4567 /* Convert the value from ascii to integer */
4568 ret = kstrtou8(value, 10, &okcMode);
4569 if (ret < 0) {
4570 /*
4571 * If the input value is greater than max value of datatype,
4572 * then also kstrtou8 fails
4573 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004574 hdd_err("kstrtou8 failed range [%d - %d]",
4575 CFG_OKC_FEATURE_ENABLED_MIN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004576 CFG_OKC_FEATURE_ENABLED_MAX);
4577 ret = -EINVAL;
4578 goto exit;
4579 }
4580
4581 if ((okcMode < CFG_OKC_FEATURE_ENABLED_MIN) ||
4582 (okcMode > CFG_OKC_FEATURE_ENABLED_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004583 hdd_err("Okc mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004584 okcMode,
4585 CFG_OKC_FEATURE_ENABLED_MIN,
4586 CFG_OKC_FEATURE_ENABLED_MAX);
4587 ret = -EINVAL;
4588 goto exit;
4589 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004590 hdd_info("Received Command to change okc mode = %d",
4591 okcMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004592
4593 hdd_ctx->config->isOkcIniFeatureEnabled = okcMode;
4594
4595exit:
4596 return ret;
4597}
4598
4599static int drv_cmd_get_roam_scan_control(hdd_adapter_t *adapter,
4600 hdd_context_t *hdd_ctx,
4601 uint8_t *command,
4602 uint8_t command_len,
4603 hdd_priv_data_t *priv_data)
4604{
4605 int ret = 0;
4606 bool roamScanControl = sme_get_roam_scan_control(hdd_ctx->hHal);
4607 char extra[32];
4608 uint8_t len = 0;
4609
4610 len = scnprintf(extra, sizeof(extra), "%s %d",
4611 command, roamScanControl);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304612 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004613 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004614 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004615 ret = -EFAULT;
4616 }
4617
4618 return ret;
4619}
4620
4621static int drv_cmd_bt_coex_mode(hdd_adapter_t *adapter,
4622 hdd_context_t *hdd_ctx,
4623 uint8_t *command,
4624 uint8_t command_len,
4625 hdd_priv_data_t *priv_data)
4626{
4627 int ret = 0;
4628 char *bcMode;
4629
4630 bcMode = command + 11;
4631 if ('1' == *bcMode) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004632 hdd_debug("BTCOEXMODE %d", *bcMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004633 hdd_ctx->btCoexModeSet = true;
4634 ret = wlan_hdd_scan_abort(adapter);
4635 if (ret < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004636 hdd_err("Failed to abort existing scan status: %d",
4637 ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004638 }
4639 } else if ('2' == *bcMode) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004640 hdd_debug("BTCOEXMODE %d", *bcMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004641 hdd_ctx->btCoexModeSet = false;
4642 }
4643
4644 return ret;
4645}
4646
4647static int drv_cmd_scan_active(hdd_adapter_t *adapter,
4648 hdd_context_t *hdd_ctx,
4649 uint8_t *command,
4650 uint8_t command_len,
4651 hdd_priv_data_t *priv_data)
4652{
4653 hdd_ctx->ioctl_scan_mode = eSIR_ACTIVE_SCAN;
4654 return 0;
4655}
4656
4657static int drv_cmd_scan_passive(hdd_adapter_t *adapter,
4658 hdd_context_t *hdd_ctx,
4659 uint8_t *command,
4660 uint8_t command_len,
4661 hdd_priv_data_t *priv_data)
4662{
4663 hdd_ctx->ioctl_scan_mode = eSIR_PASSIVE_SCAN;
4664 return 0;
4665}
4666
4667static int drv_cmd_get_dwell_time(hdd_adapter_t *adapter,
4668 hdd_context_t *hdd_ctx,
4669 uint8_t *command,
4670 uint8_t command_len,
4671 hdd_priv_data_t *priv_data)
4672{
4673 int ret = 0;
4674 struct hdd_config *pCfg =
4675 (WLAN_HDD_GET_CTX(adapter))->config;
4676 char extra[32];
4677 uint8_t len = 0;
4678
4679 memset(extra, 0, sizeof(extra));
4680 ret = hdd_get_dwell_time(pCfg, command, extra, sizeof(extra), &len);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304681 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004682 if (ret != 0 || copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004683 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004684 ret = -EFAULT;
4685 goto exit;
4686 }
4687 ret = len;
4688exit:
4689 return ret;
4690}
4691
4692static int drv_cmd_set_dwell_time(hdd_adapter_t *adapter,
4693 hdd_context_t *hdd_ctx,
4694 uint8_t *command,
4695 uint8_t command_len,
4696 hdd_priv_data_t *priv_data)
4697{
4698 return hdd_set_dwell_time(adapter, command);
4699}
4700
4701static int drv_cmd_miracast(hdd_adapter_t *adapter,
4702 hdd_context_t *hdd_ctx,
4703 uint8_t *command,
4704 uint8_t command_len,
4705 hdd_priv_data_t *priv_data)
4706{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304707 QDF_STATUS ret_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004708 int ret = 0;
4709 tHalHandle hHal;
4710 uint8_t filterType = 0;
4711 hdd_context_t *pHddCtx = NULL;
4712 uint8_t *value;
4713
4714 pHddCtx = WLAN_HDD_GET_CTX(adapter);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05304715 if (wlan_hdd_validate_context(pHddCtx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004716 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004717
4718 hHal = pHddCtx->hHal;
4719 value = command + 9;
4720
4721 /* Convert the value from ascii to integer */
4722 ret = kstrtou8(value, 10, &filterType);
4723 if (ret < 0) {
4724 /*
4725 * If the input value is greater than max value of datatype,
4726 * then also kstrtou8 fails
4727 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004728 hdd_err("kstrtou8 failed range ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004729 ret = -EINVAL;
4730 goto exit;
4731 }
4732 if ((filterType < WLAN_HDD_DRIVER_MIRACAST_CFG_MIN_VAL)
4733 || (filterType >
4734 WLAN_HDD_DRIVER_MIRACAST_CFG_MAX_VAL)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004735 hdd_err("Accepted Values are 0 to 2. 0-Disabled, 1-Source, 2-Sink ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004736 ret = -EINVAL;
4737 goto exit;
4738 }
4739 /* Filtertype value should be either 0-Disabled, 1-Source, 2-sink */
4740 pHddCtx->miracast_value = filterType;
4741
4742 ret_status = sme_set_miracast(hHal, filterType);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304743 if (QDF_STATUS_SUCCESS != ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004744 hdd_err("Failed to set miracast");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004745 return -EBUSY;
4746 }
4747
Tushnim Bhattacharyyaca50b322015-12-28 17:14:36 -08004748 if (cds_is_mcc_in_24G())
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004749 return cds_set_mas(adapter, filterType);
4750
4751exit:
4752 return ret;
4753}
4754
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004755/* Function header is left blank intentionally */
4756static int hdd_parse_set_ibss_oui_data_command(uint8_t *command, uint8_t *ie,
4757 int32_t *oui_length, int32_t limit)
4758{
4759 uint8_t len;
4760 uint8_t data;
4761
4762 while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) {
4763 command++;
4764 limit--;
4765 }
4766
4767 len = 2;
4768
4769 while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) &&
4770 (limit > 1)) {
4771 sscanf(command, "%02x", (unsigned int *)&data);
4772 ie[len++] = data;
4773 command += 2;
4774 limit -= 2;
4775 }
4776
4777 *oui_length = len - 2;
4778
4779 while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) {
4780 command++;
4781 limit--;
4782 }
4783
4784 while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) &&
4785 (limit > 1)) {
4786 sscanf(command, "%02x", (unsigned int *)&data);
4787 ie[len++] = data;
4788 command += 2;
4789 limit -= 2;
4790 }
4791
4792 ie[0] = IE_EID_VENDOR;
4793 ie[1] = len - 2;
4794
4795 return len;
4796}
4797
4798/**
4799 * drv_cmd_set_ibss_beacon_oui_data() - set ibss oui data command
4800 * @adapter: Pointer to adapter
4801 * @hdd_ctx: Pointer to HDD context
4802 * @command: Pointer to command string
4803 * @command_len : Command length
4804 * @priv_data : Pointer to priv data
4805 *
4806 * Return:
4807 * int status code
4808 */
4809static int drv_cmd_set_ibss_beacon_oui_data(hdd_adapter_t *adapter,
4810 hdd_context_t *hdd_ctx,
4811 uint8_t *command,
4812 uint8_t command_len,
4813 hdd_priv_data_t *priv_data)
4814{
4815 int i = 0;
4816 int status;
4817 int ret = 0;
4818 uint8_t *ibss_ie;
4819 int32_t oui_length = 0;
4820 uint32_t ibss_ie_length;
4821 uint8_t *value = command;
4822 tSirModifyIE ibssModifyIE;
4823 tCsrRoamProfile *pRoamProfile;
4824 hdd_wext_state_t *pWextState;
4825
4826
Krunal Sonibe766b02016-03-10 13:00:44 -08004827 if (QDF_IBSS_MODE != adapter->device_mode) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004828 hdd_info("Device_mode %s(%d) not IBSS",
4829 hdd_device_mode_to_string(adapter->device_mode),
4830 adapter->device_mode);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004831 return ret;
4832 }
4833
4834 pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(adapter);
4835
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004836 hdd_info("received command %s", ((char *)value));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004837
4838
4839 /* validate argument of command */
4840 if (strlen(value) <= command_len) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004841 hdd_err("No arguments in command length %zu",
4842 strlen(value));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004843 ret = -EFAULT;
4844 goto exit;
4845 }
4846
4847 /* moving to arguments of commands */
4848 value = value + command_len;
4849 command_len = strlen(value);
4850
4851 /* oui_data can't be less than 3 bytes */
4852 if (command_len < (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004853 hdd_err("Invalid SETIBSSBEACONOUIDATA command length %d",
4854 command_len);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004855 ret = -EFAULT;
4856 goto exit;
4857 }
4858
4859 ibss_ie = qdf_mem_malloc(command_len);
4860 if (!ibss_ie) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004861 hdd_err("Could not allocate memory for command length %d",
4862 command_len);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004863 ret = -ENOMEM;
4864 goto exit;
4865 }
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004866
4867 ibss_ie_length = hdd_parse_set_ibss_oui_data_command(value, ibss_ie,
4868 &oui_length,
4869 command_len);
4870 if (ibss_ie_length <= (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004871 hdd_err("Could not parse command %s return length %d",
4872 value, ibss_ie_length);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004873 ret = -EFAULT;
4874 qdf_mem_free(ibss_ie);
4875 goto exit;
4876 }
4877
4878 pRoamProfile = &pWextState->roamProfile;
4879
4880 qdf_copy_macaddr(&ibssModifyIE.bssid,
4881 pRoamProfile->BSSIDs.bssid);
4882
4883 ibssModifyIE.smeSessionId = adapter->sessionId;
4884 ibssModifyIE.notify = true;
4885 ibssModifyIE.ieID = IE_EID_VENDOR;
4886 ibssModifyIE.ieIDLen = ibss_ie_length;
4887 ibssModifyIE.ieBufferlength = ibss_ie_length;
4888 ibssModifyIE.pIEBuffer = ibss_ie;
4889 ibssModifyIE.oui_length = oui_length;
4890
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004891 hdd_warn("ibss_ie length %d oui_length %d ibss_ie:",
4892 ibss_ie_length, oui_length);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004893 while (i < ibssModifyIE.ieBufferlength)
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004894 hdd_warn("0x%x", ibss_ie[i++]);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004895
4896 /* Probe Bcn modification */
4897 sme_modify_add_ie(WLAN_HDD_GET_HAL_CTX(adapter),
4898 &ibssModifyIE, eUPDATE_IE_PROBE_BCN);
4899
4900 /* Populating probe resp frame */
4901 sme_modify_add_ie(WLAN_HDD_GET_HAL_CTX(adapter),
4902 &ibssModifyIE, eUPDATE_IE_PROBE_RESP);
4903
4904 qdf_mem_free(ibss_ie);
4905
4906 status = sme_send_cesium_enable_ind((tHalHandle)(hdd_ctx->hHal),
4907 adapter->sessionId);
4908 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004909 hdd_err("Could not send cesium enable indication %d",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004910 status);
4911 ret = -EINVAL;
4912 goto exit;
4913 }
4914
4915exit:
4916 return ret;
4917}
4918
4919static int drv_cmd_set_rmc_enable(hdd_adapter_t *adapter,
4920 hdd_context_t *hdd_ctx,
4921 uint8_t *command,
4922 uint8_t command_len,
4923 hdd_priv_data_t *priv_data)
4924{
4925 int ret = 0;
4926 uint8_t *value = command;
4927 uint8_t ucRmcEnable = 0;
4928 int status;
4929
Krunal Sonibe766b02016-03-10 13:00:44 -08004930 if ((QDF_IBSS_MODE != adapter->device_mode) &&
4931 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004932 hdd_err("Received SETRMCENABLE cmd in invalid mode %s(%d)",
4933 hdd_device_mode_to_string(adapter->device_mode),
4934 adapter->device_mode);
4935 hdd_err("SETRMCENABLE cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004936 ret = -EINVAL;
4937 goto exit;
4938 }
4939
4940 status = hdd_parse_setrmcenable_command(value, &ucRmcEnable);
4941 if (status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004942 hdd_err("Invalid SETRMCENABLE command ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004943 ret = -EINVAL;
4944 goto exit;
4945 }
4946
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004947 hdd_info("ucRmcEnable %d ", ucRmcEnable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004948
4949 if (true == ucRmcEnable) {
4950 status = sme_enable_rmc((tHalHandle)
4951 (hdd_ctx->hHal),
4952 adapter->sessionId);
4953 } else if (false == ucRmcEnable) {
4954 status = sme_disable_rmc((tHalHandle)
4955 (hdd_ctx->hHal),
4956 adapter->sessionId);
4957 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004958 hdd_err("Invalid SETRMCENABLE command %d",
4959 ucRmcEnable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004960 ret = -EINVAL;
4961 goto exit;
4962 }
4963
4964 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004965 hdd_err("SETRMC %d failed status %d",
4966 ucRmcEnable, status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004967 ret = -EINVAL;
4968 goto exit;
4969 }
4970
4971exit:
4972 return ret;
4973}
4974
4975static int drv_cmd_set_rmc_action_period(hdd_adapter_t *adapter,
4976 hdd_context_t *hdd_ctx,
4977 uint8_t *command,
4978 uint8_t command_len,
4979 hdd_priv_data_t *priv_data)
4980{
4981 int ret = 0;
4982 uint8_t *value = command;
4983 uint32_t uActionPeriod = 0;
4984 int status;
4985
Krunal Sonibe766b02016-03-10 13:00:44 -08004986 if ((QDF_IBSS_MODE != adapter->device_mode) &&
4987 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004988 hdd_err("Received SETRMC cmd in invalid mode %s(%d)",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004989 hdd_device_mode_to_string(adapter->device_mode),
4990 adapter->device_mode);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004991 hdd_err("SETRMC cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004992 ret = -EINVAL;
4993 goto exit;
4994 }
4995
4996 status = hdd_parse_setrmcactionperiod_command(value, &uActionPeriod);
4997 if (status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004998 hdd_err("Invalid SETRMCACTIONPERIOD command ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004999 ret = -EINVAL;
5000 goto exit;
5001 }
5002
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005003 hdd_info("uActionPeriod %d ",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005004 uActionPeriod);
5005
5006 if (sme_cfg_set_int(hdd_ctx->hHal,
5007 WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY,
5008 uActionPeriod)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005009 hdd_err("Could not set SETRMCACTIONPERIOD %d",
5010 uActionPeriod);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005011 ret = -EINVAL;
5012 goto exit;
5013 }
5014
5015 status = sme_send_rmc_action_period((tHalHandle)(hdd_ctx->hHal),
5016 adapter->sessionId);
5017 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005018 hdd_err("Could not send cesium enable indication %d",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005019 status);
5020 ret = -EINVAL;
5021 goto exit;
5022 }
5023
5024exit:
5025 return ret;
5026}
5027
5028static int drv_cmd_get_ibss_peer_info_all(hdd_adapter_t *adapter,
5029 hdd_context_t *hdd_ctx,
5030 uint8_t *command,
5031 uint8_t command_len,
5032 hdd_priv_data_t *priv_data)
5033{
5034 int ret = 0;
5035 int status = QDF_STATUS_SUCCESS;
5036 hdd_station_ctx_t *pHddStaCtx = NULL;
5037 char *extra = NULL;
5038 int idx = 0;
5039 int length = 0;
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005040 uint8_t mac_addr[QDF_MAC_ADDR_SIZE];
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005041 uint32_t numOfBytestoPrint = 0;
5042
Krunal Sonibe766b02016-03-10 13:00:44 -08005043 if (QDF_IBSS_MODE != adapter->device_mode) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005044 hdd_warn("Unsupported in mode %s(%d)",
5045 hdd_device_mode_to_string(adapter->device_mode),
5046 adapter->device_mode);
5047 return -EINVAL;
5048 }
5049
5050 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005051 hdd_info("Received GETIBSSPEERINFOALL Command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005052
5053 /* Handle the command */
5054 status = hdd_cfg80211_get_ibss_peer_info_all(adapter);
5055 if (QDF_STATUS_SUCCESS == status) {
5056 /*
5057 * The variable extra needed to be allocated on the heap since
5058 * amount of memory required to copy the data for 32 devices
5059 * exceeds the size of 1024 bytes of default stack size. On
5060 * 64 bit devices, the default max stack size of 2048 bytes
5061 */
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07005062 extra = qdf_mem_malloc(WLAN_MAX_BUF_SIZE);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005063
5064 if (NULL == extra) {
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07005065 hdd_err("memory allocation failed");
5066 ret = -ENOMEM;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005067 goto exit;
5068 }
5069
5070 /* Copy number of stations */
5071 length = scnprintf(extra, WLAN_MAX_BUF_SIZE, "%d ",
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005072 pHddStaCtx->ibss_peer_info.numPeers);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005073 numOfBytestoPrint = length;
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005074 for (idx = 0; idx < pHddStaCtx->ibss_peer_info.numPeers;
5075 idx++) {
5076 int8_t rssi;
5077 uint32_t tx_rate;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005078
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005079 qdf_mem_copy(mac_addr,
5080 pHddStaCtx->ibss_peer_info.peerInfoParams[idx].
5081 mac_addr, sizeof(mac_addr));
5082
5083 tx_rate =
5084 pHddStaCtx->ibss_peer_info.peerInfoParams[idx].
5085 txRate;
Sriram Madhvapathi85df7c72016-09-30 11:35:28 +05305086 /*
5087 * Only lower 3 bytes are rate info. Mask of the MSByte
5088 */
5089 tx_rate &= 0x00FFFFFF;
5090
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005091 rssi = pHddStaCtx->ibss_peer_info.peerInfoParams[idx].
5092 rssi;
5093
5094 length += scnprintf((extra + length),
5095 WLAN_MAX_BUF_SIZE - length,
5096 "%02x:%02x:%02x:%02x:%02x:%02x %d %d ",
5097 mac_addr[0], mac_addr[1], mac_addr[2],
5098 mac_addr[3], mac_addr[4], mac_addr[5],
5099 tx_rate, rssi);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005100 /*
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005101 * cdf_trace_msg has limitation of 512 bytes for the
5102 * print buffer. Hence printing the data in two chunks.
5103 * The first chunk will have the data for 16 devices
5104 * and the second chunk will have the rest.
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005105 */
5106 if (idx < NUM_OF_STA_DATA_TO_PRINT)
5107 numOfBytestoPrint = length;
5108 }
5109
5110 /*
5111 * Copy the data back into buffer, if the data to copy is
5112 * more than 512 bytes than we will split the data and do
5113 * it in two shots
5114 */
5115 if (copy_to_user(priv_data->buf, extra, numOfBytestoPrint)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005116 hdd_err("Copy into user data buffer failed ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005117 ret = -EFAULT;
5118 goto exit;
5119 }
5120
5121 priv_data->buf[numOfBytestoPrint] = '\0';
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005122 hdd_debug("%s", priv_data->buf);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005123
5124 if (length > numOfBytestoPrint) {
5125 if (copy_to_user
5126 (priv_data->buf + numOfBytestoPrint,
5127 extra + numOfBytestoPrint,
5128 length - numOfBytestoPrint + 1)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005129 hdd_err("Copy into user data buffer failed ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005130 ret = -EFAULT;
5131 goto exit;
5132 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005133 hdd_debug("%s", &priv_data->buf[numOfBytestoPrint]);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005134 }
5135
5136 /* Free temporary buffer */
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07005137 qdf_mem_free(extra);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005138 } else {
5139 /* Command failed, log error */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005140 hdd_err("GETIBSSPEERINFOALL command failed with status code %d",
5141 status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005142 ret = -EINVAL;
5143 goto exit;
5144 }
5145 ret = 0;
5146
5147exit:
5148 return ret;
5149}
5150
5151/* Peer Info <Peer Addr> command */
5152static int drv_cmd_get_ibss_peer_info(hdd_adapter_t *adapter,
5153 hdd_context_t *hdd_ctx,
5154 uint8_t *command,
5155 uint8_t command_len,
5156 hdd_priv_data_t *priv_data)
5157{
5158 int ret = 0;
5159 uint8_t *value = command;
5160 QDF_STATUS status;
5161 hdd_station_ctx_t *pHddStaCtx = NULL;
5162 char extra[128] = { 0 };
5163 uint32_t length = 0;
5164 uint8_t staIdx = 0;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005165 struct qdf_mac_addr peerMacAddr;
5166
Krunal Sonibe766b02016-03-10 13:00:44 -08005167 if (QDF_IBSS_MODE != adapter->device_mode) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005168 hdd_warn("Unsupported in mode %s(%d)",
5169 hdd_device_mode_to_string(adapter->device_mode),
5170 adapter->device_mode);
5171 return -EINVAL;
5172 }
5173
5174 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5175
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005176 hdd_info("Received GETIBSSPEERINFO Command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005177
5178 /* if there are no peers, no need to continue with the command */
5179 if (eConnectionState_IbssConnected !=
5180 pHddStaCtx->conn_info.connState) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005181 hdd_info("No IBSS Peers coalesced");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005182 ret = -EINVAL;
5183 goto exit;
5184 }
5185
5186 /* Parse the incoming command buffer */
5187 status = hdd_parse_get_ibss_peer_info(value, &peerMacAddr);
5188 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005189 hdd_err("Invalid GETIBSSPEERINFO command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005190 ret = -EINVAL;
5191 goto exit;
5192 }
5193
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005194 /* Get station index for the peer mac address and sanitize it */
Deepak Dhamdhere5872c8c2016-06-02 15:51:47 -07005195 hdd_get_peer_sta_id(pHddStaCtx, &peerMacAddr, &staIdx);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005196
Naveen Rawatc45d1622016-07-05 12:20:09 -07005197 if (staIdx > MAX_PEERS) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005198 hdd_err("Invalid StaIdx %d returned", staIdx);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005199 ret = -EINVAL;
5200 goto exit;
5201 }
5202
5203 /* Handle the command */
5204 status = hdd_cfg80211_get_ibss_peer_info(adapter, staIdx);
5205 if (QDF_STATUS_SUCCESS == status) {
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005206 uint32_t txRate =
5207 pHddStaCtx->ibss_peer_info.peerInfoParams[0].txRate;
Sriram Madhvapathi85df7c72016-09-30 11:35:28 +05305208 /* Only lower 3 bytes are rate info. Mask of the MSByte */
5209 txRate &= 0x00FFFFFF;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005210
5211 length = scnprintf(extra, sizeof(extra), "%d %d",
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005212 (int)txRate,
5213 (int)pHddStaCtx->ibss_peer_info.
5214 peerInfoParams[0].rssi);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005215
5216 /* Copy the data back into buffer */
5217 if (copy_to_user(priv_data->buf, &extra, length + 1)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005218 hdd_err("copy data to user buffer failed GETIBSSPEERINFO command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005219 ret = -EFAULT;
5220 goto exit;
5221 }
5222 } else {
5223 /* Command failed, log error */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005224 hdd_err("GETIBSSPEERINFO command failed with status code %d",
5225 status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005226 ret = -EINVAL;
5227 goto exit;
5228 }
5229
5230 /* Success ! */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005231 hdd_debug("%s", priv_data->buf);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005232 ret = 0;
5233
5234exit:
5235 return ret;
5236}
5237
5238static int drv_cmd_set_rmc_tx_rate(hdd_adapter_t *adapter,
5239 hdd_context_t *hdd_ctx,
5240 uint8_t *command,
5241 uint8_t command_len,
5242 hdd_priv_data_t *priv_data)
5243{
5244 int ret = 0;
5245 uint8_t *value = command;
5246 uint32_t uRate = 0;
5247 tTxrateinfoflags txFlags = 0;
5248 tSirRateUpdateInd rateUpdateParams = {0};
5249 int status;
5250 struct hdd_config *pConfig = hdd_ctx->config;
5251
Krunal Sonibe766b02016-03-10 13:00:44 -08005252 if ((QDF_IBSS_MODE != adapter->device_mode) &&
5253 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005254 hdd_err("Received SETRMCTXRATE cmd in invalid mode %s(%d)",
5255 hdd_device_mode_to_string(adapter->device_mode),
5256 adapter->device_mode);
5257 hdd_err("SETRMCTXRATE cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005258 ret = -EINVAL;
5259 goto exit;
5260 }
5261
5262 status = hdd_parse_setrmcrate_command(value, &uRate, &txFlags);
5263 if (status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005264 hdd_err("Invalid SETRMCTXRATE command ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005265 ret = -EINVAL;
5266 goto exit;
5267 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005268 hdd_info("uRate %d ", uRate);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005269 /* -1 implies ignore this param */
5270 rateUpdateParams.ucastDataRate = -1;
5271
5272 /*
5273 * Fill the user specifieed RMC rate param
5274 * and the derived tx flags.
5275 */
5276 rateUpdateParams.nss = (pConfig->enable2x2 == 0) ? 0 : 1;
5277 rateUpdateParams.reliableMcastDataRate = uRate;
5278 rateUpdateParams.reliableMcastDataRateTxFlag = txFlags;
5279 rateUpdateParams.dev_mode = adapter->device_mode;
5280 rateUpdateParams.bcastDataRate = -1;
5281 memcpy(rateUpdateParams.bssid.bytes,
5282 adapter->macAddressCurrent.bytes,
5283 sizeof(rateUpdateParams.bssid));
5284 status = sme_send_rate_update_ind((tHalHandle) (hdd_ctx->hHal),
5285 &rateUpdateParams);
5286
5287exit:
5288 return ret;
5289}
5290
5291static int drv_cmd_set_ibss_tx_fail_event(hdd_adapter_t *adapter,
5292 hdd_context_t *hdd_ctx,
5293 uint8_t *command,
5294 uint8_t command_len,
5295 hdd_priv_data_t *priv_data)
5296{
5297 int ret = 0;
5298 char *value;
5299 uint8_t tx_fail_count = 0;
5300 uint16_t pid = 0;
5301
5302 value = command;
5303
5304 ret = hdd_parse_ibsstx_fail_event_params(value, &tx_fail_count, &pid);
5305
5306 if (0 != ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005307 hdd_info("Failed to parse SETIBSSTXFAILEVENT arguments");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005308 goto exit;
5309 }
5310
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005311 hdd_info("tx_fail_cnt=%hhu, pid=%hu", tx_fail_count, pid);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005312
5313 if (0 == tx_fail_count) {
5314 /* Disable TX Fail Indication */
5315 if (QDF_STATUS_SUCCESS ==
5316 sme_tx_fail_monitor_start_stop_ind(hdd_ctx->hHal,
5317 tx_fail_count,
5318 NULL)) {
5319 cesium_pid = 0;
5320 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005321 hdd_err("failed to disable TX Fail Event ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005322 ret = -EINVAL;
5323 }
5324 } else {
5325 if (QDF_STATUS_SUCCESS ==
5326 sme_tx_fail_monitor_start_stop_ind(hdd_ctx->hHal,
5327 tx_fail_count,
5328 (void *)hdd_tx_fail_ind_callback)) {
5329 cesium_pid = pid;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005330 hdd_info("Registered Cesium pid %u",
5331 cesium_pid);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005332 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005333 hdd_err("Failed to enable TX Fail Monitoring");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005334 ret = -EINVAL;
5335 }
5336 }
5337
5338exit:
5339 return ret;
5340}
5341
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08005342#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005343static int drv_cmd_set_ccx_roam_scan_channels(hdd_adapter_t *adapter,
5344 hdd_context_t *hdd_ctx,
5345 uint8_t *command,
5346 uint8_t command_len,
5347 hdd_priv_data_t *priv_data)
5348{
5349 int ret = 0;
5350 uint8_t *value = command;
5351 uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
5352 uint8_t numChannels = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305353 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005354
5355 ret = hdd_parse_channellist(value, ChannelList, &numChannels);
5356 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005357 hdd_err("Failed to parse channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005358 goto exit;
5359 }
5360 if (numChannels > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005361 hdd_err("number of channels (%d) supported exceeded max (%d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005362 numChannels,
5363 WNI_CFG_VALID_CHANNEL_LIST_LEN);
5364 ret = -EINVAL;
5365 goto exit;
5366 }
5367 status = sme_set_ese_roam_scan_channel_list(hdd_ctx->hHal,
5368 adapter->sessionId,
5369 ChannelList,
5370 numChannels);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305371 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005372 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005373 ret = -EINVAL;
5374 goto exit;
5375 }
5376
5377exit:
5378 return ret;
5379}
5380
5381static int drv_cmd_get_tsm_stats(hdd_adapter_t *adapter,
5382 hdd_context_t *hdd_ctx,
5383 uint8_t *command,
5384 uint8_t command_len,
5385 hdd_priv_data_t *priv_data)
5386{
5387 int ret = 0;
5388 uint8_t *value = command;
5389 char extra[128] = { 0 };
5390 int len = 0;
5391 uint8_t tid = 0;
5392 hdd_station_ctx_t *pHddStaCtx;
5393 tAniTrafStrmMetrics tsm_metrics;
5394
Krunal Sonibe766b02016-03-10 13:00:44 -08005395 if ((QDF_STA_MODE != adapter->device_mode) &&
5396 (QDF_P2P_CLIENT_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005397 hdd_warn("Unsupported in mode %s(%d)",
5398 hdd_device_mode_to_string(adapter->device_mode),
5399 adapter->device_mode);
5400 return -EINVAL;
5401 }
5402
5403 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5404
5405 /* if not associated, return error */
5406 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005407 hdd_err("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005408 ret = -EINVAL;
5409 goto exit;
5410 }
5411
5412 /* Move pointer to ahead of GETTSMSTATS<delimiter> */
5413 value = value + command_len + 1;
5414
5415 /* Convert the value from ascii to integer */
5416 ret = kstrtou8(value, 10, &tid);
5417 if (ret < 0) {
5418 /*
5419 * If the input value is greater than max value of datatype,
5420 * then also kstrtou8 fails
5421 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005422 hdd_err("kstrtou8 failed range [%d - %d]",
5423 TID_MIN_VALUE,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005424 TID_MAX_VALUE);
5425 ret = -EINVAL;
5426 goto exit;
5427 }
5428 if ((tid < TID_MIN_VALUE) || (tid > TID_MAX_VALUE)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005429 hdd_err("tid value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005430 tid, TID_MIN_VALUE, TID_MAX_VALUE);
5431 ret = -EINVAL;
5432 goto exit;
5433 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005434 hdd_info("Received Command to get tsm stats tid = %d",
5435 tid);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305436 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005437 hdd_get_tsm_stats(adapter, tid, &tsm_metrics)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005438 hdd_err("failed to get tsm stats");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005439 ret = -EFAULT;
5440 goto exit;
5441 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005442 hdd_info(
5443 "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 -08005444 tsm_metrics.UplinkPktQueueDly,
5445 tsm_metrics.UplinkPktQueueDlyHist[0],
5446 tsm_metrics.UplinkPktQueueDlyHist[1],
5447 tsm_metrics.UplinkPktQueueDlyHist[2],
5448 tsm_metrics.UplinkPktQueueDlyHist[3],
5449 tsm_metrics.UplinkPktTxDly,
5450 tsm_metrics.UplinkPktLoss,
5451 tsm_metrics.UplinkPktCount,
5452 tsm_metrics.RoamingCount,
5453 tsm_metrics.RoamingDly);
5454 /*
5455 * Output TSM stats is of the format
5456 * GETTSMSTATS [PktQueueDly]
5457 * [PktQueueDlyHist[0]]:[PktQueueDlyHist[1]] ...[RoamingDly]
5458 * eg., GETTSMSTATS 10 1:0:0:161 20 1 17 8 39800
5459 */
5460 len = scnprintf(extra,
5461 sizeof(extra),
5462 "%s %d %d:%d:%d:%d %u %d %d %d %d",
5463 command,
5464 tsm_metrics.UplinkPktQueueDly,
5465 tsm_metrics.UplinkPktQueueDlyHist[0],
5466 tsm_metrics.UplinkPktQueueDlyHist[1],
5467 tsm_metrics.UplinkPktQueueDlyHist[2],
5468 tsm_metrics.UplinkPktQueueDlyHist[3],
5469 tsm_metrics.UplinkPktTxDly,
5470 tsm_metrics.UplinkPktLoss,
5471 tsm_metrics.UplinkPktCount,
5472 tsm_metrics.RoamingCount,
5473 tsm_metrics.RoamingDly);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305474 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005475 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005476 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005477 ret = -EFAULT;
5478 goto exit;
5479 }
5480
5481exit:
5482 return ret;
5483}
5484
5485static int drv_cmd_set_cckm_ie(hdd_adapter_t *adapter,
5486 hdd_context_t *hdd_ctx,
5487 uint8_t *command,
5488 uint8_t command_len,
5489 hdd_priv_data_t *priv_data)
5490{
5491 int ret;
5492 uint8_t *value = command;
5493 uint8_t *cckmIe = NULL;
5494 uint8_t cckmIeLen = 0;
5495
5496 ret = hdd_parse_get_cckm_ie(value, &cckmIe, &cckmIeLen);
5497 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005498 hdd_err("Failed to parse cckm ie data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005499 goto exit;
5500 }
5501
5502 if (cckmIeLen > DOT11F_IE_RSN_MAX_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005503 hdd_err("CCKM Ie input length is more than max[%d]",
5504 DOT11F_IE_RSN_MAX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005505 if (NULL != cckmIe) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305506 qdf_mem_free(cckmIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005507 cckmIe = NULL;
5508 }
5509 ret = -EINVAL;
5510 goto exit;
5511 }
5512
5513 sme_set_cckm_ie(hdd_ctx->hHal, adapter->sessionId,
5514 cckmIe, cckmIeLen);
5515 if (NULL != cckmIe) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305516 qdf_mem_free(cckmIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005517 cckmIe = NULL;
5518 }
5519
5520exit:
5521 return ret;
5522}
5523
5524static int drv_cmd_ccx_beacon_req(hdd_adapter_t *adapter,
5525 hdd_context_t *hdd_ctx,
5526 uint8_t *command,
5527 uint8_t command_len,
5528 hdd_priv_data_t *priv_data)
5529{
5530 int ret;
5531 uint8_t *value = command;
5532 tCsrEseBeaconReq eseBcnReq;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305533 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005534
Krunal Sonibe766b02016-03-10 13:00:44 -08005535 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005536 hdd_warn("Unsupported in mode %s(%d)",
5537 hdd_device_mode_to_string(adapter->device_mode),
5538 adapter->device_mode);
5539 return -EINVAL;
5540 }
5541
5542 ret = hdd_parse_ese_beacon_req(value, &eseBcnReq);
5543 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005544 hdd_err("Failed to parse ese beacon req");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005545 goto exit;
5546 }
5547
5548 if (!hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005549 hdd_info("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005550 hdd_indicate_ese_bcn_report_no_results(adapter,
5551 eseBcnReq.bcnReq[0].measurementToken,
5552 0x02, /* BIT(1) set for measurement done */
5553 0); /* no BSS */
5554 goto exit;
5555 }
5556
5557 status = sme_set_ese_beacon_request(hdd_ctx->hHal,
5558 adapter->sessionId,
5559 &eseBcnReq);
5560
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305561 if (QDF_STATUS_E_RESOURCES == status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005562 hdd_info("sme_set_ese_beacon_request failed (%d), a request already in progress",
5563 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005564 ret = -EBUSY;
5565 goto exit;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305566 } else if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005567 hdd_err("sme_set_ese_beacon_request failed (%d)",
5568 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005569 ret = -EINVAL;
5570 goto exit;
5571 }
5572
5573exit:
5574 return ret;
5575}
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005576
5577/**
5578 * drv_cmd_ccx_plm_req() - Set ESE PLM request
5579 * @adapter: Pointer to the HDD adapter
5580 * @hdd_ctx: Pointer to the HDD context
5581 * @command: Driver command string
5582 * @command_len: Driver command string length
5583 * @priv_data: Private data coming with the driver command. Unused here
5584 *
5585 * This function handles driver command that sets the ESE PLM request
5586 *
5587 * Return: 0 on success; negative errno otherwise
5588 */
5589static int drv_cmd_ccx_plm_req(hdd_adapter_t *adapter,
5590 hdd_context_t *hdd_ctx,
5591 uint8_t *command,
5592 uint8_t command_len,
5593 hdd_priv_data_t *priv_data)
5594{
5595 int ret = 0;
5596 uint8_t *value = command;
5597 QDF_STATUS status = QDF_STATUS_SUCCESS;
5598 tpSirPlmReq pPlmRequest = NULL;
5599
5600 pPlmRequest = qdf_mem_malloc(sizeof(tSirPlmReq));
5601 if (NULL == pPlmRequest) {
5602 ret = -ENOMEM;
5603 goto exit;
5604 }
5605
5606 status = hdd_parse_plm_cmd(value, pPlmRequest);
5607 if (QDF_STATUS_SUCCESS != status) {
5608 qdf_mem_free(pPlmRequest);
5609 pPlmRequest = NULL;
5610 ret = -EINVAL;
5611 goto exit;
5612 }
5613 pPlmRequest->sessionId = adapter->sessionId;
5614
5615 status = sme_set_plm_request(hdd_ctx->hHal, pPlmRequest);
5616 if (QDF_STATUS_SUCCESS != status) {
5617 qdf_mem_free(pPlmRequest);
5618 pPlmRequest = NULL;
5619 ret = -EINVAL;
5620 goto exit;
5621 }
5622
5623exit:
5624 return ret;
5625}
5626
5627/**
5628 * drv_cmd_set_ccx_mode() - Set ESE mode
5629 * @adapter: Pointer to the HDD adapter
5630 * @hdd_ctx: Pointer to the HDD context
5631 * @command: Driver command string
5632 * @command_len: Driver command string length
5633 * @priv_data: Private data coming with the driver command. Unused here
5634 *
5635 * This function handles driver command that sets ESE mode
5636 *
5637 * Return: 0 on success; negative errno otherwise
5638 */
5639static int drv_cmd_set_ccx_mode(hdd_adapter_t *adapter,
5640 hdd_context_t *hdd_ctx,
5641 uint8_t *command,
5642 uint8_t command_len,
5643 hdd_priv_data_t *priv_data)
5644{
5645 int ret = 0;
5646 uint8_t *value = command;
5647 uint8_t eseMode = CFG_ESE_FEATURE_ENABLED_DEFAULT;
5648
5649 /*
5650 * Check if the features OKC/ESE/11R are supported simultaneously,
5651 * then this operation is not permitted (return FAILURE)
5652 */
5653 if (sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
5654 hdd_is_okc_mode_enabled(hdd_ctx) &&
5655 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
5656 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
5657 ret = -EPERM;
5658 goto exit;
5659 }
5660
Deepak Dhamdherea2785822016-11-17 01:17:45 -08005661 if (!adapter->fast_roaming_allowed) {
5662 hdd_warn("Fast roaming is not allowed on this device hence this operation is not permitted!");
5663 ret = -EPERM;
5664 goto exit;
5665 }
5666
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005667 /* Move pointer to ahead of SETCCXMODE<delimiter> */
5668 value = value + command_len + 1;
5669
5670 /* Convert the value from ascii to integer */
5671 ret = kstrtou8(value, 10, &eseMode);
5672 if (ret < 0) {
5673 /*
5674 * If the input value is greater than max value of datatype,
5675 * then also kstrtou8 fails
5676 */
5677 hdd_err("kstrtou8 failed range [%d - %d]",
5678 CFG_ESE_FEATURE_ENABLED_MIN,
5679 CFG_ESE_FEATURE_ENABLED_MAX);
5680 ret = -EINVAL;
5681 goto exit;
5682 }
5683
5684 if ((eseMode < CFG_ESE_FEATURE_ENABLED_MIN) ||
5685 (eseMode > CFG_ESE_FEATURE_ENABLED_MAX)) {
5686 hdd_err("Ese mode value %d is out of range (Min: %d Max: %d)",
5687 eseMode,
5688 CFG_ESE_FEATURE_ENABLED_MIN,
5689 CFG_ESE_FEATURE_ENABLED_MAX);
5690 ret = -EINVAL;
5691 goto exit;
5692 }
5693 hdd_info("Received Command to change ese mode = %d", eseMode);
5694
5695 hdd_ctx->config->isEseIniFeatureEnabled = eseMode;
5696 sme_update_is_ese_feature_enabled(hdd_ctx->hHal,
5697 adapter->sessionId,
5698 eseMode);
5699
5700exit:
5701 return ret;
5702}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08005703#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005704
5705static int drv_cmd_set_mc_rate(hdd_adapter_t *adapter,
5706 hdd_context_t *hdd_ctx,
5707 uint8_t *command,
5708 uint8_t command_len,
5709 hdd_priv_data_t *priv_data)
5710{
5711 int ret = 0;
5712 uint8_t *value = command;
5713 int targetRate;
5714
5715 /* input value is in units of hundred kbps */
5716
5717 /* Move pointer to ahead of SETMCRATE<delimiter> */
5718 value = value + command_len + 1;
5719
5720 /* Convert the value from ascii to integer, decimal base */
5721 ret = kstrtouint(value, 10, &targetRate);
5722
5723 ret = wlan_hdd_set_mc_rate(adapter, targetRate);
5724 return ret;
5725}
5726
5727static int drv_cmd_max_tx_power(hdd_adapter_t *adapter,
5728 hdd_context_t *hdd_ctx,
5729 uint8_t *command,
5730 uint8_t command_len,
5731 hdd_priv_data_t *priv_data)
5732{
5733 int ret = 0;
5734 int status;
5735 int txPower;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305736 QDF_STATUS qdf_status;
5737 QDF_STATUS smeStatus;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005738 uint8_t *value = command;
Anurag Chouhan6d760662016-02-20 16:05:43 +05305739 struct qdf_mac_addr bssid = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
5740 struct qdf_mac_addr selfMac = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005741 hdd_adapter_list_node_t *pAdapterNode = NULL;
5742 hdd_adapter_list_node_t *pNext = NULL;
5743
5744 status = hdd_parse_setmaxtxpower_command(value, &txPower);
5745 if (status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005746 hdd_err("Invalid MAXTXPOWER command ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005747 ret = -EINVAL;
5748 goto exit;
5749 }
5750
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305751 qdf_status = hdd_get_front_adapter(hdd_ctx, &pAdapterNode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005752 while (NULL != pAdapterNode
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305753 && QDF_STATUS_SUCCESS == qdf_status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005754 adapter = pAdapterNode->pAdapter;
5755 /* Assign correct self MAC address */
Anurag Chouhanc5548422016-02-24 18:33:27 +05305756 qdf_copy_macaddr(&bssid,
Srinivas Girigowda97215232015-09-24 12:26:28 -07005757 &adapter->macAddressCurrent);
Anurag Chouhanc5548422016-02-24 18:33:27 +05305758 qdf_copy_macaddr(&selfMac,
Srinivas Girigowda97215232015-09-24 12:26:28 -07005759 &adapter->macAddressCurrent);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005760
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005761 hdd_info("Device mode %d max tx power %d selfMac: "
5762 MAC_ADDRESS_STR " bssId: " MAC_ADDRESS_STR " ",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005763 adapter->device_mode, txPower,
Srinivas Girigowda97215232015-09-24 12:26:28 -07005764 MAC_ADDR_ARRAY(selfMac.bytes),
5765 MAC_ADDR_ARRAY(bssid.bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005766
Srinivas Girigowda97215232015-09-24 12:26:28 -07005767 smeStatus = sme_set_max_tx_power(hdd_ctx->hHal,
5768 bssid, selfMac, txPower);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305769 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005770 hdd_err("Set max tx power failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005771 ret = -EINVAL;
5772 goto exit;
5773 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005774 hdd_info("Set max tx power success");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305775 qdf_status = hdd_get_next_adapter(hdd_ctx, pAdapterNode,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005776 &pNext);
5777 pAdapterNode = pNext;
5778 }
5779
5780exit:
5781 return ret;
5782}
5783
5784static int drv_cmd_set_dfs_scan_mode(hdd_adapter_t *adapter,
5785 hdd_context_t *hdd_ctx,
5786 uint8_t *command,
5787 uint8_t command_len,
5788 hdd_priv_data_t *priv_data)
5789{
5790 int ret = 0;
5791 uint8_t *value = command;
5792 uint8_t dfsScanMode = CFG_ROAMING_DFS_CHANNEL_DEFAULT;
5793
5794 /* Move pointer to ahead of SETDFSSCANMODE<delimiter> */
5795 value = value + command_len + 1;
5796
5797 /* Convert the value from ascii to integer */
5798 ret = kstrtou8(value, 10, &dfsScanMode);
5799 if (ret < 0) {
5800 /*
5801 * If the input value is greater than max value of datatype,
5802 * then also kstrtou8 fails
5803 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005804 hdd_err("kstrtou8 failed range [%d - %d]",
5805 CFG_ROAMING_DFS_CHANNEL_MIN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005806 CFG_ROAMING_DFS_CHANNEL_MAX);
5807 ret = -EINVAL;
5808 goto exit;
5809 }
5810
5811 if ((dfsScanMode < CFG_ROAMING_DFS_CHANNEL_MIN) ||
5812 (dfsScanMode > CFG_ROAMING_DFS_CHANNEL_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005813 hdd_err("dfsScanMode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005814 dfsScanMode,
5815 CFG_ROAMING_DFS_CHANNEL_MIN,
5816 CFG_ROAMING_DFS_CHANNEL_MAX);
5817 ret = -EINVAL;
5818 goto exit;
5819 }
5820
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005821 hdd_info("Received Command to Set DFS Scan Mode = %d",
5822 dfsScanMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005823
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005824 /* When DFS scanning is disabled, the DFS channels need to be
5825 * removed from the operation of device.
5826 */
5827 ret = wlan_hdd_disable_dfs_chan_scan(hdd_ctx, adapter,
5828 (dfsScanMode == CFG_ROAMING_DFS_CHANNEL_DISABLED));
5829 if (ret < 0) {
5830 /* Some conditions prevented it from disabling DFS channels */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005831 hdd_err("disable/enable DFS channel request was denied");
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005832 goto exit;
5833 }
5834
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005835 hdd_ctx->config->allowDFSChannelRoam = dfsScanMode;
5836 sme_update_dfs_scan_mode(hdd_ctx->hHal, adapter->sessionId,
5837 dfsScanMode);
5838
5839exit:
5840 return ret;
5841}
5842
5843static int drv_cmd_get_dfs_scan_mode(hdd_adapter_t *adapter,
5844 hdd_context_t *hdd_ctx,
5845 uint8_t *command,
5846 uint8_t command_len,
5847 hdd_priv_data_t *priv_data)
5848{
5849 int ret = 0;
5850 uint8_t dfsScanMode = sme_get_dfs_scan_mode(hdd_ctx->hHal);
5851 char extra[32];
5852 uint8_t len = 0;
5853
5854 len = scnprintf(extra, sizeof(extra), "%s %d", command, dfsScanMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305855 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005856 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005857 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005858 ret = -EFAULT;
5859 }
5860
5861 return ret;
5862}
5863
5864static int drv_cmd_get_link_status(hdd_adapter_t *adapter,
5865 hdd_context_t *hdd_ctx,
5866 uint8_t *command,
5867 uint8_t command_len,
5868 hdd_priv_data_t *priv_data)
5869{
5870 int ret = 0;
5871 int value = wlan_hdd_get_link_status(adapter);
5872 char extra[32];
5873 uint8_t len;
5874
5875 len = scnprintf(extra, sizeof(extra), "%s %d", command, value);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305876 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005877 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005878 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005879 ret = -EFAULT;
5880 }
5881
5882 return ret;
5883}
5884
5885#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
5886static int drv_cmd_enable_ext_wow(hdd_adapter_t *adapter,
5887 hdd_context_t *hdd_ctx,
5888 uint8_t *command,
5889 uint8_t command_len,
5890 hdd_priv_data_t *priv_data)
5891{
5892 uint8_t *value = command;
5893 int set_value;
5894
5895 /* Move pointer to ahead of ENABLEEXTWOW */
5896 value = value + command_len;
5897
Anurag Chouhan43e0c752016-09-03 16:17:02 +05305898 if (!(sscanf(value, "%d", &set_value))) {
5899 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
5900 ("No input identified"));
5901 return -EINVAL;
5902 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005903
5904 return hdd_enable_ext_wow_parser(adapter,
5905 adapter->sessionId,
5906 set_value);
5907}
5908
5909static int drv_cmd_set_app1_params(hdd_adapter_t *adapter,
5910 hdd_context_t *hdd_ctx,
5911 uint8_t *command,
5912 uint8_t command_len,
5913 hdd_priv_data_t *priv_data)
5914{
5915 int ret;
5916 uint8_t *value = command;
5917
5918 /* Move pointer to ahead of SETAPP1PARAMS */
5919 value = value + command_len;
5920
5921 ret = hdd_set_app_type1_parser(adapter,
5922 value, strlen(value));
5923 if (ret >= 0)
5924 hdd_ctx->is_extwow_app_type1_param_set = true;
5925
5926 return ret;
5927}
5928
5929static int drv_cmd_set_app2_params(hdd_adapter_t *adapter,
5930 hdd_context_t *hdd_ctx,
5931 uint8_t *command,
5932 uint8_t command_len,
5933 hdd_priv_data_t *priv_data)
5934{
5935 int ret;
5936 uint8_t *value = command;
5937
5938 /* Move pointer to ahead of SETAPP2PARAMS */
5939 value = value + command_len;
5940
5941 ret = hdd_set_app_type2_parser(adapter, value, strlen(value));
5942 if (ret >= 0)
5943 hdd_ctx->is_extwow_app_type2_param_set = true;
5944
5945 return ret;
5946}
5947#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
5948
5949#ifdef FEATURE_WLAN_TDLS
5950/**
5951 * drv_cmd_tdls_secondary_channel_offset() - secondary tdls off channel offset
5952 * @adapter: Pointer to the HDD adapter
5953 * @hdd_ctx: Pointer to the HDD context
5954 * @command: Driver command string
5955 * @command_len: Driver command string length
5956 * @priv_data: Private data coming with the driver command. Unused here
5957 *
5958 * This function handles driver command that sets the secondary tdls off channel
5959 * offset
5960 *
5961 * Return: 0 on success; negative errno otherwise
5962 */
5963static int drv_cmd_tdls_secondary_channel_offset(hdd_adapter_t *adapter,
5964 hdd_context_t *hdd_ctx,
5965 uint8_t *command,
5966 uint8_t command_len,
5967 hdd_priv_data_t *priv_data)
5968{
5969 int ret;
5970 uint8_t *value = command;
5971 int set_value;
5972
5973 /* Move pointer to point the string */
5974 value += command_len;
5975
5976 ret = sscanf(value, "%d", &set_value);
5977 if (ret != 1)
5978 return -EINVAL;
5979
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005980 hdd_info("Tdls offchannel offset:%d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005981
5982 ret = hdd_set_tdls_secoffchanneloffset(hdd_ctx, set_value);
5983
5984 return ret;
5985}
5986
5987/**
5988 * drv_cmd_tdls_off_channel_mode() - set tdls off channel mode
5989 * @adapter: Pointer to the HDD adapter
5990 * @hdd_ctx: Pointer to the HDD context
5991 * @command: Driver command string
5992 * @command_len: Driver command string length
5993 * @priv_data: Private data coming with the driver command. Unused here
5994 *
5995 * This function handles driver command that sets tdls off channel mode
5996 *
5997 * Return: 0 on success; negative errno otherwise
5998 */
5999static int drv_cmd_tdls_off_channel_mode(hdd_adapter_t *adapter,
6000 hdd_context_t *hdd_ctx,
6001 uint8_t *command,
6002 uint8_t command_len,
6003 hdd_priv_data_t *priv_data)
6004{
6005 int ret;
6006 uint8_t *value = command;
6007 int set_value;
6008
6009 /* Move pointer to point the string */
6010 value += command_len;
6011
6012 ret = sscanf(value, "%d", &set_value);
6013 if (ret != 1)
6014 return -EINVAL;
6015
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006016 hdd_info("Tdls offchannel mode:%d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006017
6018 ret = hdd_set_tdls_offchannelmode(adapter, set_value);
6019
6020 return ret;
6021}
6022
6023/**
6024 * drv_cmd_tdls_off_channel() - set tdls off channel number
6025 * @adapter: Pointer to the HDD adapter
6026 * @hdd_ctx: Pointer to the HDD context
6027 * @command: Driver command string
6028 * @command_len: Driver command string length
6029 * @priv_data: Private data coming with the driver command. Unused here
6030 *
6031 * This function handles driver command that sets tdls off channel number
6032 *
6033 * Return: 0 on success; negative errno otherwise
6034 */
6035static int drv_cmd_tdls_off_channel(hdd_adapter_t *adapter,
6036 hdd_context_t *hdd_ctx,
6037 uint8_t *command,
6038 uint8_t command_len,
6039 hdd_priv_data_t *priv_data)
6040{
6041 int ret;
6042 uint8_t *value = command;
6043 int set_value;
6044
6045 /* Move pointer to point the string */
6046 value += command_len;
6047
6048 ret = sscanf(value, "%d", &set_value);
6049 if (ret != 1)
6050 return -EINVAL;
6051
Krishna Kumaar Natarajan4d090352015-10-26 18:30:53 -07006052 if (CDS_IS_DFS_CH(set_value)) {
6053 hdd_err("DFS channel %d is passed for hdd_set_tdls_offchannel",
6054 set_value);
6055 return -EINVAL;
6056 }
6057
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006058 hdd_info("Tdls offchannel num: %d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006059
6060 ret = hdd_set_tdls_offchannel(hdd_ctx, set_value);
6061
6062 return ret;
6063}
6064
6065/**
6066 * drv_cmd_tdls_scan() - set tdls scan type
6067 * @adapter: Pointer to the HDD adapter
6068 * @hdd_ctx: Pointer to the HDD context
6069 * @command: Driver command string
6070 * @command_len: Driver command string length
6071 * @priv_data: Private data coming with the driver command. Unused here
6072 *
6073 * This function handles driver command that sets tdls scan type
6074 *
6075 * Return: 0 on success; negative errno otherwise
6076 */
6077static int drv_cmd_tdls_scan(hdd_adapter_t *adapter,
6078 hdd_context_t *hdd_ctx,
6079 uint8_t *command,
6080 uint8_t command_len,
6081 hdd_priv_data_t *priv_data)
6082{
6083 int ret;
6084 uint8_t *value = command;
6085 int set_value;
6086
6087 /* Move pointer to point the string */
6088 value += command_len;
6089
6090 ret = sscanf(value, "%d", &set_value);
6091 if (ret != 1)
6092 return -EINVAL;
6093
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006094 hdd_info("Tdls scan type val: %d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006095
6096 ret = hdd_set_tdls_scan_type(hdd_ctx, set_value);
6097
6098 return ret;
6099}
6100#endif
6101
6102static int drv_cmd_get_rssi(hdd_adapter_t *adapter,
6103 hdd_context_t *hdd_ctx,
6104 uint8_t *command,
6105 uint8_t command_len,
6106 hdd_priv_data_t *priv_data)
6107{
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006108 int ret = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006109 int8_t rssi = 0;
6110 char extra[32];
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006111
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006112 uint8_t len = 0;
6113
6114 wlan_hdd_get_rssi(adapter, &rssi);
6115
6116 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
Anurag Chouhan6d760662016-02-20 16:05:43 +05306117 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006118
6119 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006120 hdd_err("Failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006121 ret = -EFAULT;
6122 }
6123
6124 return ret;
6125}
6126
6127static int drv_cmd_get_linkspeed(hdd_adapter_t *adapter,
6128 hdd_context_t *hdd_ctx,
6129 uint8_t *command,
6130 uint8_t command_len,
6131 hdd_priv_data_t *priv_data)
6132{
6133 int ret;
6134 uint32_t link_speed = 0;
6135 char extra[32];
6136 uint8_t len = 0;
6137
6138 ret = wlan_hdd_get_link_speed(adapter, &link_speed);
6139 if (0 != ret)
6140 return ret;
6141
6142 len = scnprintf(extra, sizeof(extra), "%s %d", command, link_speed);
Anurag Chouhan6d760662016-02-20 16:05:43 +05306143 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006144 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006145 hdd_err("Failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006146 ret = -EFAULT;
6147 }
6148
6149 return ret;
6150}
6151
6152#ifdef FEATURE_NAPI
6153/**
6154 * hdd_parse_napi() - helper functions to drv_cmd_napi
6155 * @str : source string to parse
6156 * @cmd : pointer to cmd part after parsing
6157 * @sub : pointer to subcmd part after parsing
6158 * @aux : pointer to optional aux part after parsing
6159 *
6160 * Example:
6161 * NAPI SCALE <n> +-- IN str
6162 * | | +------ OUT aux
6163 * | +------------ OUT subcmd
6164 * +----------------- OUT cmd
6165 *
6166 * Return: ==0: success; !=0: failure
6167 */
6168static int hdd_parse_napi(char **str, char **cmd, char **sub, char **aux)
6169{
6170 int rc;
6171 char *token, *lcmd = NULL, *lsub = NULL, *laux = NULL;
6172
6173 NAPI_DEBUG("-->\n");
6174
6175 token = strsep(str, " \t");
6176 if (NULL == token) {
6177 hdd_err("cannot parse cmd");
6178 goto parse_end;
6179 }
6180 lcmd = token;
6181
6182 token = strsep(str, " \t");
6183 if (NULL == token) {
6184 hdd_err("cannot parse subcmd");
6185 goto parse_end;
6186 }
6187 lsub = token;
6188
6189 token = strsep(str, " \t");
6190 if (NULL == token)
6191 hdd_warn("cannot parse aux\n");
6192 else
6193 laux = token;
6194
6195parse_end:
6196 if ((NULL == lcmd) || (NULL == lsub))
6197 rc = -EINVAL;
6198 else {
6199 rc = 0;
6200 *cmd = lcmd;
6201 *sub = lsub;
6202 if (NULL != aux)
6203 *aux = laux;
6204 }
6205 NAPI_DEBUG("<--[rc=%d]\n", rc);
6206 return rc;
6207}
6208
6209
6210/**
6211 * hdd_parse_stats() - print NAPI stats into a buffer
6212 * @buf : buffer to write stats into
6213 * @max : "size of buffer"
6214 * @idp : NULL: all stats, otherwise, ptr to the NAPI instance
6215 * @napid: binary structure to retrieve the stats from
6216 *
6217 * Return: number of bytes written into the buffer
6218 */
6219int hdd_napi_stats(char *buf,
6220 int max,
6221 char *indp,
6222 struct qca_napi_data *napid)
6223{
6224 int n = 0;
6225 int i, j, k; /* NAPI, CPU, bucket indices */
6226 int from, to;
6227 struct qca_napi_info *napii;
6228 struct qca_napi_stat *napis;
6229
6230 NAPI_DEBUG("-->\n");
6231
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006232 if (NULL == napid)
6233 return n;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006234 if (NULL == indp) {
6235 from = 0;
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006236 to = CE_COUNT_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006237 } else {
6238 if (0 > kstrtoint(indp, 10, &to)) {
6239 from = 0;
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006240 to = CE_COUNT_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006241 } else
6242 from = to;
6243 }
6244
6245 for (i = from; i < to; i++)
6246 if (napid->ce_map & (0x01 << i)) {
6247 napii = &(napid->napis[i]);
6248 for (j = 0; j < NR_CPUS; j++) {
6249 napis = &(napii->stats[j]);
6250 n += scnprintf(buf + n, max - n,
6251 "STATS: NAPI[%d] CPU: %d scheds: %d polls: %d completes: %d done: %d ",
6252 i, j,
6253 napis->napi_schedules,
6254 napis->napi_polls,
6255 napis->napi_completes,
6256 napis->napi_workdone);
6257
6258 for (k = 0; k < QCA_NAPI_NUM_BUCKETS; k++) {
6259 n += scnprintf(
6260 buf + n, max - n,
6261 " %d",
6262 napis->napi_budget_uses[k]);
6263 }
6264 n += scnprintf(buf+n, max - n, "\n");
6265 }
6266 }
6267
6268 NAPI_DEBUG("<--[n=%d]\n", n);
6269 return n;
6270}
6271
6272/**
6273 * napi_set_scale() - sets the scale attribute in all NAPI entries
6274 * @sc : scale to set
6275 *
6276 * Return: void
6277 */
6278static void napi_set_scale(uint8_t sc)
6279{
6280 uint32_t i;
6281 struct qca_napi_data *napi_data;
6282
6283 napi_data = hdd_napi_get_all();
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006284 if (likely(NULL != napi_data))
6285 for (i = 0; i < CE_COUNT_MAX; i++)
6286 if (napi_data->ce_map & (0x01 << i))
6287 napi_data->napis[i].scale = sc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006288
6289 return;
6290}
6291/**
6292 * drv_cmd_napi() - processes NAPI commands
6293 * @adapter : net_device
6294 * @hdd_ctx : HDD context
6295 * @command : command string from user command (including "NAPI")
6296 * @command_len: length of command
6297 * @priv_data : ifr_data
6298 *
6299 * Commands supported:
6300 * NAPI ENABLE : enables NAPI administratively. Note that this may not
6301 * enable NAPI functionally, as some other conditions
6302 * may not have been satisfied yet
6303 * NAPI DISABLE : reverse operation of "enable"
6304 * NAPI STATUS : get global status of NAPI instances
6305 * NAPI STATS [<n>] : get the stats for a given NAPI instance
6306 * NAPI SCALE <n> : set the scale factor
6307 *
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006308 * Return: 0: success; !0: failure
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006309 */
6310static int drv_cmd_napi(hdd_adapter_t *adapter,
6311 hdd_context_t *hdd_ctx,
6312 uint8_t *command,
6313 uint8_t command_len,
6314 hdd_priv_data_t *priv_data)
6315{
6316 int rc = 0;
6317 int n, l;
6318 char *cmd = NULL, *subcmd = NULL, *aux = NULL;
6319 char *synopsis = "NAPI ENABLE\n"
6320 "NAPI DISABLE\n"
6321 "NAPI STATUS\n"
6322 "NAPI STATS [<n>] -- if no <n> then all\n"
6323 "NAPI SCALE <n> -- set the scale\n";
6324 char *reply = NULL;
6325
6326 /* make a local copy, as strsep modifies the str in place */
6327 char *str = NULL;
6328
6329 NAPI_DEBUG("-->\n");
6330
6331 /**
6332 * NOTE TO MAINTAINER: from this point to the end of the function,
6333 * please do not return anywhere in the code except the very end
6334 * to avoid memory leakage (goto end_drv_napi instead)
6335 * or make sure that reply+str is freed
6336 */
6337 reply = kmalloc(MAX_USER_COMMAND_SIZE, GFP_KERNEL);
6338 if (NULL == reply) {
6339 hdd_err("could not allocate reply buffer");
6340 rc = -ENOMEM;
6341 goto end_drv_napi;
6342 }
6343
6344 str = kmalloc(strlen(command) + 1, GFP_KERNEL);
6345 if (NULL == str) {
6346 hdd_err("could not allocate copy of input buffer");
6347 rc = -ENOMEM;
6348 goto end_drv_napi;
6349 }
6350
6351 strlcpy(str, command, strlen(command) + 1);
6352 hdd_debug("parsing command into cmd=0x%p sub=0x%p aux=0x%p\n",
6353 cmd, subcmd, aux);
6354
6355
6356 rc = hdd_parse_napi(&str, &cmd, &subcmd, &aux);
6357
6358 if (0 != rc) {
6359 const char *msg = "unknown or badly formatted cmd\n%s";
Anurag Chouhan6d760662016-02-20 16:05:43 +05306360 l = QDF_MIN(MAX_USER_COMMAND_SIZE,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006361 strlen(msg)+strlen(synopsis));
6362 n = scnprintf(reply, l, msg, synopsis);
6363
6364 if (copy_to_user(priv_data->buf, reply,
Anurag Chouhan6d760662016-02-20 16:05:43 +05306365 QDF_MIN(priv_data->total_len, l)))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006366 hdd_err("failed to copy data to user buffer");
6367 hdd_debug("reply: %s", reply);
6368
6369 rc = -EINVAL;
6370 } else {
6371 hdd_debug("cmd=(%s) subcmd=(%s) aux=(%s)\n",
6372 cmd, subcmd, aux);
6373 if (!strcmp(subcmd, "ENABLE"))
6374 hdd_napi_event(NAPI_EVT_CMD_STATE, (void *)1);
6375 else if (!strcmp(subcmd, "DISABLE"))
6376 hdd_napi_event(NAPI_EVT_CMD_STATE, (void *)0);
6377 else if (!strcmp(subcmd, "STATUS")) {
6378 int n = 0;
6379 uint32_t i;
6380 struct qca_napi_data *napi_data;
6381
6382 napi_data = hdd_napi_get_all();
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006383 if (unlikely(NULL == napi_data))
6384 goto status_end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006385 n += scnprintf(reply+n, MAX_USER_COMMAND_SIZE - n,
6386 "NAPI state: 0x%08x map: 0x%08x\n",
6387 napi_data->state,
6388 napi_data->ce_map);
6389
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006390 for (i = 0; i < CE_COUNT_MAX; i++)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006391 if (napi_data->ce_map & (0x01 << i)) {
6392 n += scnprintf(
6393 reply + n,
6394 MAX_USER_COMMAND_SIZE - n,
6395 "#%d: id: %d, scale=%d\n",
6396 i,
6397 napi_data->napis[i].id,
6398 napi_data->napis[i].scale);
6399 }
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006400 status_end:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006401 hdd_info("wlan: STATUS DATA:\n%s", reply);
6402 if (copy_to_user(priv_data->buf, reply,
Anurag Chouhan6d760662016-02-20 16:05:43 +05306403 QDF_MIN(n, priv_data->total_len)))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006404 rc = -EINVAL;
6405 } else if (!strcmp(subcmd, "STATS")) {
6406 int n = 0;
6407 struct qca_napi_data *napi_data;
6408
6409 napi_data = hdd_napi_get_all();
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006410 if (NULL != napi_data) {
6411 n = hdd_napi_stats(reply, MAX_USER_COMMAND_SIZE,
6412 aux, napi_data);
6413 NAPI_DEBUG("STATS: returns %d\n", n);
6414 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006415 if (n > 0) {
6416 if (copy_to_user(priv_data->buf, reply,
Anurag Chouhan6d760662016-02-20 16:05:43 +05306417 QDF_MIN(priv_data->total_len,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006418 n)))
6419 rc = -EINVAL;
6420 hdd_info("wlan: STATS_DATA\n%s\n", reply);
6421 } else
6422 rc = -EINVAL;
6423 } else if (!strcmp(subcmd, "SCALE")) {
6424 if (NULL == aux) {
6425 rc = -EINVAL;
6426 hdd_err("wlan: SCALE cmd requires <n>");
6427 } else {
6428 uint8_t sc;
6429 rc = kstrtou8(aux, 10, &sc);
6430 if (rc) {
6431 hdd_err("wlan: bad scale (%s)", aux);
6432 rc = -EINVAL;
6433 } else
6434 napi_set_scale(sc);
6435 }
6436 } /* SCALE */
6437 }
6438end_drv_napi:
6439 if (NULL != str)
6440 kfree(str);
6441 if (NULL != reply)
6442 kfree(reply);
6443
6444 NAPI_DEBUG("<--[rc=%d]\n", rc);
6445 return rc;
6446}
6447#endif /* FEATURE_NAPI */
6448
6449/**
6450 * hdd_set_rx_filter() - set RX filter
6451 * @adapter: Pointer to adapter
6452 * @action: Filter action
6453 * @pattern: Address pattern
6454 *
6455 * Address pattern is most significant byte of address for example
6456 * 0x01 for IPV4 multicast address
6457 * 0x33 for IPV6 multicast address
6458 * 0xFF for broadcast address
6459 *
6460 * Return: 0 for success, non-zero for failure
6461 */
6462static int hdd_set_rx_filter(hdd_adapter_t *adapter, bool action,
6463 uint8_t pattern)
6464{
6465 int ret;
Frank Liuf95e8132016-09-29 19:01:30 +08006466 uint8_t i, j;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006467 tHalHandle handle;
6468 tSirRcvFltMcAddrList *filter;
6469 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
6470
6471 ret = wlan_hdd_validate_context(hdd_ctx);
6472 if (0 != ret)
6473 return ret;
6474
6475 handle = hdd_ctx->hHal;
6476
6477 if (NULL == handle) {
6478 hdd_err("HAL Handle is NULL");
6479 return -EINVAL;
6480 }
6481
Mukul Sharma3a1ab302017-01-15 19:02:37 +05306482 if (!hdd_ctx->config->fEnableMCAddrList) {
6483 hdd_notice("mc addr ini is disabled");
6484 return -EINVAL;
6485 }
6486
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006487 /*
6488 * If action is false it means start dropping packets
6489 * Set addr_filter_pattern which will be used when sending
6490 * MC/BC address list to target
6491 */
6492 if (!action)
6493 adapter->addr_filter_pattern = pattern;
6494 else
6495 adapter->addr_filter_pattern = 0;
6496
Krunal Sonibe766b02016-03-10 13:00:44 -08006497 if (((adapter->device_mode == QDF_STA_MODE) ||
6498 (adapter->device_mode == QDF_P2P_CLIENT_MODE)) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006499 adapter->mc_addr_list.mc_cnt &&
6500 hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
6501
6502
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306503 filter = qdf_mem_malloc(sizeof(*filter));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006504 if (NULL == filter) {
6505 hdd_err("Could not allocate Memory");
6506 return -ENOMEM;
6507 }
6508 filter->action = action;
Frank Liuf95e8132016-09-29 19:01:30 +08006509 for (i = 0, j = 0; i < adapter->mc_addr_list.mc_cnt; i++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006510 if (!memcmp(adapter->mc_addr_list.addr[i],
6511 &pattern, 1)) {
Frank Liuf95e8132016-09-29 19:01:30 +08006512 memcpy(filter->multicastAddr[j].bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006513 adapter->mc_addr_list.addr[i],
6514 sizeof(adapter->mc_addr_list.addr[i]));
Frank Liuf95e8132016-09-29 19:01:30 +08006515
Srinivas Girigowdaf2599dd2015-11-16 18:20:46 -08006516 hdd_info("%s RX filter : addr ="
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006517 MAC_ADDRESS_STR,
6518 action ? "setting" : "clearing",
Frank Liuf95e8132016-09-29 19:01:30 +08006519 MAC_ADDR_ARRAY(filter->multicastAddr[j].bytes));
6520 j++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006521 }
6522 }
Frank Liuf95e8132016-09-29 19:01:30 +08006523 filter->ulMulticastAddrCnt = j;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006524 /* Set rx filter */
6525 sme_8023_multicast_list(handle, adapter->sessionId, filter);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306526 qdf_mem_free(filter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006527 } else {
Srinivas Girigowdaf2599dd2015-11-16 18:20:46 -08006528 hdd_info("mode %d mc_cnt %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006529 adapter->device_mode, adapter->mc_addr_list.mc_cnt);
6530 }
6531
6532 return 0;
6533}
6534
6535/**
6536 * hdd_driver_rxfilter_comand_handler() - RXFILTER driver command handler
6537 * @command: Pointer to input string driver command
6538 * @adapter: Pointer to adapter
6539 * @action: Action to enable/disable filtering
6540 *
6541 * If action == false
6542 * Start filtering out data packets based on type
6543 * RXFILTER-REMOVE 0 -> Start filtering out unicast data packets
6544 * RXFILTER-REMOVE 1 -> Start filtering out broadcast data packets
6545 * RXFILTER-REMOVE 2 -> Start filtering out IPV4 mcast data packets
6546 * RXFILTER-REMOVE 3 -> Start filtering out IPV6 mcast data packets
6547 *
6548 * if action == true
6549 * Stop filtering data packets based on type
6550 * RXFILTER-ADD 0 -> Stop filtering unicast data packets
6551 * RXFILTER-ADD 1 -> Stop filtering broadcast data packets
6552 * RXFILTER-ADD 2 -> Stop filtering IPV4 mcast data packets
6553 * RXFILTER-ADD 3 -> Stop filtering IPV6 mcast data packets
6554 *
6555 * Current implementation only supports IPV4 address filtering by
6556 * selectively allowing IPV4 multicast data packest based on
6557 * address list received in .ndo_set_rx_mode
6558 *
6559 * Return: 0 for success, non-zero for failure
6560 */
6561static int hdd_driver_rxfilter_comand_handler(uint8_t *command,
6562 hdd_adapter_t *adapter,
6563 bool action)
6564{
6565 int ret = 0;
6566 uint8_t *value;
6567 uint8_t type;
6568
6569 value = command;
6570 /* Skip space after RXFILTER-REMOVE OR RXFILTER-ADD based on action */
6571 if (!action)
6572 value = command + 16;
6573 else
6574 value = command + 13;
6575 ret = kstrtou8(value, 10, &type);
6576 if (ret < 0) {
6577 hdd_err("kstrtou8 failed invalid input value %d", type);
6578 return -EINVAL;
6579 }
6580
6581 switch (type) {
6582 case 2:
6583 /* Set rx filter for IPV4 multicast data packets */
6584 ret = hdd_set_rx_filter(adapter, action, 0x01);
6585 break;
6586 default:
6587 hdd_info("Unsupported RXFILTER type %d", type);
6588 break;
6589 }
6590
6591 return ret;
6592}
6593
6594/**
6595 * drv_cmd_rx_filter_remove() - RXFILTER REMOVE driver command handler
6596 * @adapter: Pointer to network adapter
6597 * @hdd_ctx: Pointer to hdd context
6598 * @command: Pointer to input command
6599 * @command_len: Command length
6600 * @priv_data: Pointer to private data in command
6601 */
6602static int drv_cmd_rx_filter_remove(hdd_adapter_t *adapter,
6603 hdd_context_t *hdd_ctx,
6604 uint8_t *command,
6605 uint8_t command_len,
6606 hdd_priv_data_t *priv_data)
6607{
6608 return hdd_driver_rxfilter_comand_handler(command, adapter, false);
6609}
6610
6611/**
6612 * drv_cmd_rx_filter_add() - RXFILTER ADD driver command handler
6613 * @adapter: Pointer to network adapter
6614 * @hdd_ctx: Pointer to hdd context
6615 * @command: Pointer to input command
6616 * @command_len: Command length
6617 * @priv_data: Pointer to private data in command
6618 */
6619static int drv_cmd_rx_filter_add(hdd_adapter_t *adapter,
6620 hdd_context_t *hdd_ctx,
6621 uint8_t *command,
6622 uint8_t command_len,
6623 hdd_priv_data_t *priv_data)
6624{
6625 return hdd_driver_rxfilter_comand_handler(command, adapter, true);
6626}
6627
Archana Ramachandran393f3792015-11-13 17:13:21 -08006628/**
6629 * hdd_parse_setantennamode_command() - HDD Parse SETANTENNAMODE
6630 * command
6631 * @value: Pointer to SETANTENNAMODE command
6632 * @mode: Pointer to antenna mode
6633 * @reason: Pointer to reason for set antenna mode
6634 *
6635 * This function parses the SETANTENNAMODE command passed in the format
6636 * SETANTENNAMODE<space>mode
6637 *
6638 * Return: 0 for success non-zero for failure
6639 */
6640static int hdd_parse_setantennamode_command(const uint8_t *value)
6641{
6642 const uint8_t *in_ptr = value;
6643 int tmp, v;
6644 char arg1[32];
6645
6646 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
6647
6648 /* no argument after the command */
6649 if (NULL == in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006650 hdd_err("No argument after the command");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006651 return -EINVAL;
6652 }
6653
6654 /* no space after the command */
6655 if (SPACE_ASCII_VALUE != *in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006656 hdd_err("No space after the command");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006657 return -EINVAL;
6658 }
6659
6660 /* remove empty spaces */
6661 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
6662 in_ptr++;
6663
6664 /* no argument followed by spaces */
6665 if ('\0' == *in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006666 hdd_err("No argument followed by spaces");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006667 return -EINVAL;
6668 }
6669
6670 /* get the argument i.e. antenna mode */
6671 v = sscanf(in_ptr, "%31s ", arg1);
6672 if (1 != v) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006673 hdd_err("argument retrieval from cmd string failed");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006674 return -EINVAL;
6675 }
6676
6677 v = kstrtos32(arg1, 10, &tmp);
6678 if (v < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006679 hdd_err("argument string to int conversion failed");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006680 return -EINVAL;
6681 }
6682
6683 return tmp;
6684}
6685
6686/**
6687 * hdd_is_supported_chain_mask_2x2() - Verify if supported chain
6688 * mask is 2x2 mode
6689 * @hdd_ctx: Pointer to hdd contex
6690 *
6691 * Return: true if supported chain mask 2x2 else false
6692 */
6693static bool hdd_is_supported_chain_mask_2x2(hdd_context_t *hdd_ctx)
6694{
6695 /*
6696 * Revisit and the update logic to determine the number
6697 * of TX/RX chains supported in the system when
6698 * antenna sharing per band chain mask support is
6699 * brought in
6700 */
6701 return (hdd_ctx->config->enable2x2 == 0x01) ? true : false;
6702}
6703
6704/**
6705 * hdd_is_supported_chain_mask_1x1() - Verify if the supported
6706 * chain mask is 1x1
6707 * @hdd_ctx: Pointer to hdd contex
6708 *
6709 * Return: true if supported chain mask 1x1 else false
6710 */
6711static bool hdd_is_supported_chain_mask_1x1(hdd_context_t *hdd_ctx)
6712{
6713 /*
6714 * Revisit and update the logic to determine the number
6715 * of TX/RX chains supported in the system when
6716 * antenna sharing per band chain mask support is
6717 * brought in
6718 */
6719 return (!hdd_ctx->config->enable2x2) ? true : false;
6720}
6721
6722/**
6723 * drv_cmd_set_antenna_mode() - SET ANTENNA MODE driver command
6724 * handler
6725 * @adapter: Pointer to network adapter
6726 * @hdd_ctx: Pointer to hdd context
6727 * @command: Pointer to input command
6728 * @command_len: Command length
6729 * @priv_data: Pointer to private data in command
6730 */
6731static int drv_cmd_set_antenna_mode(hdd_adapter_t *adapter,
6732 hdd_context_t *hdd_ctx,
6733 uint8_t *command,
6734 uint8_t command_len,
6735 hdd_priv_data_t *priv_data)
6736{
6737 struct sir_antenna_mode_param params;
6738 QDF_STATUS status;
6739 int ret = 0;
6740 int mode;
6741 uint8_t *value = command;
6742 uint8_t smps_mode;
6743 uint8_t smps_enable;
6744
6745 if (((1 << QDF_STA_MODE) != hdd_ctx->concurrency_mode) ||
6746 (hdd_ctx->no_of_active_sessions[QDF_STA_MODE] > 1)) {
6747 hdd_err("Operation invalid in non sta or concurrent mode");
6748 ret = -EPERM;
6749 goto exit;
6750 }
6751
6752 mode = hdd_parse_setantennamode_command(value);
6753 if (mode < 0) {
6754 hdd_err("Invalid SETANTENNA command");
6755 ret = mode;
6756 goto exit;
6757 }
6758
6759 hdd_info("Processing antenna mode switch to: %d", mode);
6760
6761 if (hdd_ctx->current_antenna_mode == mode) {
6762 hdd_err("System already in the requested mode");
6763 ret = 0;
6764 goto exit;
6765 }
6766
6767 if ((HDD_ANTENNA_MODE_2X2 == mode) &&
6768 (!hdd_is_supported_chain_mask_2x2(hdd_ctx))) {
6769 hdd_err("System does not support 2x2 mode");
6770 ret = -EPERM;
6771 goto exit;
6772 }
6773
6774 if ((HDD_ANTENNA_MODE_1X1 == mode) &&
6775 hdd_is_supported_chain_mask_1x1(hdd_ctx)) {
6776 hdd_err("System only supports 1x1 mode");
6777 ret = 0;
6778 goto exit;
6779 }
6780
6781 switch (mode) {
6782 case HDD_ANTENNA_MODE_1X1:
6783 params.num_rx_chains = 1;
6784 params.num_tx_chains = 1;
6785 break;
6786 case HDD_ANTENNA_MODE_2X2:
6787 params.num_rx_chains = 2;
6788 params.num_tx_chains = 2;
6789 break;
6790 default:
6791 hdd_err("unsupported antenna mode");
6792 ret = -EINVAL;
6793 goto exit;
6794 }
6795
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006796 /* Check TDLS status and update antenna mode */
6797 if ((QDF_STA_MODE == adapter->device_mode) &&
Kabilan Kannan32eb5022016-10-04 12:24:50 -07006798 cds_is_sta_active_connection_exists()) {
Archana Ramachandran2ad7de22016-04-22 16:53:25 -07006799 ret = wlan_hdd_tdls_antenna_switch(hdd_ctx, adapter,
6800 mode);
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006801 if (0 != ret)
6802 goto exit;
6803 }
6804
Archana Ramachandran393f3792015-11-13 17:13:21 -08006805 params.set_antenna_mode_resp =
6806 (void *)wlan_hdd_soc_set_antenna_mode_cb;
6807 hdd_info("Set antenna mode rx chains: %d tx chains: %d",
6808 params.num_rx_chains,
6809 params.num_tx_chains);
6810
6811
6812 INIT_COMPLETION(hdd_ctx->set_antenna_mode_cmpl);
6813 status = sme_soc_set_antenna_mode(hdd_ctx->hHal, &params);
6814 if (QDF_STATUS_SUCCESS != status) {
6815 hdd_err("set antenna mode failed status : %d", status);
6816 ret = -EFAULT;
6817 goto exit;
6818 }
6819
6820 ret = wait_for_completion_timeout(
6821 &hdd_ctx->set_antenna_mode_cmpl,
6822 msecs_to_jiffies(WLAN_WAIT_TIME_ANTENNA_MODE_REQ));
6823 if (!ret) {
6824 ret = -EFAULT;
6825 hdd_err("send set antenna mode timed out");
6826 goto exit;
6827 }
6828
6829 /* Update SME SMPS config */
6830 if (HDD_ANTENNA_MODE_1X1 == mode) {
6831 smps_enable = true;
6832 smps_mode = HDD_SMPS_MODE_STATIC;
6833 } else {
6834 smps_enable = false;
6835 smps_mode = HDD_SMPS_MODE_DISABLED;
6836 }
6837
6838 hdd_info("Update SME SMPS enable: %d mode: %d",
6839 smps_enable, smps_mode);
6840 status = sme_update_mimo_power_save(
6841 hdd_ctx->hHal, smps_enable, smps_mode, false);
6842 if (QDF_STATUS_SUCCESS != status) {
6843 hdd_err("Update SMPS config failed enable: %d mode: %d status: %d",
6844 smps_enable, smps_mode, status);
6845 ret = -EFAULT;
6846 goto exit;
6847 }
6848
Archana Ramachandran393f3792015-11-13 17:13:21 -08006849 hdd_ctx->current_antenna_mode = mode;
Archana Ramachandran5041b252016-04-25 14:29:25 -07006850 /* Update the user requested nss in the mac context.
6851 * This will be used in tdls protocol engine to form tdls
6852 * Management frames.
6853 */
6854 sme_update_user_configured_nss(
6855 hdd_ctx->hHal,
6856 hdd_ctx->current_antenna_mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006857
Archana Ramachandran5041b252016-04-25 14:29:25 -07006858 hdd_info("Successfully switched to mode: %d x %d",
6859 hdd_ctx->current_antenna_mode,
6860 hdd_ctx->current_antenna_mode);
6861 ret = 0;
Archana Ramachandran393f3792015-11-13 17:13:21 -08006862exit:
Kabilan Kannanff89f742016-08-15 18:14:10 -07006863#ifdef FEATURE_WLAN_TDLS
6864 /* Reset tdls NSS flags */
6865 if (hdd_ctx->tdls_nss_switch_in_progress &&
6866 hdd_ctx->tdls_nss_teardown_complete) {
6867 hdd_ctx->tdls_nss_switch_in_progress = false;
6868 hdd_ctx->tdls_nss_teardown_complete = false;
6869 }
6870 hdd_info("tdls_nss_switch_in_progress: %d tdls_nss_teardown_complete: %d",
6871 hdd_ctx->tdls_nss_switch_in_progress,
6872 hdd_ctx->tdls_nss_teardown_complete);
6873#endif
Archana Ramachandran393f3792015-11-13 17:13:21 -08006874 hdd_info("Set antenna status: %d current mode: %d",
6875 ret, hdd_ctx->current_antenna_mode);
6876 return ret;
6877
6878}
6879
6880/**
6881 * drv_cmd_get_antenna_mode() - GET ANTENNA MODE driver command
6882 * handler
6883 * @adapter: Pointer to hdd adapter
6884 * @hdd_ctx: Pointer to hdd context
6885 * @command: Pointer to input command
6886 * @command_len: length of the command
6887 * @priv_data: private data coming with the driver command
6888 *
6889 * Return: 0 for success non-zero for failure
6890 */
6891static inline int drv_cmd_get_antenna_mode(hdd_adapter_t *adapter,
6892 hdd_context_t *hdd_ctx,
6893 uint8_t *command,
6894 uint8_t command_len,
6895 hdd_priv_data_t *priv_data)
6896{
6897 uint32_t antenna_mode = 0;
6898 char extra[32];
6899 uint8_t len = 0;
6900
6901 antenna_mode = hdd_ctx->current_antenna_mode;
6902 len = scnprintf(extra, sizeof(extra), "%s %d", command,
6903 antenna_mode);
6904 len = QDF_MIN(priv_data->total_len, len + 1);
6905 if (copy_to_user(priv_data->buf, &extra, len)) {
6906 hdd_err("Failed to copy data to user buffer");
6907 return -EFAULT;
6908 }
6909
6910 hdd_info("Get antenna mode: %d", antenna_mode);
6911
6912 return 0;
6913}
6914
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006915/*
6916 * dummy (no-op) hdd driver command handler
6917 */
6918static int drv_cmd_dummy(hdd_adapter_t *adapter,
6919 hdd_context_t *hdd_ctx,
6920 uint8_t *command,
6921 uint8_t command_len,
6922 hdd_priv_data_t *priv_data)
6923{
6924 hdd_info("%s: Ignoring driver command \"%s\"",
6925 adapter->dev->name, command);
6926 return 0;
6927}
6928
6929/*
6930 * handler for any unsupported wlan hdd driver command
6931 */
6932static int drv_cmd_invalid(hdd_adapter_t *adapter,
6933 hdd_context_t *hdd_ctx,
6934 uint8_t *command,
6935 uint8_t command_len,
6936 hdd_priv_data_t *priv_data)
6937{
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306938 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006939 TRACE_CODE_HDD_UNSUPPORTED_IOCTL,
6940 adapter->sessionId, 0));
6941
6942 hdd_warn("%s: Unsupported driver command \"%s\"",
6943 adapter->dev->name, command);
6944
6945 return -ENOTSUPP;
6946}
6947
6948/**
6949 * drv_cmd_set_fcc_channel() - handle fcc constraint request
6950 * @adapter: HDD adapter
6951 * @hdd_ctx: HDD context
6952 * @command: command ptr, SET_FCC_CHANNEL 0/1 is the command
6953 * @command_len: command len
6954 * @priv_data: private data
6955 *
6956 * Return: status
6957 */
6958static int drv_cmd_set_fcc_channel(hdd_adapter_t *adapter,
6959 hdd_context_t *hdd_ctx,
6960 uint8_t *command,
6961 uint8_t command_len,
6962 hdd_priv_data_t *priv_data)
6963{
6964 uint8_t *value;
6965 uint8_t fcc_constraint;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306966 QDF_STATUS status;
Amar Singhal83a047a2016-05-19 15:56:11 -07006967 bool scan_pending;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006968 int ret = 0;
6969
6970 /*
6971 * this command would be called by user-space when it detects WLAN
6972 * ON after airplane mode is set. When APM is set, WLAN turns off.
6973 * But it can be turned back on. Otherwise; when APM is turned back
6974 * off, WLAN would turn back on. So at that point the command is
6975 * expected to come down. 0 means disable, 1 means enable. The
6976 * constraint is removed when parameter 1 is set or different
6977 * country code is set
6978 */
6979
6980 value = command + command_len + 1;
6981
6982 ret = kstrtou8(value, 10, &fcc_constraint);
6983 if ((ret < 0) || (fcc_constraint > 1)) {
6984 /*
6985 * If the input value is greater than max value of datatype,
6986 * then also it is a failure
6987 */
6988 hdd_err("value out of range");
6989 return -EINVAL;
6990 }
6991
Amar Singhal83a047a2016-05-19 15:56:11 -07006992 scan_pending = !qdf_list_empty(&hdd_ctx->hdd_scan_req_q);
6993 status = sme_handle_set_fcc_channel(hdd_ctx->hHal, !fcc_constraint,
6994 scan_pending);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306995 if (status != QDF_STATUS_SUCCESS) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006996 hdd_err("sme disable fn. returned err");
6997 ret = -EPERM;
6998 }
6999
7000 return ret;
7001}
7002
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307003/**
7004 * hdd_parse_set_channel_switch_command() - Parse and validate CHANNEL_SWITCH
7005 * command
7006 * @value: Pointer to the command
7007 * @chan_number: Pointer to the channel number
7008 * @chan_bw: Pointer to the channel bandwidth
7009 *
7010 * Parses and provides the channel number and channel width from the input
7011 * command which is expected to be of the format: CHANNEL_SWITCH <CH> <BW>
7012 * <CH> is channel number to move (where 1 = channel 1, 149 = channel 149, ...)
7013 * <BW> is bandwidth to move (where 20 = BW 20, 40 = BW 40, 80 = BW 80)
7014 *
7015 * Return: 0 for success, non-zero for failure
7016 */
7017static int hdd_parse_set_channel_switch_command(uint8_t *value,
7018 uint32_t *chan_number,
7019 uint32_t *chan_bw)
7020{
7021 const uint8_t *in_ptr = value;
7022 int ret;
7023
7024 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
7025
7026 /* no argument after the command */
7027 if (NULL == in_ptr) {
7028 hdd_err("No argument after the command");
7029 return -EINVAL;
7030 }
7031
7032 /* no space after the command */
7033 if (SPACE_ASCII_VALUE != *in_ptr) {
7034 hdd_err("No space after the command ");
7035 return -EINVAL;
7036 }
7037
7038 /* remove empty spaces and move the next argument */
7039 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
7040 in_ptr++;
7041
7042 /* no argument followed by spaces */
7043 if ('\0' == *in_ptr) {
7044 hdd_err("No argument followed by spaces");
7045 return -EINVAL;
7046 }
7047
7048 /* get the two arguments: channel number and bandwidth */
7049 ret = sscanf(in_ptr, "%u %u", chan_number, chan_bw);
7050 if (ret != 2) {
7051 hdd_err("Arguments retrieval from cmd string failed");
7052 return -EINVAL;
7053 }
7054
7055 return 0;
7056}
7057
7058/**
7059 * drv_cmd_set_channel_switch() - Switch SAP/P2P-GO operating channel
7060 * @adapter: HDD adapter
7061 * @hdd_ctx: HDD context
7062 * @command: Pointer to the input command CHANNEL_SWITCH
7063 * @command_len: Command len
7064 * @priv_data: Private data
7065 *
7066 * Handles private IOCTL CHANNEL_SWITCH command to switch the operating channel
7067 * of SAP/P2P-GO
7068 *
7069 * Return: 0 for success, non-zero for failure
7070 */
7071static int drv_cmd_set_channel_switch(hdd_adapter_t *adapter,
7072 hdd_context_t *hdd_ctx,
7073 uint8_t *command,
7074 uint8_t command_len,
7075 hdd_priv_data_t *priv_data)
7076{
7077 struct net_device *dev = adapter->dev;
7078 int status;
7079 uint32_t chan_number = 0, chan_bw = 0;
7080 uint8_t *value = command;
Kiran Kumar Lokere13644672016-02-29 15:40:10 -08007081 enum phy_ch_width width;
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307082
Krunal Sonibe766b02016-03-10 13:00:44 -08007083 if ((adapter->device_mode != QDF_P2P_GO_MODE) &&
7084 (adapter->device_mode != QDF_SAP_MODE)) {
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307085 hdd_err("IOCTL CHANNEL_SWITCH not supported for mode %d",
7086 adapter->device_mode);
7087 return -EINVAL;
7088 }
7089
7090 status = hdd_parse_set_channel_switch_command(value,
7091 &chan_number, &chan_bw);
7092 if (status) {
7093 hdd_err("Invalid CHANNEL_SWITCH command");
7094 return status;
7095 }
7096
7097 if ((chan_bw != 20) && (chan_bw != 40) && (chan_bw != 80)) {
7098 hdd_err("BW %d is not allowed for CHANNEL_SWITCH", chan_bw);
7099 return -EINVAL;
7100 }
7101
7102 if (chan_bw == 80)
7103 width = CH_WIDTH_80MHZ;
7104 else if (chan_bw == 40)
7105 width = CH_WIDTH_40MHZ;
7106 else
7107 width = CH_WIDTH_20MHZ;
7108
7109 hdd_info("CH:%d BW:%d", chan_number, chan_bw);
7110
7111 status = hdd_softap_set_channel_change(dev, chan_number, width);
7112 if (status) {
7113 hdd_err("Set channel change fail");
7114 return status;
7115 }
7116
7117 return 0;
7118}
7119
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007120/*
7121 * The following table contains all supported WLAN HDD
7122 * IOCTL driver commands and the handler for each of them.
7123 */
7124static const hdd_drv_cmd_t hdd_drv_cmds[] = {
7125 {"P2P_DEV_ADDR", drv_cmd_p2p_dev_addr},
7126 {"P2P_SET_NOA", drv_cmd_p2p_set_noa},
7127 {"P2P_SET_PS", drv_cmd_p2p_set_ps},
7128 {"SETBAND", drv_cmd_set_band},
7129 {"SETWMMPS", drv_cmd_set_wmmps},
7130 {"COUNTRY", drv_cmd_country},
7131 {"SETSUSPENDMODE", drv_cmd_dummy},
7132 {"SET_AP_WPS_P2P_IE", drv_cmd_dummy},
7133 {"BTCOEXSCAN", drv_cmd_dummy},
7134 {"RXFILTER", drv_cmd_dummy},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007135 {"SETROAMTRIGGER", drv_cmd_set_roam_trigger},
7136 {"GETROAMTRIGGER", drv_cmd_get_roam_trigger},
7137 {"SETROAMSCANPERIOD", drv_cmd_set_roam_scan_period},
7138 {"GETROAMSCANPERIOD", drv_cmd_get_roam_scan_period},
7139 {"SETROAMSCANREFRESHPERIOD", drv_cmd_set_roam_scan_refresh_period},
7140 {"GETROAMSCANREFRESHPERIOD", drv_cmd_get_roam_scan_refresh_period},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007141 {"SETROAMMODE", drv_cmd_set_roam_mode},
7142 {"GETROAMMODE", drv_cmd_get_roam_mode},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007143 {"SETROAMDELTA", drv_cmd_set_roam_delta},
7144 {"GETROAMDELTA", drv_cmd_get_roam_delta},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007145 {"GETBAND", drv_cmd_get_band},
7146 {"SETROAMSCANCHANNELS", drv_cmd_set_roam_scan_channels},
7147 {"GETROAMSCANCHANNELS", drv_cmd_get_roam_scan_channels},
7148 {"GETCCXMODE", drv_cmd_get_ccx_mode},
7149 {"GETOKCMODE", drv_cmd_get_okc_mode},
7150 {"GETFASTROAM", drv_cmd_get_fast_roam},
7151 {"GETFASTTRANSITION", drv_cmd_get_fast_transition},
7152 {"SETROAMSCANCHANNELMINTIME", drv_cmd_set_roam_scan_channel_min_time},
7153 {"SENDACTIONFRAME", drv_cmd_send_action_frame},
7154 {"GETROAMSCANCHANNELMINTIME", drv_cmd_get_roam_scan_channel_min_time},
7155 {"SETSCANCHANNELTIME", drv_cmd_set_scan_channel_time},
7156 {"GETSCANCHANNELTIME", drv_cmd_get_scan_channel_time},
7157 {"SETSCANHOMETIME", drv_cmd_set_scan_home_time},
7158 {"GETSCANHOMETIME", drv_cmd_get_scan_home_time},
7159 {"SETROAMINTRABAND", drv_cmd_set_roam_intra_band},
7160 {"GETROAMINTRABAND", drv_cmd_get_roam_intra_band},
7161 {"SETSCANNPROBES", drv_cmd_set_scan_n_probes},
7162 {"GETSCANNPROBES", drv_cmd_get_scan_n_probes},
7163 {"SETSCANHOMEAWAYTIME", drv_cmd_set_scan_home_away_time},
7164 {"GETSCANHOMEAWAYTIME", drv_cmd_get_scan_home_away_time},
7165 {"REASSOC", drv_cmd_reassoc},
7166 {"SETWESMODE", drv_cmd_set_wes_mode},
7167 {"GETWESMODE", drv_cmd_get_wes_mode},
7168 {"SETOPPORTUNISTICRSSIDIFF", drv_cmd_set_opportunistic_rssi_diff},
7169 {"GETOPPORTUNISTICRSSIDIFF", drv_cmd_get_opportunistic_rssi_diff},
7170 {"SETROAMRESCANRSSIDIFF", drv_cmd_set_roam_rescan_rssi_diff},
7171 {"GETROAMRESCANRSSIDIFF", drv_cmd_get_roam_rescan_rssi_diff},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007172 {"SETFASTROAM", drv_cmd_set_fast_roam},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007173 {"SETFASTTRANSITION", drv_cmd_set_fast_transition},
7174 {"FASTREASSOC", drv_cmd_fast_reassoc},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007175 {"SETROAMSCANCONTROL", drv_cmd_set_roam_scan_control},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007176 {"SETOKCMODE", drv_cmd_set_okc_mode},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007177 {"GETROAMSCANCONTROL", drv_cmd_get_roam_scan_control},
7178 {"BTCOEXMODE", drv_cmd_bt_coex_mode},
7179 {"SCAN-ACTIVE", drv_cmd_scan_active},
7180 {"SCAN-PASSIVE", drv_cmd_scan_passive},
7181 {"GETDWELLTIME", drv_cmd_get_dwell_time},
7182 {"SETDWELLTIME", drv_cmd_set_dwell_time},
7183 {"MIRACAST", drv_cmd_miracast},
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08007184 {"SETIBSSBEACONOUIDATA", drv_cmd_set_ibss_beacon_oui_data},
7185 {"SETRMCENABLE", drv_cmd_set_rmc_enable},
7186 {"SETRMCACTIONPERIOD", drv_cmd_set_rmc_action_period},
7187 {"GETIBSSPEERINFOALL", drv_cmd_get_ibss_peer_info_all},
7188 {"GETIBSSPEERINFO", drv_cmd_get_ibss_peer_info},
7189 {"SETRMCTXRATE", drv_cmd_set_rmc_tx_rate},
7190 {"SETIBSSTXFAILEVENT", drv_cmd_set_ibss_tx_fail_event},
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08007191#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007192 {"SETCCXROAMSCANCHANNELS", drv_cmd_set_ccx_roam_scan_channels},
7193 {"GETTSMSTATS", drv_cmd_get_tsm_stats},
7194 {"SETCCKMIE", drv_cmd_set_cckm_ie},
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07007195 {"CCXBEACONREQ", drv_cmd_ccx_beacon_req},
7196 {"CCXPLMREQ", drv_cmd_ccx_plm_req},
7197 {"SETCCXMODE", drv_cmd_set_ccx_mode},
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08007198#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007199 {"SETMCRATE", drv_cmd_set_mc_rate},
7200 {"MAXTXPOWER", drv_cmd_max_tx_power},
7201 {"SETDFSSCANMODE", drv_cmd_set_dfs_scan_mode},
7202 {"GETDFSSCANMODE", drv_cmd_get_dfs_scan_mode},
7203 {"GETLINKSTATUS", drv_cmd_get_link_status},
7204#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
7205 {"ENABLEEXTWOW", drv_cmd_enable_ext_wow},
7206 {"SETAPP1PARAMS", drv_cmd_set_app1_params},
7207 {"SETAPP2PARAMS", drv_cmd_set_app2_params},
7208#endif
7209#ifdef FEATURE_WLAN_TDLS
7210 {"TDLSSECONDARYCHANNELOFFSET", drv_cmd_tdls_secondary_channel_offset},
7211 {"TDLSOFFCHANNELMODE", drv_cmd_tdls_off_channel_mode},
7212 {"TDLSOFFCHANNEL", drv_cmd_tdls_off_channel},
7213 {"TDLSSCAN", drv_cmd_tdls_scan},
7214#endif
7215 {"RSSI", drv_cmd_get_rssi},
7216 {"LINKSPEED", drv_cmd_get_linkspeed},
7217#ifdef FEATURE_NAPI
7218 {"NAPI", drv_cmd_napi},
7219#endif /* FEATURE_NAPI */
7220 {"RXFILTER-REMOVE", drv_cmd_rx_filter_remove},
7221 {"RXFILTER-ADD", drv_cmd_rx_filter_add},
7222 {"SET_FCC_CHANNEL", drv_cmd_set_fcc_channel},
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307223 {"CHANNEL_SWITCH", drv_cmd_set_channel_switch},
Archana Ramachandran393f3792015-11-13 17:13:21 -08007224 {"SETANTENNAMODE", drv_cmd_set_antenna_mode},
7225 {"GETANTENNAMODE", drv_cmd_get_antenna_mode},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007226};
7227
7228/**
7229 * hdd_drv_cmd_process() - chooses and runs the proper
7230 * handler based on the input command
7231 * @adapter: Pointer to the hdd adapter
7232 * @cmd: Pointer to the driver command
7233 * @priv_data: Pointer to the data associated with the command
7234 *
7235 * This function parses the input hdd driver command and runs
7236 * the proper handler
7237 *
7238 * Return: 0 for success non-zero for failure
7239 */
7240static int hdd_drv_cmd_process(hdd_adapter_t *adapter,
7241 uint8_t *cmd,
7242 hdd_priv_data_t *priv_data)
7243{
7244 hdd_context_t *hdd_ctx;
7245 int i;
7246 const int cmd_num_total = ARRAY_SIZE(hdd_drv_cmds);
7247 uint8_t *cmd_i = NULL;
7248 hdd_drv_cmd_handler_t handler = NULL;
7249 int len = 0;
7250
7251 if (!adapter || !cmd || !priv_data) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007252 hdd_err("at least 1 param is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007253 return -EINVAL;
7254 }
7255
7256 hdd_ctx = (hdd_context_t *)adapter->pHddCtx;
7257
7258 for (i = 0; i < cmd_num_total; i++) {
7259
7260 cmd_i = (uint8_t *)hdd_drv_cmds[i].cmd;
7261 handler = hdd_drv_cmds[i].handler;
7262 len = strlen(cmd_i);
7263
7264 if (!handler) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007265 hdd_err("no. %d handler is NULL", i);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007266 return -EINVAL;
7267 }
7268
7269 if (strncasecmp(cmd, cmd_i, len) == 0)
7270 return handler(adapter, hdd_ctx,
7271 cmd, len, priv_data);
7272 }
7273
7274 return drv_cmd_invalid(adapter, hdd_ctx, cmd, len, priv_data);
7275}
7276
7277/**
7278 * hdd_driver_command() - top level wlan hdd driver command handler
7279 * @adapter: Pointer to the hdd adapter
7280 * @priv_data: Pointer to the raw command data
7281 *
7282 * This function is the top level wlan hdd driver command handler. It
7283 * handles the command with the help of hdd_drv_cmd_process()
7284 *
7285 * Return: 0 for success non-zero for failure
7286 */
7287static int hdd_driver_command(hdd_adapter_t *adapter,
7288 hdd_priv_data_t *priv_data)
7289{
7290 uint8_t *command = NULL;
7291 int ret = 0;
7292
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307293 ENTER();
7294
Anurag Chouhan6d760662016-02-20 16:05:43 +05307295 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007296 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007297 return -EINVAL;
7298 }
7299
7300 /*
7301 * Note that valid pointers are provided by caller
7302 */
7303
7304 /* copy to local struct to avoid numerous changes to legacy code */
7305 if (priv_data->total_len <= 0 ||
7306 priv_data->total_len > WLAN_PRIV_DATA_MAX_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007307 hdd_warn("Invalid priv_data.total_len(%d)!!!",
7308 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007309 ret = -EINVAL;
7310 goto exit;
7311 }
7312
7313 /* Allocate +1 for '\0' */
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07007314 command = qdf_mem_malloc(priv_data->total_len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007315 if (!command) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007316 hdd_err("failed to allocate memory");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007317 ret = -ENOMEM;
7318 goto exit;
7319 }
7320
7321 if (copy_from_user(command, priv_data->buf, priv_data->total_len)) {
7322 ret = -EFAULT;
7323 goto exit;
7324 }
7325
7326 /* Make sure the command is NUL-terminated */
7327 command[priv_data->total_len] = '\0';
7328
7329 hdd_info("%s: %s", adapter->dev->name, command);
7330 ret = hdd_drv_cmd_process(adapter, command, priv_data);
7331
7332exit:
7333 if (command)
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07007334 qdf_mem_free(command);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307335 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007336 return ret;
7337}
7338
7339#ifdef CONFIG_COMPAT
7340static int hdd_driver_compat_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
7341{
7342 struct {
7343 compat_uptr_t buf;
7344 int used_len;
7345 int total_len;
7346 } compat_priv_data;
7347 hdd_priv_data_t priv_data;
7348 int ret = 0;
7349
7350 /*
7351 * Note that adapter and ifr have already been verified by caller,
7352 * and HDD context has also been validated
7353 */
7354 if (copy_from_user(&compat_priv_data, ifr->ifr_data,
7355 sizeof(compat_priv_data))) {
7356 ret = -EFAULT;
7357 goto exit;
7358 }
7359 priv_data.buf = compat_ptr(compat_priv_data.buf);
7360 priv_data.used_len = compat_priv_data.used_len;
7361 priv_data.total_len = compat_priv_data.total_len;
7362 ret = hdd_driver_command(adapter, &priv_data);
7363exit:
7364 return ret;
7365}
7366#else /* CONFIG_COMPAT */
7367static int hdd_driver_compat_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
7368{
7369 /* will never be invoked */
7370 return 0;
7371}
7372#endif /* CONFIG_COMPAT */
7373
7374static int hdd_driver_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
7375{
7376 hdd_priv_data_t priv_data;
7377 int ret = 0;
7378
7379 /*
7380 * Note that adapter and ifr have already been verified by caller,
7381 * and HDD context has also been validated
7382 */
7383 if (copy_from_user(&priv_data, ifr->ifr_data, sizeof(priv_data)))
7384 ret = -EFAULT;
7385 else
7386 ret = hdd_driver_command(adapter, &priv_data);
7387
7388 return ret;
7389}
7390
7391/**
7392 * __hdd_ioctl() - ioctl handler for wlan network interfaces
7393 * @dev: device upon which the ioctl was received
7394 * @ifr: ioctl request information
7395 * @cmd: ioctl command
7396 *
7397 * This function does initial processing of wlan device ioctls.
7398 * Currently two flavors of ioctls are supported. The primary ioctl
7399 * that is supported is the (SIOCDEVPRIVATE + 1) ioctl which is used
7400 * for Android "DRIVER" commands. The other ioctl that is
7401 * conditionally supported is the SIOCIOCTLTX99 ioctl which is used
7402 * for FTM on some platforms. This function simply verifies that the
7403 * driver is in a sane state, and that the ioctl is one of the
7404 * supported flavors, in which case flavor-specific handlers are
7405 * dispatched.
7406 *
7407 * Return: 0 on success, non-zero on error
7408 */
7409static int __hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7410{
7411 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
7412 hdd_context_t *hdd_ctx;
7413 int ret;
7414
Jeff Johnson3c3994a2016-02-11 08:12:30 -08007415 ENTER_DEV(dev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307416
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007417 if (dev != adapter->dev) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007418 hdd_alert("HDD adapter/dev inconsistency");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007419 ret = -ENODEV;
7420 goto exit;
7421 }
7422
7423 if ((!ifr) || (!ifr->ifr_data)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007424 hdd_err("invalid data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007425 ret = -EINVAL;
7426 goto exit;
7427 }
7428#if defined(QCA_WIFI_FTM) && defined(LINUX_QCMBR)
Anurag Chouhan6d760662016-02-20 16:05:43 +05307429 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007430 if (SIOCIOCTLTX99 == cmd) {
7431 ret = wlan_hdd_qcmbr_unified_ioctl(adapter, ifr);
7432 goto exit;
7433 }
7434 }
7435#endif
7436
7437 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
7438 ret = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307439 if (ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007440 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007441
7442 switch (cmd) {
7443 case (SIOCDEVPRIVATE + 1):
7444 if (is_compat_task())
7445 ret = hdd_driver_compat_ioctl(adapter, ifr);
7446 else
7447 ret = hdd_driver_ioctl(adapter, ifr);
7448 break;
7449 default:
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007450 hdd_err("unknown ioctl %d", cmd);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007451 ret = -EINVAL;
7452 break;
7453 }
7454exit:
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307455 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007456 return ret;
7457}
7458
7459/**
7460 * hdd_ioctl() - ioctl handler (wrapper) for wlan network interfaces
7461 * @dev: device upon which the ioctl was received
7462 * @ifr: ioctl request information
7463 * @cmd: ioctl command
7464 *
7465 * This function acts as an SSR-protecting wrapper to __hdd_ioctl()
7466 * which is where the ioctls are really handled.
7467 *
7468 * Return: 0 on success, non-zero on error
7469 */
7470int hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7471{
7472 int ret;
7473
7474 cds_ssr_protect(__func__);
7475 ret = __hdd_ioctl(dev, ifr, cmd);
7476 cds_ssr_unprotect(__func__);
7477 return ret;
7478}