blob: 27a7f5f80fcaa957cde9bd64d2f42a1bb02bda42 [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Tushnim Bhattacharyyaca50b322015-12-28 17:14:36 -08002 * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/*
23 * This file was originally distributed by Qualcomm Atheros, Inc.
24 * under proprietary terms before Copyright ownership was assigned
25 * to the Linux Foundation.
26 */
27
28/* Include Files */
29
Archana Ramachandran3abc3912016-04-29 17:01:32 -070030/* denote that this file does not allow legacy hddLog */
31#define HDD_DISALLOW_LEGACY_HDDLOG 1
32
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080033#include <wlan_hdd_includes.h>
34#include <wlan_hdd_wowl.h>
35#include "wlan_hdd_trace.h"
36#include "wlan_hdd_ioctl.h"
37#include "wlan_hdd_power.h"
38#include "wlan_hdd_driver_ops.h"
39#include "cds_concurrency.h"
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +053040#include "wlan_hdd_hostapd.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080041
42#include "wlan_hdd_p2p.h"
43#include <linux/ctype.h>
44#include "wma.h"
45#include "wlan_hdd_napi.h"
46
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -080047#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080048#include <sme_api.h>
49#include <sir_api.h>
50#endif
51#include "hif.h"
52
53#if defined(LINUX_QCMBR)
54#define SIOCIOCTLTX99 (SIOCDEVPRIVATE+13)
55#endif
56
57/*
58 * Size of Driver command strings from upper layer
59 */
60#define SIZE_OF_SETROAMMODE 11 /* size of SETROAMMODE */
61#define SIZE_OF_GETROAMMODE 11 /* size of GETROAMMODE */
62
Rajeev Kumar8e3e2832015-11-06 16:02:54 -080063/*
64 * Ibss prop IE from command will be of size:
65 * size = sizeof(oui) + sizeof(oui_data) + 1(Element ID) + 1(EID Length)
66 * OUI_DATA should be at least 3 bytes long
67 */
68#define WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH (3)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080069
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -080070#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080071#define TID_MIN_VALUE 0
72#define TID_MAX_VALUE 15
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -080073#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080074
75/*
76 * Maximum buffer size used for returning the data back to user space
77 */
78#define WLAN_MAX_BUF_SIZE 1024
79#define WLAN_PRIV_DATA_MAX_LEN 8192
80
81/*
82 * Driver miracast parameters 0-Disabled
83 * 1-Source, 2-Sink
84 */
85#define WLAN_HDD_DRIVER_MIRACAST_CFG_MIN_VAL 0
86#define WLAN_HDD_DRIVER_MIRACAST_CFG_MAX_VAL 2
87
88/*
89 * When ever we need to print IBSSPEERINFOALL for more than 16 STA
90 * we will split the printing.
91 */
92#define NUM_OF_STA_DATA_TO_PRINT 16
93
94/*
95 * Android DRIVER command structures
96 */
97struct android_wifi_reassoc_params {
98 unsigned char bssid[18];
99 int channel;
100};
101
102#define ANDROID_WIFI_ACTION_FRAME_SIZE 1040
103struct android_wifi_af_params {
104 unsigned char bssid[18];
105 int channel;
106 int dwell_time;
107 int len;
108 unsigned char data[ANDROID_WIFI_ACTION_FRAME_SIZE];
109};
110
111/*
112 * Define HDD driver command handling entry, each contains a command
113 * string and the handler.
114 */
115typedef int (*hdd_drv_cmd_handler_t)(hdd_adapter_t *adapter,
116 hdd_context_t *hdd_ctx,
117 uint8_t *cmd,
118 uint8_t cmd_name_len,
119 hdd_priv_data_t *priv_data);
120
121typedef struct {
122 const char *cmd;
123 hdd_drv_cmd_handler_t handler;
124} hdd_drv_cmd_t;
125
126#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
127#define WLAN_WAIT_TIME_READY_TO_EXTWOW 2000
128#define WLAN_HDD_MAX_TCP_PORT 65535
129#endif
130
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800131static uint16_t cesium_pid;
132extern struct sock *cesium_nl_srv_sock;
133
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -0800134#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800135static void hdd_get_tsm_stats_cb(tAniTrafStrmMetrics tsm_metrics,
136 const uint32_t staId, void *context)
137{
138 struct statsContext *stats_context = NULL;
139 hdd_adapter_t *adapter = NULL;
140
141 if (NULL == context) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700142 hdd_err("Bad param, context [%p]", context);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800143 return;
144 }
145
146 /*
147 * there is a race condition that exists between this callback
148 * function and the caller since the caller could time out either
149 * before or while this code is executing. we use a spinlock to
150 * serialize these actions
151 */
152 spin_lock(&hdd_context_lock);
153
154 stats_context = context;
155 adapter = stats_context->pAdapter;
156 if ((NULL == adapter) ||
157 (STATS_CONTEXT_MAGIC != stats_context->magic)) {
158 /*
159 * the caller presumably timed out so there is
160 * nothing we can do
161 */
162 spin_unlock(&hdd_context_lock);
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700163 hdd_warn("Invalid context, adapter [%p] magic [%08x]",
164 adapter, stats_context->magic);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800165 return;
166 }
167
168 /* context is valid so caller is still waiting */
169
170 /* paranoia: invalidate the magic */
171 stats_context->magic = 0;
172
173 /* copy over the tsm stats */
174 adapter->tsmStats.UplinkPktQueueDly = tsm_metrics.UplinkPktQueueDly;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530175 qdf_mem_copy(adapter->tsmStats.UplinkPktQueueDlyHist,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800176 tsm_metrics.UplinkPktQueueDlyHist,
177 sizeof(adapter->tsmStats.UplinkPktQueueDlyHist) /
178 sizeof(adapter->tsmStats.UplinkPktQueueDlyHist[0]));
179 adapter->tsmStats.UplinkPktTxDly = tsm_metrics.UplinkPktTxDly;
180 adapter->tsmStats.UplinkPktLoss = tsm_metrics.UplinkPktLoss;
181 adapter->tsmStats.UplinkPktCount = tsm_metrics.UplinkPktCount;
182 adapter->tsmStats.RoamingCount = tsm_metrics.RoamingCount;
183 adapter->tsmStats.RoamingDly = tsm_metrics.RoamingDly;
184
185 /* notify the caller */
186 complete(&stats_context->completion);
187
188 /* serialization is complete */
189 spin_unlock(&hdd_context_lock);
190}
191
192static
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530193QDF_STATUS hdd_get_tsm_stats(hdd_adapter_t *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800194 const uint8_t tid,
195 tAniTrafStrmMetrics *tsm_metrics)
196{
197 hdd_station_ctx_t *hdd_sta_ctx = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530198 QDF_STATUS hstatus;
199 QDF_STATUS vstatus = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800200 unsigned long rc;
201 struct statsContext context;
202 hdd_context_t *hdd_ctx = NULL;
203
204 if (NULL == adapter) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700205 hdd_err("adapter is NULL");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530206 return QDF_STATUS_E_FAULT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800207 }
208
209 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
210 hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
211
212 /* we are connected prepare our callback context */
213 init_completion(&context.completion);
214 context.pAdapter = adapter;
215 context.magic = STATS_CONTEXT_MAGIC;
216
217 /* query tsm stats */
218 hstatus = sme_get_tsm_stats(hdd_ctx->hHal, hdd_get_tsm_stats_cb,
219 hdd_sta_ctx->conn_info.staId[0],
220 hdd_sta_ctx->conn_info.bssId,
221 &context, hdd_ctx->pcds_context, tid);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530222 if (QDF_STATUS_SUCCESS != hstatus) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700223 hdd_err("Unable to retrieve statistics");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530224 vstatus = QDF_STATUS_E_FAULT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800225 } else {
226 /* request was sent -- wait for the response */
227 rc = wait_for_completion_timeout(&context.completion,
228 msecs_to_jiffies(WLAN_WAIT_TIME_STATS));
229 if (!rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700230 hdd_err("SME timed out while retrieving statistics");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530231 vstatus = QDF_STATUS_E_TIMEOUT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800232 }
233 }
234
235 /*
236 * either we never sent a request, we sent a request and received a
237 * response or we sent a request and timed out. if we never sent a
238 * request or if we sent a request and got a response, we want to
239 * clear the magic out of paranoia. if we timed out there is a
240 * race condition such that the callback function could be
241 * executing at the same time we are. of primary concern is if the
242 * callback function had already verified the "magic" but had not
243 * yet set the completion variable when a timeout occurred. we
244 * serialize these activities by invalidating the magic while
245 * holding a shared spinlock which will cause us to block if the
246 * callback is currently executing
247 */
248 spin_lock(&hdd_context_lock);
249 context.magic = 0;
250 spin_unlock(&hdd_context_lock);
251
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530252 if (QDF_STATUS_SUCCESS == vstatus) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800253 tsm_metrics->UplinkPktQueueDly =
254 adapter->tsmStats.UplinkPktQueueDly;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530255 qdf_mem_copy(tsm_metrics->UplinkPktQueueDlyHist,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800256 adapter->tsmStats.UplinkPktQueueDlyHist,
257 sizeof(adapter->tsmStats.UplinkPktQueueDlyHist) /
258 sizeof(adapter->tsmStats.
259 UplinkPktQueueDlyHist[0]));
260 tsm_metrics->UplinkPktTxDly = adapter->tsmStats.UplinkPktTxDly;
261 tsm_metrics->UplinkPktLoss = adapter->tsmStats.UplinkPktLoss;
262 tsm_metrics->UplinkPktCount = adapter->tsmStats.UplinkPktCount;
263 tsm_metrics->RoamingCount = adapter->tsmStats.RoamingCount;
264 tsm_metrics->RoamingDly = adapter->tsmStats.RoamingDly;
265 }
266 return vstatus;
267}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -0800268#endif /*FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800269
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800270/* Function header is left blank intentionally */
271static int hdd_parse_setrmcenable_command(uint8_t *pValue,
272 uint8_t *pRmcEnable)
273{
274 uint8_t *inPtr = pValue;
275 int tempInt;
276 int v = 0;
277 char buf[32];
278 *pRmcEnable = 0;
279
280 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
281
282 if (NULL == inPtr) {
283 return 0;
284 }
285
286 else if (SPACE_ASCII_VALUE != *inPtr) {
287 return 0;
288 }
289
290 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
291 inPtr++;
292
293 if ('\0' == *inPtr) {
294 return 0;
295 }
296
297 sscanf(inPtr, "%32s ", buf);
298 v = kstrtos32(buf, 10, &tempInt);
299 if (v < 0) {
300 return -EINVAL;
301 }
302
303 *pRmcEnable = tempInt;
304
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700305 hdd_info("ucRmcEnable: %d", *pRmcEnable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800306
307 return 0;
308}
309
310/* Function header is left blank intentionally */
311static int hdd_parse_setrmcactionperiod_command(uint8_t *pValue,
312 uint32_t *pActionPeriod)
313{
314 uint8_t *inPtr = pValue;
315 int tempInt;
316 int v = 0;
317 char buf[32];
318 *pActionPeriod = 0;
319
320 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
321
322 if (NULL == inPtr) {
323 return -EINVAL;
324 }
325
326 else if (SPACE_ASCII_VALUE != *inPtr) {
327 return -EINVAL;
328 }
329
330 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
331 inPtr++;
332
333 if ('\0' == *inPtr) {
334 return 0;
335 }
336
337 sscanf(inPtr, "%32s ", buf);
338 v = kstrtos32(buf, 10, &tempInt);
339 if (v < 0) {
340 return -EINVAL;
341 }
342
343 if ((tempInt < WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STAMIN) ||
344 (tempInt > WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STAMAX)) {
345 return -EINVAL;
346 }
347
348 *pActionPeriod = tempInt;
349
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700350 hdd_info("uActionPeriod: %d", *pActionPeriod);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800351
352 return 0;
353}
354
355/* Function header is left blank intentionally */
356static int hdd_parse_setrmcrate_command(uint8_t *pValue,
357 uint32_t *pRate,
358 tTxrateinfoflags *pTxFlags)
359{
360 uint8_t *inPtr = pValue;
361 int tempInt;
362 int v = 0;
363 char buf[32];
364 *pRate = 0;
365 *pTxFlags = 0;
366
367 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
368
369 if (NULL == inPtr) {
370 return -EINVAL;
371 }
372
373 else if (SPACE_ASCII_VALUE != *inPtr) {
374 return -EINVAL;
375 }
376
377 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
378 inPtr++;
379
380 if ('\0' == *inPtr) {
381 return 0;
382 }
383
384 sscanf(inPtr, "%32s ", buf);
385 v = kstrtos32(buf, 10, &tempInt);
386 if (v < 0) {
387 return -EINVAL;
388 }
389
390 switch (tempInt) {
391 default:
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700392 hdd_warn("Unsupported rate: %d", tempInt);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800393 return -EINVAL;
394 case 0:
395 case 6:
396 case 9:
397 case 12:
398 case 18:
399 case 24:
400 case 36:
401 case 48:
402 case 54:
403 *pTxFlags = eHAL_TX_RATE_LEGACY;
404 *pRate = tempInt * 10;
405 break;
406 case 65:
407 *pTxFlags = eHAL_TX_RATE_HT20;
408 *pRate = tempInt * 10;
409 break;
410 case 72:
411 *pTxFlags = eHAL_TX_RATE_HT20 | eHAL_TX_RATE_SGI;
412 *pRate = 722;
413 break;
414 }
415
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700416 hdd_info("Rate: %d", *pRate);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800417
418 return 0;
419}
420
421/**
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700422 * hdd_get_ibss_peer_info_cb() - IBSS peer Info request callback
423 * @UserData: Adapter private data
424 * @pPeerInfoRsp: Peer info response
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800425 *
426 * This is an asynchronous callback function from SME when the peer info
427 * is received
428 *
429 * Return: 0 for success non-zero for failure
430 */
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700431void
432hdd_get_ibss_peer_info_cb(void *pUserData,
433 tSirPeerInfoRspParams *pPeerInfo)
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800434{
435 hdd_adapter_t *adapter = (hdd_adapter_t *) pUserData;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800436 hdd_station_ctx_t *pStaCtx;
437 uint8_t i;
438
439 /* Sanity check */
440 if ((NULL == adapter) ||
441 (WLAN_HDD_ADAPTER_MAGIC != adapter->magic)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700442 hdd_alert("invalid adapter or adapter has invalid magic");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800443 return;
444 }
445
446 pStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
447 if (NULL != pPeerInfo && QDF_STATUS_SUCCESS == pPeerInfo->status) {
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700448 /* validate number of peers */
449 if (pPeerInfo->numPeers < SIR_MAX_NUM_STA_IN_IBSS) {
450 pStaCtx->ibss_peer_info.status = pPeerInfo->status;
451 pStaCtx->ibss_peer_info.numPeers = pPeerInfo->numPeers;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800452
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700453 for (i = 0; i < pPeerInfo->numPeers; i++) {
454 pStaCtx->ibss_peer_info.peerInfoParams[i] =
455 pPeerInfo->peerInfoParams[i];
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800456 }
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700457 hdd_info("Peer Info copied in HDD");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800458 } else {
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700459 hdd_info("Number of peers %d returned is more than limit %d",
460 pPeerInfo->numPeers, SIR_MAX_NUM_STA_IN_IBSS);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800461 }
462 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700463 hdd_info("peerInfo returned is NULL");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800464 }
465
466 complete(&adapter->ibss_peer_info_comp);
467}
468
469/**
470 * hdd_cfg80211_get_ibss_peer_info_all() - get ibss peers' info
471 * @adapter: Adapter context
472 *
473 * Request function to get IBSS peer info from lower layers
474 *
475 * Return: 0 for success non-zero for failure
476 */
477static
478QDF_STATUS hdd_cfg80211_get_ibss_peer_info_all(hdd_adapter_t *adapter)
479{
480 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
481 QDF_STATUS retStatus = QDF_STATUS_E_FAILURE;
482 unsigned long rc;
483
484 INIT_COMPLETION(adapter->ibss_peer_info_comp);
485
486 retStatus = sme_request_ibss_peer_info(hHal, adapter,
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700487 hdd_get_ibss_peer_info_cb,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800488 true, 0xFF);
489
490 if (QDF_STATUS_SUCCESS == retStatus) {
491 rc = wait_for_completion_timeout
492 (&adapter->ibss_peer_info_comp,
493 msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT));
494
495 /* status will be 0 if timed out */
496 if (!rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700497 hdd_warn("Warning: IBSS_PEER_INFO_TIMEOUT");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800498 retStatus = QDF_STATUS_E_FAILURE;
499 return retStatus;
500 }
501 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700502 hdd_warn("Warning: sme_request_ibss_peer_info Request failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800503 }
504
505 return retStatus;
506}
507
508/**
509 * hdd_cfg80211_get_ibss_peer_info() - get ibss peer info
510 * @adapter: Adapter context
511 * @staIdx: Sta index for which the peer info is requested
512 *
513 * Request function to get IBSS peer info from lower layers
514 *
515 * Return: 0 for success non-zero for failure
516 */
517static QDF_STATUS
518hdd_cfg80211_get_ibss_peer_info(hdd_adapter_t *adapter, uint8_t staIdx)
519{
520 unsigned long rc;
521 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
522 QDF_STATUS retStatus = QDF_STATUS_E_FAILURE;
523
524 INIT_COMPLETION(adapter->ibss_peer_info_comp);
525
526 retStatus = sme_request_ibss_peer_info(hHal, adapter,
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700527 hdd_get_ibss_peer_info_cb,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800528 false, staIdx);
529
530 if (QDF_STATUS_SUCCESS == retStatus) {
531 rc = wait_for_completion_timeout(
532 &adapter->ibss_peer_info_comp,
533 msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT));
534
535 /* status = 0 on timeout */
536 if (!rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700537 hdd_warn("Warning: IBSS_PEER_INFO_TIMEOUT");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800538 retStatus = QDF_STATUS_E_FAILURE;
539 return retStatus;
540 }
541 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700542 hdd_warn("Warning: sme_request_ibss_peer_info Request failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800543 }
544
545 return retStatus;
546}
547
548/* Function header is left blank intentionally */
549QDF_STATUS
550hdd_parse_get_ibss_peer_info(uint8_t *pValue, struct qdf_mac_addr *pPeerMacAddr)
551{
552 uint8_t *inPtr = pValue;
553 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
554
555 if (NULL == inPtr) {
556 return QDF_STATUS_E_FAILURE;;
557 }
558
559 else if (SPACE_ASCII_VALUE != *inPtr) {
560 return QDF_STATUS_E_FAILURE;;
561 }
562
563 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
564 inPtr++;
565
566 if ('\0' == *inPtr) {
567 return QDF_STATUS_E_FAILURE;;
568 }
569
570 if (inPtr[2] != ':' || inPtr[5] != ':' || inPtr[8] != ':' ||
571 inPtr[11] != ':' || inPtr[14] != ':') {
572 return QDF_STATUS_E_FAILURE;;
573 }
574 sscanf(inPtr, "%2x:%2x:%2x:%2x:%2x:%2x",
575 (unsigned int *)&pPeerMacAddr->bytes[0],
576 (unsigned int *)&pPeerMacAddr->bytes[1],
577 (unsigned int *)&pPeerMacAddr->bytes[2],
578 (unsigned int *)&pPeerMacAddr->bytes[3],
579 (unsigned int *)&pPeerMacAddr->bytes[4],
580 (unsigned int *)&pPeerMacAddr->bytes[5]);
581
582 return QDF_STATUS_SUCCESS;
583}
584
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800585static void hdd_get_band_helper(hdd_context_t *hdd_ctx, int *pBand)
586{
587 eCsrBand band = -1;
588 sme_get_freq_band((tHalHandle) (hdd_ctx->hHal), &band);
589 switch (band) {
590 case eCSR_BAND_ALL:
591 *pBand = WLAN_HDD_UI_BAND_AUTO;
592 break;
593
594 case eCSR_BAND_24:
595 *pBand = WLAN_HDD_UI_BAND_2_4_GHZ;
596 break;
597
598 case eCSR_BAND_5G:
599 *pBand = WLAN_HDD_UI_BAND_5_GHZ;
600 break;
601
602 default:
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700603 hdd_warn("Invalid Band %d", band);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800604 *pBand = -1;
605 break;
606 }
607}
608
609/**
610 * _hdd_parse_bssid_and_chan() - helper function to parse bssid and channel
611 * @data: input data
612 * @target_ap_bssid: pointer to bssid (output parameter)
613 * @channel: pointer to channel (output parameter)
614 *
615 * Return: 0 if parsing is successful; -EINVAL otherwise
616 */
617static int _hdd_parse_bssid_and_chan(const uint8_t **data,
618 uint8_t *bssid,
619 uint8_t *channel)
620{
621 const uint8_t *in_ptr;
622 int v = 0;
623 int temp_int;
624 uint8_t temp_buf[32];
625
626 /* 12 hexa decimal digits, 5 ':' and '\0' */
627 uint8_t mac_addr[18];
628
629 if (!data || !*data)
630 return -EINVAL;
631
632 in_ptr = *data;
633
634 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
635 /* no argument after the command */
636 if (NULL == in_ptr)
637 goto error;
638 /* no space after the command */
639 else if (SPACE_ASCII_VALUE != *in_ptr)
640 goto error;
641
642 /* remove empty spaces */
643 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
644 in_ptr++;
645
646 /* no argument followed by spaces */
647 if ('\0' == *in_ptr)
648 goto error;
649
650 v = sscanf(in_ptr, "%17s", mac_addr);
651 if (!((1 == v) && hdd_is_valid_mac_address(mac_addr))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700652 hdd_err("Invalid MAC address or All hex inputs are not read (%d)",
653 v);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800654 goto error;
655 }
656
657 bssid[0] = hex_to_bin(mac_addr[0]) << 4 |
658 hex_to_bin(mac_addr[1]);
659 bssid[1] = hex_to_bin(mac_addr[3]) << 4 |
660 hex_to_bin(mac_addr[4]);
661 bssid[2] = hex_to_bin(mac_addr[6]) << 4 |
662 hex_to_bin(mac_addr[7]);
663 bssid[3] = hex_to_bin(mac_addr[9]) << 4 |
664 hex_to_bin(mac_addr[10]);
665 bssid[4] = hex_to_bin(mac_addr[12]) << 4 |
666 hex_to_bin(mac_addr[13]);
667 bssid[5] = hex_to_bin(mac_addr[15]) << 4 |
668 hex_to_bin(mac_addr[16]);
669
670 /* point to the next argument */
671 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
672 /* no argument after the command */
673 if (NULL == in_ptr)
674 goto error;
675
676 /* remove empty spaces */
677 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
678 in_ptr++;
679
680 /* no argument followed by spaces */
681 if ('\0' == *in_ptr)
682 goto error;
683
684 /* get the next argument ie the channel number */
685 v = sscanf(in_ptr, "%31s ", temp_buf);
686 if (1 != v)
687 goto error;
688
689 v = kstrtos32(temp_buf, 10, &temp_int);
690 if ((v < 0) || (temp_int < 0) ||
691 (temp_int > WNI_CFG_CURRENT_CHANNEL_STAMAX))
692 return -EINVAL;
693
694 *channel = temp_int;
695 *data = in_ptr;
696 return 0;
697error:
698 *data = in_ptr;
699 return -EINVAL;
700}
701
702/**
703 * hdd_parse_send_action_frame_data() - HDD Parse send action frame data
704 * @pValue: Pointer to input data
705 * @pTargetApBssid: Pointer to target Ap bssid
706 * @pChannel: Pointer to the Target AP channel
707 * @pDwellTime: Pointer to the time to stay off-channel
708 * after transmitting action frame
709 * @pBuf: Pointer to data
710 * @pBufLen: Pointer to data length
711 *
712 * This function parses the send action frame data passed in the format
713 * SENDACTIONFRAME<space><bssid><space><channel><space><dwelltime><space><data>
714 *
715 * Return: 0 for success non-zero for failure
716 */
717static int
718hdd_parse_send_action_frame_v1_data(const uint8_t *pValue,
719 uint8_t *pTargetApBssid,
720 uint8_t *pChannel, uint8_t *pDwellTime,
721 uint8_t **pBuf, uint8_t *pBufLen)
722{
723 const uint8_t *inPtr = pValue;
724 const uint8_t *dataEnd;
725 int tempInt;
726 int j = 0;
727 int i = 0;
728 int v = 0;
729 uint8_t tempBuf[32];
730 uint8_t tempByte = 0;
731
732 if (_hdd_parse_bssid_and_chan(&inPtr, pTargetApBssid, pChannel))
733 return -EINVAL;
734
735 /* point to the next argument */
736 inPtr = strnchr(inPtr, strlen(inPtr), SPACE_ASCII_VALUE);
737 /* no argument after the command */
738 if (NULL == inPtr)
739 return -EINVAL;
740 /* removing empty spaces */
741 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
742 inPtr++;
743
744 /* no argument followed by spaces */
745 if ('\0' == *inPtr) {
746 return -EINVAL;
747 }
748
749 /* getting the next argument ie the dwell time */
750 v = sscanf(inPtr, "%31s ", tempBuf);
751 if (1 != v)
752 return -EINVAL;
753
754 v = kstrtos32(tempBuf, 10, &tempInt);
755 if (v < 0 || tempInt < 0)
756 return -EINVAL;
757
758 *pDwellTime = tempInt;
759
760 /* point to the next argument */
761 inPtr = strnchr(inPtr, strlen(inPtr), SPACE_ASCII_VALUE);
762 /* no argument after the command */
763 if (NULL == inPtr)
764 return -EINVAL;
765 /* removing empty spaces */
766 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
767 inPtr++;
768
769 /* no argument followed by spaces */
770 if ('\0' == *inPtr) {
771 return -EINVAL;
772 }
773
774 /* find the length of data */
775 dataEnd = inPtr;
776 while (('\0' != *dataEnd)) {
777 dataEnd++;
778 }
779 *pBufLen = dataEnd - inPtr;
780 if (*pBufLen <= 0)
781 return -EINVAL;
782
783 /*
784 * Allocate the number of bytes based on the number of input characters
785 * whether it is even or odd.
786 * if the number of input characters are even, then we need N/2 byte.
787 * if the number of input characters are odd, then we need do (N+1)/2
788 * to compensate rounding off.
789 * For example, if N = 18, then (18 + 1)/2 = 9 bytes are enough.
790 * If N = 19, then we need 10 bytes, hence (19 + 1)/2 = 10 bytes
791 */
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530792 *pBuf = qdf_mem_malloc((*pBufLen + 1) / 2);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800793 if (NULL == *pBuf) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700794 hdd_err("qdf_mem_malloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800795 return -ENOMEM;
796 }
797
798 /* the buffer received from the upper layer is character buffer,
799 * we need to prepare the buffer taking 2 characters in to a U8 hex
800 * decimal number for example 7f0000f0...form a buffer to contain 7f
801 * in 0th location, 00 in 1st and f0 in 3rd location
802 */
803 for (i = 0, j = 0; j < *pBufLen; j += 2) {
804 if (j + 1 == *pBufLen) {
805 tempByte = hex_to_bin(inPtr[j]);
806 } else {
807 tempByte =
808 (hex_to_bin(inPtr[j]) << 4) |
809 (hex_to_bin(inPtr[j + 1]));
810 }
811 (*pBuf)[i++] = tempByte;
812 }
813 *pBufLen = i;
814 return 0;
815}
816
817/**
818 * hdd_parse_reassoc_command_data() - HDD Parse reassoc command data
819 * @pValue: Pointer to input data (its a NULL terminated string)
820 * @pTargetApBssid: Pointer to target Ap bssid
821 * @pChannel: Pointer to the Target AP channel
822 *
823 * This function parses the reasoc command data passed in the format
824 * REASSOC<space><bssid><space><channel>
825 *
826 * Return: 0 for success non-zero for failure
827 */
828static int hdd_parse_reassoc_command_v1_data(const uint8_t *pValue,
829 uint8_t *pTargetApBssid,
830 uint8_t *pChannel)
831{
832 const uint8_t *inPtr = pValue;
833
834 if (_hdd_parse_bssid_and_chan(&inPtr, pTargetApBssid, pChannel))
835 return -EINVAL;
836
837 return 0;
838}
839
Naveen Rawat05376ee2016-07-18 16:43:32 -0700840#ifdef WLAN_FEATURE_ROAM_OFFLOAD
841void hdd_wma_send_fastreassoc_cmd(int sessionId, const tSirMacAddr bssid,
842 int channel)
843{
844 struct wma_roam_invoke_cmd *fastreassoc;
845 cds_msg_t msg = {0};
846
847 fastreassoc = qdf_mem_malloc(sizeof(*fastreassoc));
848 if (NULL == fastreassoc) {
849 hdd_err("qdf_mem_malloc failed for fastreassoc");
850 return;
851 }
852 fastreassoc->vdev_id = sessionId;
853 fastreassoc->channel = channel;
854 fastreassoc->bssid[0] = bssid[0];
855 fastreassoc->bssid[1] = bssid[1];
856 fastreassoc->bssid[2] = bssid[2];
857 fastreassoc->bssid[3] = bssid[3];
858 fastreassoc->bssid[4] = bssid[4];
859 fastreassoc->bssid[5] = bssid[5];
860
861 msg.type = SIR_HAL_ROAM_INVOKE;
862 msg.reserved = 0;
863 msg.bodyptr = fastreassoc;
864 if (QDF_STATUS_SUCCESS != cds_mq_post_message(QDF_MODULE_ID_WMA,
865 &msg)) {
866 qdf_mem_free(fastreassoc);
867 hdd_err("Not able to post ROAM_INVOKE_CMD message to WMA");
868 }
869}
870#else
871void hdd_wma_send_fastreassoc_cmd(int sessionId, const tSirMacAddr bssid,
872 int channel)
873{
874}
875
876#endif
877
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800878/**
879 * hdd_reassoc() - perform a userspace-directed reassoc
880 * @adapter: Adapter upon which the command was received
881 * @bssid: BSSID with which to reassociate
882 * @channel: channel upon which to reassociate
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700883 * @src: The source for the trigger of this action
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800884 *
885 * This function performs a userspace-directed reassoc operation
886 *
887 * Return: 0 for success non-zero for failure
888 */
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700889int hdd_reassoc(hdd_adapter_t *adapter, const uint8_t *bssid,
890 const uint8_t channel, const handoff_src src)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800891{
892 hdd_station_ctx_t *pHddStaCtx;
Naveen Rawat05376ee2016-07-18 16:43:32 -0700893 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800894 int ret = 0;
895
Naveen Rawat05376ee2016-07-18 16:43:32 -0700896 if (hdd_ctx == NULL) {
897 hdd_err("Invalid hdd ctx");
898 return -EINVAL;
899 }
900
Krunal Sonibe766b02016-03-10 13:00:44 -0800901 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800902 hdd_warn("Unsupported in mode %s(%d)",
903 hdd_device_mode_to_string(adapter->device_mode),
904 adapter->device_mode);
905 return -EINVAL;
906 }
907
908 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
909
910 /* if not associated, no need to proceed with reassoc */
911 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700912 hdd_info("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800913 ret = -EINVAL;
914 goto exit;
915 }
916
917 /*
918 * if the target bssid is same as currently associated AP,
919 * then no need to proceed with reassoc
920 */
921 if (!memcmp(bssid, pHddStaCtx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530922 QDF_MAC_ADDR_SIZE)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700923 hdd_info("Reassoc BSSID is same as currently associated AP bssid");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800924 ret = -EINVAL;
925 goto exit;
926 }
927
928 /* Check channel number is a valid channel number */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530929 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800930 wlan_hdd_validate_operation_channel(adapter, channel)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700931 hdd_err("Invalid Channel %d", channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800932 ret = -EINVAL;
933 goto exit;
934 }
935
936 /* Proceed with reassoc */
Naveen Rawat05376ee2016-07-18 16:43:32 -0700937 if (roaming_offload_enabled(hdd_ctx)) {
938 hdd_wma_send_fastreassoc_cmd((int)adapter->sessionId,
939 bssid, (int)channel);
940 } else {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800941 tCsrHandoffRequest handoffInfo;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800942
943 handoffInfo.channel = channel;
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700944 handoffInfo.src = src;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530945 qdf_mem_copy(handoffInfo.bssid.bytes, bssid, QDF_MAC_ADDR_SIZE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800946 sme_handoff_request(hdd_ctx->hHal, adapter->sessionId,
947 &handoffInfo);
948 }
949exit:
950 return ret;
951}
952
953/**
954 * hdd_parse_reassoc_v1() - parse version 1 of the REASSOC command
955 * @adapter: Adapter upon which the command was received
956 * @command: ASCII text command that was received
957 *
958 * This function parses the v1 REASSOC command with the format
959 *
960 * REASSOC xx:xx:xx:xx:xx:xx CH
961 *
962 * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the
963 * BSSID and CH is the ASCII representation of the channel. For
964 * example
965 *
966 * REASSOC 00:0a:0b:11:22:33 48
967 *
968 * Return: 0 for success non-zero for failure
969 */
970static int hdd_parse_reassoc_v1(hdd_adapter_t *adapter, const char *command)
971{
972 uint8_t channel = 0;
973 tSirMacAddr bssid;
974 int ret;
975
976 ret = hdd_parse_reassoc_command_v1_data(command, bssid, &channel);
977 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700978 hdd_err("Failed to parse reassoc command data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800979 } else {
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700980 ret = hdd_reassoc(adapter, bssid, channel, REASSOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800981 }
982 return ret;
983}
984
985/**
986 * hdd_parse_reassoc_v2() - parse version 2 of the REASSOC command
987 * @adapter: Adapter upon which the command was received
988 * @command: Command that was received, ASCII command
989 * followed by binary data
990 *
991 * This function parses the v2 REASSOC command with the format
992 *
993 * REASSOC <android_wifi_reassoc_params>
994 *
995 * Return: 0 for success non-zero for failure
996 */
997static int hdd_parse_reassoc_v2(hdd_adapter_t *adapter, const char *command)
998{
999 struct android_wifi_reassoc_params params;
1000 tSirMacAddr bssid;
1001 int ret;
1002
1003 /* The params are located after "REASSOC " */
1004 memcpy(&params, command + 8, sizeof(params));
1005
1006 if (!mac_pton(params.bssid, (u8 *) &bssid)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001007 hdd_err("MAC address parsing failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001008 ret = -EINVAL;
1009 } else {
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -07001010 ret = hdd_reassoc(adapter, bssid, params.channel, REASSOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001011 }
1012 return ret;
1013}
1014
1015/**
1016 * hdd_parse_reassoc() - parse the REASSOC command
1017 * @adapter: Adapter upon which the command was received
1018 * @command: Command that was received
1019 *
1020 * There are two different versions of the REASSOC command. Version 1
1021 * of the command contains a parameter list that is ASCII characters
1022 * whereas version 2 contains a combination of ASCII and binary
1023 * payload. Determine if a version 1 or a version 2 command is being
1024 * parsed by examining the parameters, and then dispatch the parser
1025 * that is appropriate for the command.
1026 *
1027 * Return: 0 for success non-zero for failure
1028 */
1029static int hdd_parse_reassoc(hdd_adapter_t *adapter, const char *command)
1030{
1031 int ret;
1032
1033 /* both versions start with "REASSOC "
1034 * v1 has a bssid and channel # as an ASCII string
1035 * REASSOC xx:xx:xx:xx:xx:xx CH
1036 * v2 has a C struct
1037 * REASSOC <binary c struct>
1038 *
1039 * The first field in the v2 struct is also the bssid in ASCII.
1040 * But in the case of a v2 message the BSSID is NUL-terminated.
1041 * Hence we can peek at that offset to see if this is V1 or V2
1042 * REASSOC xx:xx:xx:xx:xx:xx*
1043 * 1111111111222222
1044 * 01234567890123456789012345
1045 */
1046 if (command[25]) {
1047 ret = hdd_parse_reassoc_v1(adapter, command);
1048 } else {
1049 ret = hdd_parse_reassoc_v2(adapter, command);
1050 }
1051
1052 return ret;
1053}
1054
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001055/**
1056 * hdd_sendactionframe() - send a userspace-supplied action frame
1057 * @adapter: Adapter upon which the command was received
1058 * @bssid: BSSID target of the action frame
1059 * @channel: Channel upon which to send the frame
1060 * @dwell_time: Amount of time to dwell when the frame is sent
1061 * @payload_len:Length of the payload
1062 * @payload: Payload of the frame
1063 *
1064 * This function sends a userspace-supplied action frame
1065 *
1066 * Return: 0 for success non-zero for failure
1067 */
1068static int
1069hdd_sendactionframe(hdd_adapter_t *adapter, const uint8_t *bssid,
1070 const uint8_t channel, const uint8_t dwell_time,
1071 const uint8_t payload_len, const uint8_t *payload)
1072{
1073 struct ieee80211_channel chan;
1074 uint8_t frame_len;
1075 uint8_t *frame;
1076 struct ieee80211_hdr_3addr *hdr;
1077 u64 cookie;
1078 hdd_station_ctx_t *pHddStaCtx;
1079 hdd_context_t *hdd_ctx;
1080 int ret = 0;
1081 tpSirMacVendorSpecificFrameHdr pVendorSpecific =
1082 (tpSirMacVendorSpecificFrameHdr) payload;
1083#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
1084 struct cfg80211_mgmt_tx_params params;
1085#endif
1086
Krunal Sonibe766b02016-03-10 13:00:44 -08001087 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001088 hdd_warn("Unsupported in mode %s(%d)",
1089 hdd_device_mode_to_string(adapter->device_mode),
1090 adapter->device_mode);
1091 return -EINVAL;
1092 }
1093
1094 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
1095 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1096
1097 /* if not associated, no need to send action frame */
1098 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001099 hdd_info("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001100 ret = -EINVAL;
1101 goto exit;
1102 }
1103
1104 /*
1105 * if the target bssid is different from currently associated AP,
1106 * then no need to send action frame
1107 */
1108 if (memcmp(bssid, pHddStaCtx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05301109 QDF_MAC_ADDR_SIZE)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001110 hdd_info("STA is not associated to this AP");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001111 ret = -EINVAL;
1112 goto exit;
1113 }
1114
1115 chan.center_freq = sme_chn_to_freq(channel);
1116 /* Check if it is specific action frame */
1117 if (pVendorSpecific->category ==
1118 SIR_MAC_ACTION_VENDOR_SPECIFIC_CATEGORY) {
1119 static const uint8_t Oui[] = { 0x00, 0x00, 0xf0 };
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301120 if (!qdf_mem_cmp(pVendorSpecific->Oui, (void *)Oui, 3)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001121 /*
1122 * if the channel number is different from operating
1123 * channel then no need to send action frame
1124 */
1125 if (channel != 0) {
1126 if (channel !=
1127 pHddStaCtx->conn_info.operationChannel) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001128 hdd_info("channel(%d) is different from operating channel(%d)",
1129 channel,
1130 pHddStaCtx->conn_info.
1131 operationChannel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001132 ret = -EINVAL;
1133 goto exit;
1134 }
1135 /*
1136 * If channel number is specified and same
1137 * as home channel, ensure that action frame
1138 * is sent immediately by cancelling
1139 * roaming scans. Otherwise large dwell times
1140 * may cause long delays in sending action
1141 * frames.
1142 */
1143 sme_abort_roam_scan(hdd_ctx->hHal,
1144 adapter->sessionId);
1145 } else {
1146 /*
1147 * 0 is accepted as current home channel,
1148 * delayed transmission of action frame is ok.
1149 */
1150 chan.center_freq =
1151 sme_chn_to_freq(pHddStaCtx->conn_info.
1152 operationChannel);
1153 }
1154 }
1155 }
1156 if (chan.center_freq == 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001157 hdd_err("Invalid channel number %d", channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001158 ret = -EINVAL;
1159 goto exit;
1160 }
1161
1162 frame_len = payload_len + 24;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301163 frame = qdf_mem_malloc(frame_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001164 if (!frame) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001165 hdd_err("memory allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001166 ret = -ENOMEM;
1167 goto exit;
1168 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301169 qdf_mem_zero(frame, frame_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001170
1171 hdr = (struct ieee80211_hdr_3addr *)frame;
1172 hdr->frame_control =
1173 cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301174 qdf_mem_copy(hdr->addr1, bssid, QDF_MAC_ADDR_SIZE);
1175 qdf_mem_copy(hdr->addr2, adapter->macAddressCurrent.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05301176 QDF_MAC_ADDR_SIZE);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301177 qdf_mem_copy(hdr->addr3, bssid, QDF_MAC_ADDR_SIZE);
1178 qdf_mem_copy(hdr + 1, payload, payload_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001179
1180#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
1181 params.chan = &chan;
1182 params.offchan = 0;
1183 params.wait = dwell_time;
1184 params.buf = frame;
1185 params.len = frame_len;
1186 params.no_cck = 1;
1187 params.dont_wait_for_ack = 1;
1188 ret = wlan_hdd_mgmt_tx(NULL, &adapter->wdev, &params, &cookie);
1189#else
1190 ret = wlan_hdd_mgmt_tx(NULL,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001191 &(adapter->wdev),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001192 &chan, 0,
Amar Singhal01098f72015-10-08 11:55:32 -07001193
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001194 dwell_time, frame, frame_len, 1, 1, &cookie);
1195#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
1196
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301197 qdf_mem_free(frame);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001198exit:
1199 return ret;
1200}
1201
1202/**
1203 * hdd_parse_sendactionframe_v1() - parse version 1 of the
1204 * SENDACTIONFRAME command
1205 * @adapter: Adapter upon which the command was received
1206 * @command: ASCII text command that was received
1207 *
1208 * This function parses the v1 SENDACTIONFRAME command with the format
1209 *
1210 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DW xxxxxx
1211 *
1212 * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the
1213 * BSSID, CH is the ASCII representation of the channel, DW is the
1214 * ASCII representation of the dwell time, and xxxxxx is the Hex-ASCII
1215 * payload. For example
1216 *
1217 * SENDACTIONFRAME 00:0a:0b:11:22:33 48 40 aabbccddee
1218 *
1219 * Return: 0 for success non-zero for failure
1220 */
1221static int
1222hdd_parse_sendactionframe_v1(hdd_adapter_t *adapter, const char *command)
1223{
1224 uint8_t channel = 0;
1225 uint8_t dwell_time = 0;
1226 uint8_t payload_len = 0;
1227 uint8_t *payload = NULL;
1228 tSirMacAddr bssid;
1229 int ret;
1230
1231 ret = hdd_parse_send_action_frame_v1_data(command, bssid, &channel,
1232 &dwell_time, &payload,
1233 &payload_len);
1234 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001235 hdd_err("Failed to parse send action frame data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001236 } else {
1237 ret = hdd_sendactionframe(adapter, bssid, channel,
1238 dwell_time, payload_len, payload);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301239 qdf_mem_free(payload);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001240 }
1241
1242 return ret;
1243}
1244
1245/**
1246 * hdd_parse_sendactionframe_v2() - parse version 2 of the
1247 * SENDACTIONFRAME command
1248 * @adapter: Adapter upon which the command was received
1249 * @command: Command that was received, ASCII command
1250 * followed by binary data
1251 *
1252 * This function parses the v2 SENDACTIONFRAME command with the format
1253 *
1254 * SENDACTIONFRAME <android_wifi_af_params>
1255 *
1256 * Return: 0 for success non-zero for failure
1257 */
1258static int
1259hdd_parse_sendactionframe_v2(hdd_adapter_t *adapter, const char *command)
1260{
1261 struct android_wifi_af_params *params;
1262 tSirMacAddr bssid;
1263 int ret;
1264
1265 /* params are large so keep off the stack */
1266 params = kmalloc(sizeof(*params), GFP_KERNEL);
1267 if (!params)
1268 return -ENOMEM;
1269
1270 /* The params are located after "SENDACTIONFRAME " */
1271 memcpy(params, command + 16, sizeof(*params));
1272
1273 if (!mac_pton(params->bssid, (u8 *) &bssid)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001274 hdd_err("MAC address parsing failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001275 ret = -EINVAL;
1276 } else {
1277 ret = hdd_sendactionframe(adapter, bssid, params->channel,
1278 params->dwell_time, params->len,
1279 params->data);
1280 }
1281 kfree(params);
1282 return ret;
1283}
1284
1285/**
1286 * hdd_parse_sendactionframe() - parse the SENDACTIONFRAME command
1287 * @adapter: Adapter upon which the command was received
1288 * @command: Command that was received
1289 *
1290 * There are two different versions of the SENDACTIONFRAME command.
1291 * Version 1 of the command contains a parameter list that is ASCII
1292 * characters whereas version 2 contains a combination of ASCII and
1293 * binary payload. Determine if a version 1 or a version 2 command is
1294 * being parsed by examining the parameters, and then dispatch the
1295 * parser that is appropriate for the version of the command.
1296 *
1297 * Return: 0 for success non-zero for failure
1298 */
1299static int
1300hdd_parse_sendactionframe(hdd_adapter_t *adapter, const char *command)
1301{
1302 int ret;
1303
1304 /*
1305 * both versions start with "SENDACTIONFRAME "
1306 * v1 has a bssid and other parameters as an ASCII string
1307 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DWELL LEN FRAME
1308 * v2 has a C struct
1309 * SENDACTIONFRAME <binary c struct>
1310 *
1311 * The first field in the v2 struct is also the bssid in ASCII.
1312 * But in the case of a v2 message the BSSID is NUL-terminated.
1313 * Hence we can peek at that offset to see if this is V1 or V2
1314 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx*
1315 * 111111111122222222223333
1316 * 0123456789012345678901234567890123
1317 */
1318 if (command[33]) {
1319 ret = hdd_parse_sendactionframe_v1(adapter, command);
1320 } else {
1321 ret = hdd_parse_sendactionframe_v2(adapter, command);
1322 }
1323
1324 return ret;
1325}
1326
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001327/**
1328 * hdd_parse_channellist() - HDD Parse channel list
1329 * @pValue: Pointer to input channel list
1330 * @ChannelList: Pointer to local output array to record
1331 * channel list
1332 * @pNumChannels: Pointer to number of roam scan channels
1333 *
1334 * This function parses the channel list passed in the format
1335 * SETROAMSCANCHANNELS<space><Number of channels><space>Channel 1<space>Channel 2<space>Channel N
1336 * if the Number of channels (N) does not match with the actual number
1337 * of channels passed then take the minimum of N and count of
1338 * (Ch1, Ch2, ...Ch M). For example, if SETROAMSCANCHANNELS 3 36 40 44 48,
1339 * only 36, 40 and 44 shall be taken. If SETROAMSCANCHANNELS 5 36 40 44 48,
1340 * ignore 5 and take 36, 40, 44 and 48. This function does not take care of
1341 * removing duplicate channels from the list
1342 *
1343 * Return: 0 for success non-zero for failure
1344 */
1345static int
1346hdd_parse_channellist(const uint8_t *pValue, uint8_t *pChannelList,
1347 uint8_t *pNumChannels)
1348{
1349 const uint8_t *inPtr = pValue;
1350 int tempInt;
1351 int j = 0;
1352 int v = 0;
1353 char buf[32];
1354
1355 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
1356 /* no argument after the command */
1357 if (NULL == inPtr) {
1358 return -EINVAL;
1359 }
1360
1361 /* no space after the command */
1362 else if (SPACE_ASCII_VALUE != *inPtr) {
1363 return -EINVAL;
1364 }
1365
1366 /* remove empty spaces */
1367 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
1368 inPtr++;
1369
1370 /* no argument followed by spaces */
1371 if ('\0' == *inPtr) {
1372 return -EINVAL;
1373 }
1374
1375 /* get the first argument ie the number of channels */
1376 v = sscanf(inPtr, "%31s ", buf);
1377 if (1 != v)
1378 return -EINVAL;
1379
1380 v = kstrtos32(buf, 10, &tempInt);
1381 if ((v < 0) ||
1382 (tempInt <= 0) || (tempInt > WNI_CFG_VALID_CHANNEL_LIST_LEN)) {
1383 return -EINVAL;
1384 }
1385
1386 *pNumChannels = tempInt;
1387
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001388 hdd_info("Number of channels are: %d", *pNumChannels);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001389
1390 for (j = 0; j < (*pNumChannels); j++) {
1391 /*
1392 * inPtr pointing to the beginning of first space after number
1393 * of channels
1394 */
1395 inPtr = strpbrk(inPtr, " ");
1396 /* no channel list after the number of channels argument */
1397 if (NULL == inPtr) {
1398 if (0 != j) {
1399 *pNumChannels = j;
1400 return 0;
1401 } else {
1402 return -EINVAL;
1403 }
1404 }
1405
1406 /* remove empty space */
1407 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
1408 inPtr++;
1409
1410 /*
1411 * no channel list after the number of channels
1412 * argument and spaces
1413 */
1414 if ('\0' == *inPtr) {
1415 if (0 != j) {
1416 *pNumChannels = j;
1417 return 0;
1418 } else {
1419 return -EINVAL;
1420 }
1421 }
1422
1423 v = sscanf(inPtr, "%31s ", buf);
1424 if (1 != v)
1425 return -EINVAL;
1426
1427 v = kstrtos32(buf, 10, &tempInt);
1428 if ((v < 0) ||
1429 (tempInt <= 0) ||
1430 (tempInt > WNI_CFG_CURRENT_CHANNEL_STAMAX)) {
1431 return -EINVAL;
1432 }
1433 pChannelList[j] = tempInt;
1434
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001435 hdd_info("Channel %d added to preferred channel list",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001436 pChannelList[j]);
1437 }
1438
1439 return 0;
1440}
1441
1442/**
1443 * hdd_parse_set_roam_scan_channels_v1() - parse version 1 of the
1444 * SETROAMSCANCHANNELS command
1445 * @adapter: Adapter upon which the command was received
1446 * @command: ASCII text command that was received
1447 *
1448 * This function parses the v1 SETROAMSCANCHANNELS command with the format
1449 *
1450 * SETROAMSCANCHANNELS N C1 C2 ... Cn
1451 *
1452 * Where "N" is the ASCII representation of the number of channels and
1453 * C1 thru Cn is the ASCII representation of the channels. For example
1454 *
1455 * SETROAMSCANCHANNELS 4 36 40 44 48
1456 *
1457 * Return: 0 for success non-zero for failure
1458 */
1459static int
1460hdd_parse_set_roam_scan_channels_v1(hdd_adapter_t *adapter,
1461 const char *command)
1462{
1463 uint8_t channel_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
1464 uint8_t num_chan = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301465 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001466 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1467 int ret;
1468
1469 ret = hdd_parse_channellist(command, channel_list, &num_chan);
1470 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001471 hdd_err("Failed to parse channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001472 goto exit;
1473 }
1474
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301475 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001476 TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL,
1477 adapter->sessionId, num_chan));
1478
1479 if (num_chan > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001480 hdd_err("number of channels (%d) supported exceeded max (%d)",
1481 num_chan, WNI_CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001482 ret = -EINVAL;
1483 goto exit;
1484 }
1485
1486 status =
1487 sme_change_roam_scan_channel_list(hdd_ctx->hHal,
1488 adapter->sessionId,
1489 channel_list, num_chan);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301490 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001491 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001492 ret = -EINVAL;
1493 goto exit;
1494 }
1495exit:
1496 return ret;
1497}
1498
1499/**
1500 * hdd_parse_set_roam_scan_channels_v2() - parse version 2 of the
1501 * SETROAMSCANCHANNELS command
1502 * @adapter: Adapter upon which the command was received
1503 * @command: Command that was received, ASCII command
1504 * followed by binary data
1505 *
1506 * This function parses the v2 SETROAMSCANCHANNELS command with the format
1507 *
1508 * SETROAMSCANCHANNELS [N][C1][C2][Cn]
1509 *
1510 * The command begins with SETROAMSCANCHANNELS followed by a space, but
1511 * what follows the space is an array of u08 parameters. For example
1512 *
1513 * SETROAMSCANCHANNELS [0x04 0x24 0x28 0x2c 0x30]
1514 *
1515 * Return: 0 for success non-zero for failure
1516 */
1517static int
1518hdd_parse_set_roam_scan_channels_v2(hdd_adapter_t *adapter,
1519 const char *command)
1520{
1521 const uint8_t *value;
1522 uint8_t channel_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
1523 uint8_t channel;
1524 uint8_t num_chan;
1525 int i;
1526 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301527 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001528 int ret = 0;
1529
1530 /* array of values begins after "SETROAMSCANCHANNELS " */
1531 value = command + 20;
1532
1533 num_chan = *value++;
1534 if (num_chan > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001535 hdd_err("number of channels (%d) supported exceeded max (%d)",
1536 num_chan, WNI_CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001537 ret = -EINVAL;
1538 goto exit;
1539 }
1540
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301541 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001542 TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL,
1543 adapter->sessionId, num_chan));
1544
1545 for (i = 0; i < num_chan; i++) {
1546 channel = *value++;
1547 if (channel > WNI_CFG_CURRENT_CHANNEL_STAMAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001548 hdd_err("index %d invalid channel %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001549 i, channel);
1550 ret = -EINVAL;
1551 goto exit;
1552 }
1553 channel_list[i] = channel;
1554 }
1555 status =
1556 sme_change_roam_scan_channel_list(hdd_ctx->hHal,
1557 adapter->sessionId,
1558 channel_list, num_chan);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301559 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001560 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001561 ret = -EINVAL;
1562 goto exit;
1563 }
1564exit:
1565 return ret;
1566}
1567
1568/**
1569 * hdd_parse_set_roam_scan_channels() - parse the
1570 * SETROAMSCANCHANNELS command
1571 * @adapter: Adapter upon which the command was received
1572 * @command: Command that was received
1573 *
1574 * There are two different versions of the SETROAMSCANCHANNELS command.
1575 * Version 1 of the command contains a parameter list that is ASCII
1576 * characters whereas version 2 contains a binary payload. Determine
1577 * if a version 1 or a version 2 command is being parsed by examining
1578 * the parameters, and then dispatch the parser that is appropriate for
1579 * the command.
1580 *
1581 * Return: 0 for success non-zero for failure
1582 */
1583static int
1584hdd_parse_set_roam_scan_channels(hdd_adapter_t *adapter, const char *command)
1585{
1586 const char *cursor;
1587 char ch;
1588 bool v1;
1589 int ret;
1590
1591 /* start after "SETROAMSCANCHANNELS " */
1592 cursor = command + 20;
1593
1594 /* assume we have a version 1 command until proven otherwise */
1595 v1 = true;
1596
1597 /* v1 params will only contain ASCII digits and space */
1598 while ((ch = *cursor++) && v1) {
1599 if (!(isdigit(ch) || isspace(ch))) {
1600 v1 = false;
1601 }
1602 }
1603 if (v1) {
1604 ret = hdd_parse_set_roam_scan_channels_v1(adapter, command);
1605 } else {
1606 ret = hdd_parse_set_roam_scan_channels_v2(adapter, command);
1607 }
1608
1609 return ret;
1610}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001611
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08001612#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001613/**
1614 * hdd_parse_plm_cmd() - HDD Parse Plm command
1615 * @pValue: Pointer to input data
1616 * @pPlmRequest:Pointer to output struct tpSirPlmReq
1617 *
1618 * This function parses the plm command passed in the format
1619 * CCXPLMREQ<space><enable><space><dialog_token><space>
1620 * <meas_token><space><num_of_bursts><space><burst_int><space>
1621 * <measu duration><space><burst_len><space><desired_tx_pwr>
1622 * <space><multcast_addr><space><number_of_channels>
1623 * <space><channel_numbers>
1624 *
1625 * Return: 0 for success non-zero for failure
1626 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301627QDF_STATUS hdd_parse_plm_cmd(uint8_t *pValue, tSirPlmReq *pPlmRequest)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001628{
1629 uint8_t *cmdPtr = NULL;
1630 int count, content = 0, ret = 0;
1631 char buf[32];
1632
1633 /* move to argument list */
1634 cmdPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
1635 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301636 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001637
1638 /* no space after the command */
1639 if (SPACE_ASCII_VALUE != *cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301640 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001641
1642 /* remove empty spaces */
1643 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1644 cmdPtr++;
1645
1646 /* START/STOP PLM req */
1647 ret = sscanf(cmdPtr, "%31s ", buf);
1648 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301649 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001650
1651 ret = kstrtos32(buf, 10, &content);
1652 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301653 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001654
1655 pPlmRequest->enable = content;
1656 cmdPtr = strpbrk(cmdPtr, " ");
1657
1658 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301659 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001660
1661 /* remove empty spaces */
1662 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1663 cmdPtr++;
1664
1665 /* Dialog token of radio meas req containing meas reqIE */
1666 ret = sscanf(cmdPtr, "%31s ", buf);
1667 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301668 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001669
1670 ret = kstrtos32(buf, 10, &content);
1671 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301672 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001673
1674 pPlmRequest->diag_token = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001675 hdd_debug("diag token %d", pPlmRequest->diag_token);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001676 cmdPtr = strpbrk(cmdPtr, " ");
1677
1678 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301679 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001680
1681 /* remove empty spaces */
1682 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1683 cmdPtr++;
1684
1685 /* measurement token of meas req IE */
1686 ret = sscanf(cmdPtr, "%31s ", buf);
1687 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301688 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001689
1690 ret = kstrtos32(buf, 10, &content);
1691 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301692 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001693
1694 pPlmRequest->meas_token = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001695 hdd_debug("meas token %d", pPlmRequest->meas_token);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001696
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001697 hdd_err("PLM req %s", pPlmRequest->enable ? "START" : "STOP");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001698 if (pPlmRequest->enable) {
1699
1700 cmdPtr = strpbrk(cmdPtr, " ");
1701
1702 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301703 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001704
1705 /* remove empty spaces */
1706 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1707 cmdPtr++;
1708
1709 /* total number of bursts after which STA stops sending */
1710 ret = sscanf(cmdPtr, "%31s ", buf);
1711 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301712 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001713
1714 ret = kstrtos32(buf, 10, &content);
1715 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301716 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001717
1718 if (content < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301719 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001720
1721 pPlmRequest->numBursts = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001722 hdd_debug("num burst %d", pPlmRequest->numBursts);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001723 cmdPtr = strpbrk(cmdPtr, " ");
1724
1725 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301726 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001727
1728 /* remove empty spaces */
1729 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1730 cmdPtr++;
1731
1732 /* burst interval in seconds */
1733 ret = sscanf(cmdPtr, "%31s ", buf);
1734 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301735 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001736
1737 ret = kstrtos32(buf, 10, &content);
1738 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301739 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001740
1741 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301742 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001743
1744 pPlmRequest->burstInt = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001745 hdd_debug("burst Int %d", pPlmRequest->burstInt);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001746 cmdPtr = strpbrk(cmdPtr, " ");
1747
1748 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301749 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001750
1751 /* remove empty spaces */
1752 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1753 cmdPtr++;
1754
1755 /* Meas dur in TU's,STA goes off-ch and transmit PLM bursts */
1756 ret = sscanf(cmdPtr, "%31s ", buf);
1757 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301758 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001759
1760 ret = kstrtos32(buf, 10, &content);
1761 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301762 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001763
1764 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301765 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001766
1767 pPlmRequest->measDuration = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001768 hdd_debug("measDur %d", pPlmRequest->measDuration);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001769 cmdPtr = strpbrk(cmdPtr, " ");
1770
1771 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301772 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001773
1774 /* remove empty spaces */
1775 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1776 cmdPtr++;
1777
1778 /* burst length of PLM bursts */
1779 ret = sscanf(cmdPtr, "%31s ", buf);
1780 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301781 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001782
1783 ret = kstrtos32(buf, 10, &content);
1784 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301785 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001786
1787 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301788 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001789
1790 pPlmRequest->burstLen = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001791 hdd_debug("burstLen %d", pPlmRequest->burstLen);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001792 cmdPtr = strpbrk(cmdPtr, " ");
1793
1794 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301795 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001796
1797 /* remove empty spaces */
1798 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1799 cmdPtr++;
1800
1801 /* desired tx power for transmission of PLM bursts */
1802 ret = sscanf(cmdPtr, "%31s ", buf);
1803 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301804 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001805
1806 ret = kstrtos32(buf, 10, &content);
1807 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301808 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001809
1810 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301811 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001812
1813 pPlmRequest->desiredTxPwr = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001814 hdd_debug("desiredTxPwr %d",
1815 pPlmRequest->desiredTxPwr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001816
Anurag Chouhan6d760662016-02-20 16:05:43 +05301817 for (count = 0; count < QDF_MAC_ADDR_SIZE; count++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001818 cmdPtr = strpbrk(cmdPtr, " ");
1819
1820 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301821 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001822
1823 /* remove empty spaces */
1824 while ((SPACE_ASCII_VALUE == *cmdPtr)
1825 && ('\0' != *cmdPtr))
1826 cmdPtr++;
1827
1828 ret = sscanf(cmdPtr, "%31s ", buf);
1829 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301830 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001831
1832 ret = kstrtos32(buf, 16, &content);
1833 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301834 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001835
Srinivas Girigowda5146dee2015-11-18 21:46:48 -08001836 pPlmRequest->mac_addr.bytes[count] = content;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001837 }
1838
Srinivas Girigowda5146dee2015-11-18 21:46:48 -08001839 hdd_debug("MC addr " MAC_ADDRESS_STR,
1840 MAC_ADDR_ARRAY(pPlmRequest->mac_addr.bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001841
1842 cmdPtr = strpbrk(cmdPtr, " ");
1843
1844 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301845 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001846
1847 /* remove empty spaces */
1848 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1849 cmdPtr++;
1850
1851 /* number of channels */
1852 ret = sscanf(cmdPtr, "%31s ", buf);
1853 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301854 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001855
1856 ret = kstrtos32(buf, 10, &content);
1857 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301858 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001859
1860 if (content < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301861 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001862
1863 pPlmRequest->plmNumCh = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001864 hdd_debug("numch %d", pPlmRequest->plmNumCh);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001865
1866 /* Channel numbers */
1867 for (count = 0; count < pPlmRequest->plmNumCh; count++) {
1868 cmdPtr = strpbrk(cmdPtr, " ");
1869
1870 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301871 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001872
1873 /* remove empty spaces */
1874 while ((SPACE_ASCII_VALUE == *cmdPtr)
1875 && ('\0' != *cmdPtr))
1876 cmdPtr++;
1877
1878 ret = sscanf(cmdPtr, "%31s ", buf);
1879 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301880 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001881
1882 ret = kstrtos32(buf, 10, &content);
1883 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301884 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001885
1886 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301887 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001888
1889 pPlmRequest->plmChList[count] = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001890 hdd_debug(" ch- %d", pPlmRequest->plmChList[count]);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001891 }
1892 }
1893 /* If PLM START */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301894 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001895}
1896#endif
1897
1898#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
1899static void wlan_hdd_ready_to_extwow(void *callbackContext, bool is_success)
1900{
1901 hdd_context_t *hdd_ctx = (hdd_context_t *) callbackContext;
1902 int rc;
1903
1904 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301905 if (rc)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001906 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001907 hdd_ctx->ext_wow_should_suspend = is_success;
1908 complete(&hdd_ctx->ready_to_extwow);
1909}
1910
1911static int hdd_enable_ext_wow(hdd_adapter_t *adapter,
1912 tpSirExtWoWParams arg_params)
1913{
1914 tSirExtWoWParams params;
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301915 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001916 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1917 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
1918 int rc;
1919
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301920 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001921
1922 INIT_COMPLETION(hdd_ctx->ready_to_extwow);
1923
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301924 qdf_ret_status = sme_configure_ext_wow(hHal, &params,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001925 &wlan_hdd_ready_to_extwow,
1926 hdd_ctx);
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301927 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001928 hdd_err("sme_configure_ext_wow returned failure %d",
1929 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001930 return -EPERM;
1931 }
1932
1933 rc = wait_for_completion_timeout(&hdd_ctx->ready_to_extwow,
1934 msecs_to_jiffies(WLAN_WAIT_TIME_READY_TO_EXTWOW));
1935 if (!rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001936 hdd_err("Failed to get ready to extwow");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001937 return -EPERM;
1938 }
1939
1940 if (hdd_ctx->ext_wow_should_suspend) {
1941 if (hdd_ctx->config->extWowGotoSuspend) {
1942 pm_message_t state;
1943
1944 state.event = PM_EVENT_SUSPEND;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001945 hdd_info("Received ready to ExtWoW. Going to suspend");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001946
1947 rc = wlan_hdd_cfg80211_suspend_wlan(hdd_ctx->wiphy, NULL);
1948 if (rc < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001949 hdd_err("wlan_hdd_cfg80211_suspend_wlan failed, error = %d",
1950 rc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001951 return rc;
1952 }
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301953 qdf_ret_status = wlan_hdd_bus_suspend(state);
1954 if (qdf_ret_status != QDF_STATUS_SUCCESS) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001955 hdd_err("wlan_hdd_suspend failed, status = %d",
1956 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001957 wlan_hdd_cfg80211_resume_wlan(hdd_ctx->wiphy);
1958 return -EPERM;
1959 }
1960 }
1961 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001962 hdd_err("Received ready to ExtWoW failure");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001963 return -EPERM;
1964 }
1965
1966 return 0;
1967}
1968
1969static int hdd_enable_ext_wow_parser(hdd_adapter_t *adapter, int vdev_id,
1970 int value)
1971{
1972 tSirExtWoWParams params;
1973 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1974 int rc;
1975
1976 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301977 if (rc)
1978 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001979
1980 if (value < EXT_WOW_TYPE_APP_TYPE1 ||
1981 value > EXT_WOW_TYPE_APP_TYPE1_2) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001982 hdd_err("Invalid type");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001983 return -EINVAL;
1984 }
1985
1986 if (value == EXT_WOW_TYPE_APP_TYPE1 &&
1987 hdd_ctx->is_extwow_app_type1_param_set)
1988 params.type = value;
1989 else if (value == EXT_WOW_TYPE_APP_TYPE2 &&
1990 hdd_ctx->is_extwow_app_type2_param_set)
1991 params.type = value;
1992 else if (value == EXT_WOW_TYPE_APP_TYPE1_2 &&
1993 hdd_ctx->is_extwow_app_type1_param_set &&
1994 hdd_ctx->is_extwow_app_type2_param_set)
1995 params.type = value;
1996 else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001997 hdd_err("Set app params before enable it value %d",
1998 value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001999 return -EINVAL;
2000 }
2001
2002 params.vdev_id = vdev_id;
2003 params.wakeup_pin_num = hdd_ctx->config->extWowApp1WakeupPinNumber |
2004 (hdd_ctx->config->extWowApp2WakeupPinNumber
2005 << 8);
2006
2007 return hdd_enable_ext_wow(adapter, &params);
2008}
2009
2010static int hdd_set_app_type1_params(tHalHandle hHal,
2011 tpSirAppType1Params arg_params)
2012{
2013 tSirAppType1Params params;
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05302014 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002015
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302016 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002017
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05302018 qdf_ret_status = sme_configure_app_type1_params(hHal, &params);
2019 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002020 hdd_err("sme_configure_app_type1_params returned failure %d",
2021 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002022 return -EPERM;
2023 }
2024
2025 return 0;
2026}
2027
2028static int hdd_set_app_type1_parser(hdd_adapter_t *adapter,
2029 char *arg, int len)
2030{
2031 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2032 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
2033 char id[20], password[20];
2034 tSirAppType1Params params;
Srinivas Girigowda04209912015-11-24 12:11:13 -08002035 int rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002036
2037 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302038 if (rc)
2039 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002040
2041 if (2 != sscanf(arg, "%8s %16s", id, password)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002042 hdd_err("Invalid Number of arguments");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002043 return -EINVAL;
2044 }
2045
2046 memset(&params, 0, sizeof(tSirAppType1Params));
2047 params.vdev_id = adapter->sessionId;
Anurag Chouhanc5548422016-02-24 18:33:27 +05302048 qdf_copy_macaddr(&params.wakee_mac_addr, &adapter->macAddressCurrent);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002049
2050 params.id_length = strlen(id);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302051 qdf_mem_copy(params.identification_id, id, params.id_length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002052 params.pass_length = strlen(password);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302053 qdf_mem_copy(params.password, password, params.pass_length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002054
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002055 hdd_info("%d %pM %.8s %u %.16s %u",
2056 params.vdev_id, params.wakee_mac_addr.bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002057 params.identification_id, params.id_length,
2058 params.password, params.pass_length);
2059
2060 return hdd_set_app_type1_params(hHal, &params);
2061}
2062
2063static int hdd_set_app_type2_params(tHalHandle hHal,
2064 tpSirAppType2Params arg_params)
2065{
2066 tSirAppType2Params params;
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05302067 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002068
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302069 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002070
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05302071 qdf_ret_status = sme_configure_app_type2_params(hHal, &params);
2072 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002073 hdd_err("sme_configure_app_type2_params returned failure %d",
2074 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002075 return -EPERM;
2076 }
2077
2078 return 0;
2079}
2080
2081static int hdd_set_app_type2_parser(hdd_adapter_t *adapter,
2082 char *arg, int len)
2083{
2084 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2085 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
2086 char mac_addr[20], rc4_key[20];
Anurag Chouhan6d760662016-02-20 16:05:43 +05302087 unsigned int gateway_mac[QDF_MAC_ADDR_SIZE];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002088 tSirAppType2Params params;
2089 int ret;
2090
2091 ret = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302092 if (ret)
2093 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002094
2095 memset(&params, 0, sizeof(tSirAppType2Params));
2096
Bhargav Shahf4fd97d2015-07-08 10:21:37 +05302097 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 -08002098 mac_addr, rc4_key, (unsigned int *)&params.ip_id,
2099 (unsigned int *)&params.ip_device_ip,
2100 (unsigned int *)&params.ip_server_ip,
2101 (unsigned int *)&params.tcp_seq,
2102 (unsigned int *)&params.tcp_ack_seq,
Bhargav Shahf4fd97d2015-07-08 10:21:37 +05302103 (uint16_t *)&params.tcp_src_port,
2104 (uint16_t *)&params.tcp_dst_port,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002105 (unsigned int *)&params.keepalive_init,
2106 (unsigned int *)&params.keepalive_min,
2107 (unsigned int *)&params.keepalive_max,
2108 (unsigned int *)&params.keepalive_inc,
2109 (unsigned int *)&params.tcp_tx_timeout_val,
2110 (unsigned int *)&params.tcp_rx_timeout_val);
2111
2112 if (ret != 15 && ret != 7) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002113 hdd_err("Invalid Number of arguments");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002114 return -EINVAL;
2115 }
2116
2117 if (6 !=
2118 sscanf(mac_addr, "%02x:%02x:%02x:%02x:%02x:%02x", &gateway_mac[0],
2119 &gateway_mac[1], &gateway_mac[2], &gateway_mac[3],
2120 &gateway_mac[4], &gateway_mac[5])) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002121 hdd_err("Invalid MacAddress Input %s", mac_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002122 return -EINVAL;
2123 }
2124
2125 if (params.tcp_src_port > WLAN_HDD_MAX_TCP_PORT ||
2126 params.tcp_dst_port > WLAN_HDD_MAX_TCP_PORT) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002127 hdd_err("Invalid TCP Port Number");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002128 return -EINVAL;
2129 }
2130
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302131 qdf_mem_copy(&params.gateway_mac.bytes, (uint8_t *) &gateway_mac,
Anurag Chouhan6d760662016-02-20 16:05:43 +05302132 QDF_MAC_ADDR_SIZE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002133
2134 params.rc4_key_len = strlen(rc4_key);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302135 qdf_mem_copy(params.rc4_key, rc4_key, params.rc4_key_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002136
2137 params.vdev_id = adapter->sessionId;
2138 params.tcp_src_port = (params.tcp_src_port != 0) ?
2139 params.tcp_src_port : hdd_ctx->config->extWowApp2TcpSrcPort;
2140 params.tcp_dst_port = (params.tcp_dst_port != 0) ?
2141 params.tcp_dst_port : hdd_ctx->config->extWowApp2TcpDstPort;
2142 params.keepalive_init = (params.keepalive_init != 0) ?
2143 params.keepalive_init : hdd_ctx->config->
2144 extWowApp2KAInitPingInterval;
2145 params.keepalive_min =
2146 (params.keepalive_min != 0) ?
2147 params.keepalive_min :
2148 hdd_ctx->config->extWowApp2KAMinPingInterval;
2149 params.keepalive_max =
2150 (params.keepalive_max != 0) ?
2151 params.keepalive_max :
2152 hdd_ctx->config->extWowApp2KAMaxPingInterval;
2153 params.keepalive_inc =
2154 (params.keepalive_inc != 0) ?
2155 params.keepalive_inc :
2156 hdd_ctx->config->extWowApp2KAIncPingInterval;
2157 params.tcp_tx_timeout_val =
2158 (params.tcp_tx_timeout_val != 0) ?
2159 params.tcp_tx_timeout_val :
2160 hdd_ctx->config->extWowApp2TcpTxTimeout;
2161 params.tcp_rx_timeout_val =
2162 (params.tcp_rx_timeout_val != 0) ?
2163 params.tcp_rx_timeout_val :
2164 hdd_ctx->config->extWowApp2TcpRxTimeout;
2165
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002166 hdd_info("%pM %.16s %u %u %u %u %u %u %u %u %u %u %u %u %u",
2167 gateway_mac, rc4_key, params.ip_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002168 params.ip_device_ip, params.ip_server_ip, params.tcp_seq,
2169 params.tcp_ack_seq, params.tcp_src_port, params.tcp_dst_port,
2170 params.keepalive_init, params.keepalive_min,
2171 params.keepalive_max, params.keepalive_inc,
2172 params.tcp_tx_timeout_val, params.tcp_rx_timeout_val);
2173
2174 return hdd_set_app_type2_params(hHal, &params);
2175}
2176#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
2177
2178/**
2179 * hdd_parse_setmaxtxpower_command() - HDD Parse MAXTXPOWER command
2180 * @pValue: Pointer to MAXTXPOWER command
2181 * @pDbm: Pointer to tx power
2182 *
2183 * This function parses the MAXTXPOWER command passed in the format
2184 * MAXTXPOWER<space>X(Tx power in dbm)
2185 *
2186 * For example input commands:
2187 * 1) MAXTXPOWER -8 -> This is translated into set max TX power to -8 dbm
2188 * 2) MAXTXPOWER -23 -> This is translated into set max TX power to -23 dbm
2189 *
2190 * Return: 0 for success non-zero for failure
2191 */
2192static int hdd_parse_setmaxtxpower_command(uint8_t *pValue, int *pTxPower)
2193{
2194 uint8_t *inPtr = pValue;
2195 int tempInt;
2196 int v = 0;
2197 *pTxPower = 0;
2198
2199 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2200 /* no argument after the command */
2201 if (NULL == inPtr) {
2202 return -EINVAL;
2203 }
2204
2205 /* no space after the command */
2206 else if (SPACE_ASCII_VALUE != *inPtr) {
2207 return -EINVAL;
2208 }
2209
2210 /* remove empty spaces */
2211 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2212 inPtr++;
2213
2214 /* no argument followed by spaces */
2215 if ('\0' == *inPtr) {
2216 return 0;
2217 }
2218
2219 v = kstrtos32(inPtr, 10, &tempInt);
2220
2221 /* Range checking for passed parameter */
2222 if ((tempInt < HDD_MIN_TX_POWER) || (tempInt > HDD_MAX_TX_POWER)) {
2223 return -EINVAL;
2224 }
2225
2226 *pTxPower = tempInt;
2227
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002228 hdd_info("SETMAXTXPOWER: %d", *pTxPower);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002229
2230 return 0;
2231} /* End of hdd_parse_setmaxtxpower_command */
2232
2233static int hdd_get_dwell_time(struct hdd_config *pCfg, uint8_t *command,
2234 char *extra, uint8_t n, uint8_t *len)
2235{
2236 int ret = 0;
2237
2238 if (!pCfg || !command || !extra || !len) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002239 hdd_err("argument passed for GETDWELLTIME is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002240 ret = -EINVAL;
2241 return ret;
2242 }
2243
2244 if (strncmp(command, "GETDWELLTIME ACTIVE MAX", 23) == 0) {
2245 *len = scnprintf(extra, n, "GETDWELLTIME ACTIVE MAX %u\n",
2246 (int)pCfg->nActiveMaxChnTime);
2247 return ret;
2248 } else if (strncmp(command, "GETDWELLTIME ACTIVE MIN", 23) == 0) {
2249 *len = scnprintf(extra, n, "GETDWELLTIME ACTIVE MIN %u\n",
2250 (int)pCfg->nActiveMinChnTime);
2251 return ret;
2252 } else if (strncmp(command, "GETDWELLTIME PASSIVE MAX", 24) == 0) {
2253 *len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MAX %u\n",
2254 (int)pCfg->nPassiveMaxChnTime);
2255 return ret;
2256 } else if (strncmp(command, "GETDWELLTIME PASSIVE MIN", 24) == 0) {
2257 *len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MIN %u\n",
2258 (int)pCfg->nPassiveMinChnTime);
2259 return ret;
2260 } else if (strncmp(command, "GETDWELLTIME", 12) == 0) {
2261 *len = scnprintf(extra, n, "GETDWELLTIME %u \n",
2262 (int)pCfg->nActiveMaxChnTime);
2263 return ret;
2264 } else {
2265 ret = -EINVAL;
2266 }
2267
2268 return ret;
2269}
2270
2271static int hdd_set_dwell_time(hdd_adapter_t *adapter, uint8_t *command)
2272{
2273 tHalHandle hHal;
2274 struct hdd_config *pCfg;
2275 uint8_t *value = command;
2276 tSmeConfigParams smeConfig;
2277 int val = 0, temp = 0;
2278
2279 pCfg = (WLAN_HDD_GET_CTX(adapter))->config;
2280 hHal = WLAN_HDD_GET_HAL_CTX(adapter);
2281 if (!pCfg || !hHal) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002282 hdd_err("argument passed for SETDWELLTIME is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002283 return -EINVAL;
2284 }
2285
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302286 qdf_mem_zero(&smeConfig, sizeof(smeConfig));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002287 sme_get_config_param(hHal, &smeConfig);
2288
2289 if (strncmp(command, "SETDWELLTIME ACTIVE MAX", 23) == 0) {
2290 value = value + 24;
2291 temp = kstrtou32(value, 10, &val);
2292 if (temp != 0 || val < CFG_ACTIVE_MAX_CHANNEL_TIME_MIN ||
2293 val > CFG_ACTIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002294 hdd_err("argument passed for SETDWELLTIME ACTIVE MAX is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002295 return -EFAULT;
2296 }
2297 pCfg->nActiveMaxChnTime = val;
2298 smeConfig.csrConfig.nActiveMaxChnTime = val;
2299 sme_update_config(hHal, &smeConfig);
2300 } else if (strncmp(command, "SETDWELLTIME ACTIVE MIN", 23) == 0) {
2301 value = value + 24;
2302 temp = kstrtou32(value, 10, &val);
2303 if (temp != 0 || val < CFG_ACTIVE_MIN_CHANNEL_TIME_MIN ||
2304 val > CFG_ACTIVE_MIN_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002305 hdd_err("argument passed for SETDWELLTIME ACTIVE MIN is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002306 return -EFAULT;
2307 }
2308 pCfg->nActiveMinChnTime = val;
2309 smeConfig.csrConfig.nActiveMinChnTime = val;
2310 sme_update_config(hHal, &smeConfig);
2311 } else if (strncmp(command, "SETDWELLTIME PASSIVE MAX", 24) == 0) {
2312 value = value + 25;
2313 temp = kstrtou32(value, 10, &val);
2314 if (temp != 0 || val < CFG_PASSIVE_MAX_CHANNEL_TIME_MIN ||
2315 val > CFG_PASSIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002316 hdd_err("argument passed for SETDWELLTIME PASSIVE MAX is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002317 return -EFAULT;
2318 }
2319 pCfg->nPassiveMaxChnTime = val;
2320 smeConfig.csrConfig.nPassiveMaxChnTime = val;
2321 sme_update_config(hHal, &smeConfig);
2322 } else if (strncmp(command, "SETDWELLTIME PASSIVE MIN", 24) == 0) {
2323 value = value + 25;
2324 temp = kstrtou32(value, 10, &val);
2325 if (temp != 0 || val < CFG_PASSIVE_MIN_CHANNEL_TIME_MIN ||
2326 val > CFG_PASSIVE_MIN_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002327 hdd_err("argument passed for SETDWELLTIME PASSIVE MIN is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002328 return -EFAULT;
2329 }
2330 pCfg->nPassiveMinChnTime = val;
2331 smeConfig.csrConfig.nPassiveMinChnTime = val;
2332 sme_update_config(hHal, &smeConfig);
2333 } else if (strncmp(command, "SETDWELLTIME", 12) == 0) {
2334 value = value + 13;
2335 temp = kstrtou32(value, 10, &val);
2336 if (temp != 0 || val < CFG_ACTIVE_MAX_CHANNEL_TIME_MIN ||
2337 val > CFG_ACTIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002338 hdd_err("argument passed for SETDWELLTIME is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002339 return -EFAULT;
2340 }
2341 pCfg->nActiveMaxChnTime = val;
2342 smeConfig.csrConfig.nActiveMaxChnTime = val;
2343 sme_update_config(hHal, &smeConfig);
2344 } else {
2345 return -EINVAL;
2346 }
2347
2348 return 0;
2349}
2350
2351static void hdd_get_link_status_cb(uint8_t status, void *context)
2352{
2353 struct statsContext *pLinkContext;
2354 hdd_adapter_t *adapter;
2355
2356 if (NULL == context) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002357 hdd_err("Bad context [%p]", context);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002358 return;
2359 }
2360
2361 pLinkContext = context;
2362 adapter = pLinkContext->pAdapter;
2363
2364 spin_lock(&hdd_context_lock);
2365
2366 if ((NULL == adapter) ||
2367 (LINK_STATUS_MAGIC != pLinkContext->magic)) {
2368 /*
2369 * the caller presumably timed out so there is
2370 * nothing we can do
2371 */
2372 spin_unlock(&hdd_context_lock);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002373 hdd_warn("Invalid context, adapter [%p] magic [%08x]",
2374 adapter, pLinkContext->magic);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002375 return;
2376 }
2377
2378 /* context is valid so caller is still waiting */
2379
2380 /* paranoia: invalidate the magic */
2381 pLinkContext->magic = 0;
2382
2383 /* copy over the status */
2384 adapter->linkStatus = status;
2385
2386 /* notify the caller */
2387 complete(&pLinkContext->completion);
2388
2389 /* serialization is complete */
2390 spin_unlock(&hdd_context_lock);
2391}
2392
2393/**
2394 * wlan_hdd_get_link_status() - get link status
2395 * @pAdapter: pointer to the adapter
2396 *
2397 * This function sends a request to query the link status and waits
2398 * on a timer to invoke the callback. if the callback is invoked then
2399 * latest link status shall be returned or otherwise cached value
2400 * will be returned.
2401 *
2402 * Return: On success, link status shall be returned.
2403 * On error or not associated, link status 0 will be returned.
2404 */
2405static int wlan_hdd_get_link_status(hdd_adapter_t *adapter)
2406{
2407
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002408 hdd_station_ctx_t *pHddStaCtx =
2409 WLAN_HDD_GET_STATION_CTX_PTR(adapter);
2410 struct statsContext context;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302411 QDF_STATUS hstatus;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002412 unsigned long rc;
2413
Prashanth Bhatta9e143052015-12-04 11:56:47 -08002414 if (cds_is_driver_recovering()) {
2415 hdd_warn("Recovery in Progress. State: 0x%x Ignore!!!",
2416 cds_get_driver_state());
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002417 return 0;
2418 }
2419
Krunal Sonibe766b02016-03-10 13:00:44 -08002420 if ((QDF_STA_MODE != adapter->device_mode) &&
2421 (QDF_P2P_CLIENT_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002422 hdd_warn("Unsupported in mode %s(%d)",
2423 hdd_device_mode_to_string(adapter->device_mode),
2424 adapter->device_mode);
2425 return 0;
2426 }
2427
2428 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
2429 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
2430 /* If not associated, then expected link status return
2431 * value is 0
2432 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002433 hdd_info("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002434 return 0;
2435 }
2436
2437 init_completion(&context.completion);
2438 context.pAdapter = adapter;
2439 context.magic = LINK_STATUS_MAGIC;
2440 hstatus = sme_get_link_status(WLAN_HDD_GET_HAL_CTX(adapter),
2441 hdd_get_link_status_cb,
2442 &context, adapter->sessionId);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302443 if (QDF_STATUS_SUCCESS != hstatus) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002444 hdd_err("Unable to retrieve link status");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002445 /* return a cached value */
2446 } else {
2447 /* request is sent -- wait for the response */
2448 rc = wait_for_completion_timeout(&context.completion,
2449 msecs_to_jiffies(WLAN_WAIT_TIME_LINK_STATUS));
2450 if (!rc)
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002451 hdd_err("SME timed out while retrieving link status");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002452 }
2453
2454 spin_lock(&hdd_context_lock);
2455 context.magic = 0;
2456 spin_unlock(&hdd_context_lock);
2457
2458 /* either callback updated adapter stats or it has cached data */
2459 return adapter->linkStatus;
2460}
2461
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002462static void hdd_tx_fail_ind_callback(uint8_t *MacAddr, uint8_t seqNo)
2463{
2464 int payload_len;
2465 struct sk_buff *skb;
2466 struct nlmsghdr *nlh;
2467 uint8_t *data;
2468
2469 payload_len = ETH_ALEN;
2470
Ryan Hsu5e2e2052016-04-28 10:19:38 -07002471 if (0 == cesium_pid || cesium_nl_srv_sock == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002472 hdd_err("cesium process not registered");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002473 return;
2474 }
2475
2476 skb = nlmsg_new(payload_len, GFP_ATOMIC);
2477 if (skb == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002478 hdd_err("nlmsg_new() failed for msg size[%d]",
2479 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002480 return;
2481 }
2482
2483 nlh = nlmsg_put(skb, cesium_pid, seqNo, 0, payload_len, NLM_F_REQUEST);
2484
2485 if (NULL == nlh) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002486 hdd_err("nlmsg_put() failed for msg size[%d]",
2487 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002488
2489 kfree_skb(skb);
2490 return;
2491 }
2492
2493 data = nlmsg_data(nlh);
2494 memcpy(data, MacAddr, ETH_ALEN);
2495
2496 if (nlmsg_unicast(cesium_nl_srv_sock, skb, cesium_pid) < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002497 hdd_err("nlmsg_unicast() failed for msg size[%d]",
2498 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002499 }
2500
2501 return;
2502}
2503
2504
2505/**
2506 * hdd_ParseuserParams - return a pointer to the next argument
2507 * @pValue: Input argument string
2508 * @ppArg: Output pointer to the next argument
2509 *
2510 * This function parses argument stream and finds the pointer
2511 * to the next argument
2512 *
2513 * Return: 0 if the next argument found; -EINVAL otherwise
2514 */
2515static int hdd_parse_user_params(uint8_t *pValue, uint8_t **ppArg)
2516{
2517 uint8_t *pVal;
2518
2519 pVal = strnchr(pValue, strlen(pValue), ' ');
2520
2521 if (NULL == pVal) {
2522 /* no argument remains */
2523 return -EINVAL;
2524 } else if (SPACE_ASCII_VALUE != *pVal) {
2525 /* no space after the current argument */
2526 return -EINVAL;
2527 }
2528
2529 pVal++;
2530
2531 /* remove empty spaces */
2532 while ((SPACE_ASCII_VALUE == *pVal) && ('\0' != *pVal)) {
2533 pVal++;
2534 }
2535
2536 /* no argument followed by spaces */
2537 if ('\0' == *pVal) {
2538 return -EINVAL;
2539 }
2540
2541 *ppArg = pVal;
2542
2543 return 0;
2544}
2545
2546/**
2547 * hdd_parse_ibsstx_fail_event_params - Parse params
2548 * for SETIBSSTXFAILEVENT
2549 * @pValue: Input ibss tx fail event argument
2550 * @tx_fail_count: (Output parameter) Tx fail counter
2551 * @pid: (Output parameter) PID
2552 *
2553 * Return: 0 if the parsing succeeds; -EINVAL otherwise
2554 */
2555static int hdd_parse_ibsstx_fail_event_params(uint8_t *pValue,
2556 uint8_t *tx_fail_count,
2557 uint16_t *pid)
2558{
2559 uint8_t *param = NULL;
2560 int ret;
2561
2562 ret = hdd_parse_user_params(pValue, &param);
2563
2564 if (0 == ret && NULL != param) {
2565 if (1 != sscanf(param, "%hhu", tx_fail_count)) {
2566 ret = -EINVAL;
2567 goto done;
2568 }
2569 } else {
2570 goto done;
2571 }
2572
2573 if (0 == *tx_fail_count) {
2574 *pid = 0;
2575 goto done;
2576 }
2577
2578 pValue = param;
2579 pValue++;
2580
2581 ret = hdd_parse_user_params(pValue, &param);
2582
2583 if (0 == ret) {
2584 if (1 != sscanf(param, "%hu", pid)) {
2585 ret = -EINVAL;
2586 goto done;
2587 }
2588 } else {
2589 goto done;
2590 }
2591
2592done:
2593 return ret;
2594}
2595
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08002596#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002597/**
2598 * hdd_parse_ese_beacon_req() - Parse ese beacon request
2599 * @pValue: Pointer to data
2600 * @pEseBcnReq: Output pointer to store parsed ie information
2601 *
2602 * This function parses the ese beacon request passed in the format
2603 * CCXBEACONREQ<space><Number of fields><space><Measurement token>
2604 * <space>Channel 1<space>Scan Mode <space>Meas Duration<space>Channel N
2605 * <space>Scan Mode N<space>Meas Duration N
2606 *
2607 * If the Number of bcn req fields (N) does not match with the
2608 * actual number of fields passed then take N.
2609 * <Meas Token><Channel><Scan Mode> and <Meas Duration> are treated
2610 * as one pair. For example, CCXBEACONREQ 2 1 1 1 30 2 44 0 40.
2611 * This function does not take care of removing duplicate channels from the
2612 * list
2613 *
2614 * Return: 0 for success non-zero for failure
2615 */
2616static int hdd_parse_ese_beacon_req(uint8_t *pValue,
2617 tCsrEseBeaconReq *pEseBcnReq)
2618{
2619 uint8_t *inPtr = pValue;
2620 int tempInt = 0;
2621 int j = 0, i = 0, v = 0;
2622 char buf[32];
2623
2624 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2625 /* no argument after the command */
2626 if (NULL == inPtr) {
2627 return -EINVAL;
2628 }
2629 /* no space after the command */
2630 else if (SPACE_ASCII_VALUE != *inPtr) {
2631 return -EINVAL;
2632 }
2633
2634 /* remove empty spaces */
2635 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2636 inPtr++;
2637
2638 /* no argument followed by spaces */
2639 if ('\0' == *inPtr)
2640 return -EINVAL;
2641
2642 /* get the first argument ie measurement token */
2643 v = sscanf(inPtr, "%31s ", buf);
2644 if (1 != v)
2645 return -EINVAL;
2646
2647 v = kstrtos32(buf, 10, &tempInt);
2648 if (v < 0)
2649 return -EINVAL;
2650
2651 pEseBcnReq->numBcnReqIe = tempInt;
2652
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002653 hdd_info("Number of Bcn Req Ie fields(%d)",
2654 pEseBcnReq->numBcnReqIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002655
2656 for (j = 0; j < (pEseBcnReq->numBcnReqIe); j++) {
2657 for (i = 0; i < 4; i++) {
2658 /*
2659 * inPtr pointing to the beginning of 1st space
2660 * after number of ie fields
2661 */
2662 inPtr = strpbrk(inPtr, " ");
2663 /* no ie data after the number of ie fields argument */
2664 if (NULL == inPtr)
2665 return -EINVAL;
2666
2667 /* remove empty space */
2668 while ((SPACE_ASCII_VALUE == *inPtr)
2669 && ('\0' != *inPtr))
2670 inPtr++;
2671
2672 /*
2673 * no ie data after the number of ie fields
2674 * argument and spaces
2675 */
2676 if ('\0' == *inPtr)
2677 return -EINVAL;
2678
2679 v = sscanf(inPtr, "%31s ", buf);
2680 if (1 != v)
2681 return -EINVAL;
2682
2683 v = kstrtos32(buf, 10, &tempInt);
2684 if (v < 0)
2685 return -EINVAL;
2686
2687 switch (i) {
2688 case 0: /* Measurement token */
2689 if (tempInt <= 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002690 hdd_err("Invalid Measurement Token(%d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002691 tempInt);
2692 return -EINVAL;
2693 }
2694 pEseBcnReq->bcnReq[j].measurementToken =
2695 tempInt;
2696 break;
2697
2698 case 1: /* Channel number */
2699 if ((tempInt <= 0) ||
2700 (tempInt >
2701 WNI_CFG_CURRENT_CHANNEL_STAMAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002702 hdd_err("Invalid Channel Number(%d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002703 tempInt);
2704 return -EINVAL;
2705 }
2706 pEseBcnReq->bcnReq[j].channel = tempInt;
2707 break;
2708
2709 case 2: /* Scan mode */
2710 if ((tempInt < eSIR_PASSIVE_SCAN)
2711 || (tempInt > eSIR_BEACON_TABLE)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002712 hdd_err("Invalid Scan Mode(%d) Expected{0|1|2}",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002713 tempInt);
2714 return -EINVAL;
2715 }
2716 pEseBcnReq->bcnReq[j].scanMode = tempInt;
2717 break;
2718
2719 case 3: /* Measurement duration */
2720 if (((tempInt <= 0)
2721 && (pEseBcnReq->bcnReq[j].scanMode !=
2722 eSIR_BEACON_TABLE)) ||
2723 ((tempInt < 0) &&
2724 (pEseBcnReq->bcnReq[j].scanMode ==
2725 eSIR_BEACON_TABLE))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002726 hdd_err("Invalid Measurement Duration(%d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002727 tempInt);
2728 return -EINVAL;
2729 }
2730 pEseBcnReq->bcnReq[j].measurementDuration =
2731 tempInt;
2732 break;
2733 }
2734 }
2735 }
2736
2737 for (j = 0; j < pEseBcnReq->numBcnReqIe; j++) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002738 hdd_info("Index(%d) Measurement Token(%u) Channel(%u) Scan Mode(%u) Measurement Duration(%u)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002739 j,
2740 pEseBcnReq->bcnReq[j].measurementToken,
2741 pEseBcnReq->bcnReq[j].channel,
2742 pEseBcnReq->bcnReq[j].scanMode,
2743 pEseBcnReq->bcnReq[j].measurementDuration);
2744 }
2745
2746 return 0;
2747}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002748
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002749/**
2750 * hdd_parse_get_cckm_ie() - HDD Parse and fetch the CCKM IE
2751 * @pValue: Pointer to input data
2752 * @pCckmIe: Pointer to output cckm Ie
2753 * @pCckmIeLen: Pointer to output cckm ie length
2754 *
2755 * This function parses the SETCCKM IE command
2756 * SETCCKMIE<space><ie data>
2757 *
2758 * Return: 0 for success non-zero for failure
2759 */
2760static int hdd_parse_get_cckm_ie(uint8_t *pValue, uint8_t **pCckmIe,
2761 uint8_t *pCckmIeLen)
2762{
2763 uint8_t *inPtr = pValue;
2764 uint8_t *dataEnd;
2765 int j = 0;
2766 int i = 0;
2767 uint8_t tempByte = 0;
2768 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2769 /* no argument after the command */
2770 if (NULL == inPtr) {
2771 return -EINVAL;
2772 }
2773 /* no space after the command */
2774 else if (SPACE_ASCII_VALUE != *inPtr) {
2775 return -EINVAL;
2776 }
2777 /* remove empty spaces */
2778 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2779 inPtr++;
2780 /* no argument followed by spaces */
2781 if ('\0' == *inPtr) {
2782 return -EINVAL;
2783 }
2784 /* find the length of data */
2785 dataEnd = inPtr;
2786 while (('\0' != *dataEnd)) {
2787 dataEnd++;
2788 ++(*pCckmIeLen);
2789 }
2790 if (*pCckmIeLen <= 0)
2791 return -EINVAL;
2792 /*
2793 * Allocate the number of bytes based on the number of input characters
2794 * whether it is even or odd.
2795 * if the number of input characters are even, then we need N / 2 byte.
2796 * if the number of input characters are odd, then we need do
2797 * (N + 1) / 2 to compensate rounding off.
2798 * For example, if N = 18, then (18 + 1) / 2 = 9 bytes are enough.
2799 * If N = 19, then we need 10 bytes, hence (19 + 1) / 2 = 10 bytes
2800 */
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302801 *pCckmIe = qdf_mem_malloc((*pCckmIeLen + 1) / 2);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002802 if (NULL == *pCckmIe) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002803 hdd_err("qdf_mem_malloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002804 return -ENOMEM;
2805 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302806 qdf_mem_zero(*pCckmIe, (*pCckmIeLen + 1) / 2);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002807 /*
2808 * the buffer received from the upper layer is character buffer,
2809 * we need to prepare the buffer taking 2 characters in to a U8 hex
2810 * decimal number for example 7f0000f0...form a buffer to contain
2811 * 7f in 0th location, 00 in 1st and f0 in 3rd location
2812 */
2813 for (i = 0, j = 0; j < *pCckmIeLen; j += 2) {
2814 tempByte = (hex_to_bin(inPtr[j]) << 4) |
2815 (hex_to_bin(inPtr[j + 1]));
2816 (*pCckmIe)[i++] = tempByte;
2817 }
2818 *pCckmIeLen = i;
2819 return 0;
2820}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08002821#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002822
2823int wlan_hdd_set_mc_rate(hdd_adapter_t *pAdapter, int targetRate)
2824{
2825 tSirRateUpdateInd rateUpdate = {0};
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302826 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002827 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
2828 struct hdd_config *pConfig = NULL;
2829
2830 if (pHddCtx == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002831 hdd_err("HDD context is null");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002832 return -EINVAL;
2833 }
Krunal Sonibe766b02016-03-10 13:00:44 -08002834 if ((QDF_IBSS_MODE != pAdapter->device_mode) &&
2835 (QDF_SAP_MODE != pAdapter->device_mode) &&
2836 (QDF_STA_MODE != pAdapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002837 hdd_err("Received SETMCRATE cmd in invalid mode %s(%d)",
2838 hdd_device_mode_to_string(pAdapter->device_mode),
2839 pAdapter->device_mode);
2840 hdd_err("SETMCRATE cmd is allowed only in STA, IBSS or SOFTAP mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002841 return -EINVAL;
2842 }
2843 pConfig = pHddCtx->config;
2844 rateUpdate.nss = (pConfig->enable2x2 == 0) ? 0 : 1;
2845 rateUpdate.dev_mode = pAdapter->device_mode;
2846 rateUpdate.mcastDataRate24GHz = targetRate;
2847 rateUpdate.mcastDataRate24GHzTxFlag = 1;
2848 rateUpdate.mcastDataRate5GHz = targetRate;
2849 rateUpdate.bcastDataRate = -1;
Anurag Chouhanc5548422016-02-24 18:33:27 +05302850 qdf_copy_macaddr(&rateUpdate.bssid, &pAdapter->macAddressCurrent);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002851 hdd_info("MC Target rate %d, mac = %pM, dev_mode %s(%d)",
2852 rateUpdate.mcastDataRate24GHz, rateUpdate.bssid.bytes,
2853 hdd_device_mode_to_string(pAdapter->device_mode),
2854 pAdapter->device_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002855 status = sme_send_rate_update_ind(pHddCtx->hHal, &rateUpdate);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302856 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002857 hdd_err("SETMCRATE failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002858 return -EFAULT;
2859 }
2860 return 0;
2861}
2862
2863static int drv_cmd_p2p_dev_addr(hdd_adapter_t *adapter,
2864 hdd_context_t *hdd_ctx,
2865 uint8_t *command,
2866 uint8_t command_len,
2867 hdd_priv_data_t *priv_data)
2868{
2869 int ret = 0;
2870
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302871 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002872 TRACE_CODE_HDD_P2P_DEV_ADDR_IOCTL,
2873 adapter->sessionId,
2874 (unsigned)(*(hdd_ctx->p2pDeviceAddress.bytes + 2)
2875 << 24 | *(hdd_ctx->p2pDeviceAddress.bytes
2876 + 3) << 16 | *(hdd_ctx->
2877 p2pDeviceAddress.bytes + 4) << 8 |
2878 *(hdd_ctx->p2pDeviceAddress.bytes +
2879 5))));
2880
2881 if (copy_to_user(priv_data->buf, hdd_ctx->p2pDeviceAddress.bytes,
2882 sizeof(tSirMacAddr))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002883 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002884 ret = -EFAULT;
2885 }
2886
2887 return ret;
2888}
2889
2890/**
2891 * drv_cmd_p2p_set_noa() - Handler for P2P_SET_NOA driver command
2892 * @adapter: Adapter on which the command was received
2893 * @hdd_ctx: HDD global context
2894 * @command: Entire driver command received from userspace
2895 * @command_len: Length of @command
2896 * @priv_data: Pointer to ioctl private data structure
2897 *
2898 * This is a trivial command hander function which simply forwards the
2899 * command to the actual command processor within the P2P module.
2900 *
2901 * Return: 0 on success, non-zero on failure
2902 */
2903static int drv_cmd_p2p_set_noa(hdd_adapter_t *adapter,
2904 hdd_context_t *hdd_ctx,
2905 uint8_t *command,
2906 uint8_t command_len,
2907 hdd_priv_data_t *priv_data)
2908{
2909 return hdd_set_p2p_noa(adapter->dev, command);
2910}
2911
2912/**
2913 * drv_cmd_p2p_set_ps() - Handler for P2P_SET_PS driver command
2914 * @adapter: Adapter on which the command was received
2915 * @hdd_ctx: HDD global context
2916 * @command: Entire driver command received from userspace
2917 * @command_len: Length of @command
2918 * @priv_data: Pointer to ioctl private data structure
2919 *
2920 * This is a trivial command hander function which simply forwards the
2921 * command to the actual command processor within the P2P module.
2922 *
2923 * Return: 0 on success, non-zero on failure
2924 */
2925static int drv_cmd_p2p_set_ps(hdd_adapter_t *adapter,
2926 hdd_context_t *hdd_ctx,
2927 uint8_t *command,
2928 uint8_t command_len,
2929 hdd_priv_data_t *priv_data)
2930{
2931 return hdd_set_p2p_opps(adapter->dev, command);
2932}
2933
2934static int drv_cmd_set_band(hdd_adapter_t *adapter,
2935 hdd_context_t *hdd_ctx,
2936 uint8_t *command,
2937 uint8_t command_len,
2938 hdd_priv_data_t *priv_data)
2939{
2940 int ret = 0;
2941
2942 uint8_t *ptr = command;
2943
2944 /* Change band request received */
2945
2946 /*
2947 * First 8 bytes will have "SETBAND " and
2948 * 9 byte will have band setting value
2949 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002950 hdd_info("SetBandCommand Info comm %s UL %d, TL %d",
2951 command, priv_data->used_len,
2952 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002953
2954 /* Change band request received */
2955 ret = hdd_set_band_helper(adapter->dev, ptr);
2956
2957 return ret;
2958}
2959
2960static int drv_cmd_set_wmmps(hdd_adapter_t *adapter,
2961 hdd_context_t *hdd_ctx,
2962 uint8_t *command,
2963 uint8_t command_len,
2964 hdd_priv_data_t *priv_data)
2965{
2966 return hdd_wmmps_helper(adapter, command);
2967}
2968
2969static int drv_cmd_country(hdd_adapter_t *adapter,
2970 hdd_context_t *hdd_ctx,
2971 uint8_t *command,
2972 uint8_t command_len,
2973 hdd_priv_data_t *priv_data)
2974{
2975 int ret = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302976 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002977 unsigned long rc;
2978 char *country_code;
2979
2980 country_code = command + 8;
2981
2982 INIT_COMPLETION(adapter->change_country_code);
2983
2984 status = sme_change_country_code(hdd_ctx->hHal,
2985 wlan_hdd_change_country_code_callback,
2986 country_code,
2987 adapter,
2988 hdd_ctx->pcds_context,
2989 eSIR_TRUE,
2990 eSIR_TRUE);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302991 if (status == QDF_STATUS_SUCCESS) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002992 rc = wait_for_completion_timeout(
2993 &adapter->change_country_code,
2994 msecs_to_jiffies(WLAN_WAIT_TIME_COUNTRY));
2995 if (!rc)
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002996 hdd_err("SME while setting country code timed out");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002997 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002998 hdd_err("SME Change Country code fail, status %d",
2999 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003000 ret = -EINVAL;
3001 }
3002
3003 return ret;
3004}
3005
3006static int drv_cmd_set_roam_trigger(hdd_adapter_t *adapter,
3007 hdd_context_t *hdd_ctx,
3008 uint8_t *command,
3009 uint8_t command_len,
3010 hdd_priv_data_t *priv_data)
3011{
3012 int ret = 0;
3013 uint8_t *value = command;
3014 int8_t rssi = 0;
3015 uint8_t lookUpThreshold = CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_DEFAULT;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303016 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003017
3018 /* Move pointer to ahead of SETROAMTRIGGER<delimiter> */
3019 value = value + command_len + 1;
3020
3021 /* Convert the value from ascii to integer */
3022 ret = kstrtos8(value, 10, &rssi);
3023 if (ret < 0) {
3024 /*
3025 * If the input value is greater than max value of datatype,
3026 * then also kstrtou8 fails
3027 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003028 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
3029 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN,
3030 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003031 ret = -EINVAL;
3032 goto exit;
3033 }
3034
3035 lookUpThreshold = abs(rssi);
3036
3037 if ((lookUpThreshold < CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN)
3038 || (lookUpThreshold > CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003039 hdd_err("Neighbor lookup threshold value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003040 lookUpThreshold,
3041 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN,
3042 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX);
3043 ret = -EINVAL;
3044 goto exit;
3045 }
3046
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303047 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003048 TRACE_CODE_HDD_SETROAMTRIGGER_IOCTL,
3049 adapter->sessionId, lookUpThreshold));
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003050 hdd_info("Received Command to Set Roam trigger (Neighbor lookup threshold) = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003051 lookUpThreshold);
3052
3053 hdd_ctx->config->nNeighborLookupRssiThreshold = lookUpThreshold;
3054 status = sme_set_neighbor_lookup_rssi_threshold(hdd_ctx->hHal,
3055 adapter->sessionId,
3056 lookUpThreshold);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303057 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003058 hdd_err("Failed to set roam trigger, try again");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003059 ret = -EPERM;
3060 goto exit;
3061 }
3062
3063exit:
3064 return ret;
3065}
3066
3067static int drv_cmd_get_roam_trigger(hdd_adapter_t *adapter,
3068 hdd_context_t *hdd_ctx,
3069 uint8_t *command,
3070 uint8_t command_len,
3071 hdd_priv_data_t *priv_data)
3072{
3073 int ret = 0;
3074 uint8_t lookUpThreshold =
3075 sme_get_neighbor_lookup_rssi_threshold(hdd_ctx->hHal);
3076 int rssi = (-1) * lookUpThreshold;
3077 char extra[32];
3078 uint8_t len = 0;
3079
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303080 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003081 TRACE_CODE_HDD_GETROAMTRIGGER_IOCTL,
3082 adapter->sessionId, lookUpThreshold));
3083
3084 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303085 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003086 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003087 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003088 ret = -EFAULT;
3089 }
3090
3091 return ret;
3092}
3093
3094static int drv_cmd_set_roam_scan_period(hdd_adapter_t *adapter,
3095 hdd_context_t *hdd_ctx,
3096 uint8_t *command,
3097 uint8_t command_len,
3098 hdd_priv_data_t *priv_data)
3099{
3100 int ret = 0;
3101 uint8_t *value = command;
3102 uint8_t roamScanPeriod = 0;
3103 uint16_t neighborEmptyScanRefreshPeriod =
3104 CFG_EMPTY_SCAN_REFRESH_PERIOD_DEFAULT;
3105
3106 /* input refresh period is in terms of seconds */
3107
3108 /* Move pointer to ahead of SETROAMSCANPERIOD<delimiter> */
3109 value = value + command_len + 1;
3110
3111 /* Convert the value from ascii to integer */
3112 ret = kstrtou8(value, 10, &roamScanPeriod);
3113 if (ret < 0) {
3114 /*
3115 * If the input value is greater than max value of datatype,
3116 * then also kstrtou8 fails
3117 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003118 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
3119 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000),
3120 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003121 ret = -EINVAL;
3122 goto exit;
3123 }
3124
3125 if ((roamScanPeriod < (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000))
3126 || (roamScanPeriod > (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003127 hdd_err("Roam scan period value %d is out of range (Min: %d Max: %d)",
3128 roamScanPeriod,
3129 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000),
3130 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003131 ret = -EINVAL;
3132 goto exit;
3133 }
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303134 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003135 TRACE_CODE_HDD_SETROAMSCANPERIOD_IOCTL,
3136 adapter->sessionId, roamScanPeriod));
3137 neighborEmptyScanRefreshPeriod = roamScanPeriod * 1000;
3138
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003139 hdd_info("Received Command to Set roam scan period (Empty Scan refresh period) = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003140 roamScanPeriod);
3141
3142 hdd_ctx->config->nEmptyScanRefreshPeriod =
3143 neighborEmptyScanRefreshPeriod;
3144 sme_update_empty_scan_refresh_period(hdd_ctx->hHal,
3145 adapter->sessionId,
3146 neighborEmptyScanRefreshPeriod);
3147
3148exit:
3149 return ret;
3150}
3151
3152static int drv_cmd_get_roam_scan_period(hdd_adapter_t *adapter,
3153 hdd_context_t *hdd_ctx,
3154 uint8_t *command,
3155 uint8_t command_len,
3156 hdd_priv_data_t *priv_data)
3157{
3158 int ret = 0;
3159 uint16_t nEmptyScanRefreshPeriod =
3160 sme_get_empty_scan_refresh_period(hdd_ctx->hHal);
3161 char extra[32];
3162 uint8_t len = 0;
3163
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303164 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003165 TRACE_CODE_HDD_GETROAMSCANPERIOD_IOCTL,
3166 adapter->sessionId,
3167 nEmptyScanRefreshPeriod));
3168 len = scnprintf(extra, sizeof(extra), "%s %d",
3169 "GETROAMSCANPERIOD",
3170 (nEmptyScanRefreshPeriod / 1000));
3171 /* Returned value is in units of seconds */
Anurag Chouhan6d760662016-02-20 16:05:43 +05303172 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003173 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003174 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003175 ret = -EFAULT;
3176 }
3177
3178 return ret;
3179}
3180
3181static int drv_cmd_set_roam_scan_refresh_period(hdd_adapter_t *adapter,
3182 hdd_context_t *hdd_ctx,
3183 uint8_t *command,
3184 uint8_t command_len,
3185 hdd_priv_data_t *priv_data)
3186{
3187 int ret = 0;
3188 uint8_t *value = command;
3189 uint8_t roamScanRefreshPeriod = 0;
3190 uint16_t neighborScanRefreshPeriod =
3191 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_DEFAULT;
3192
3193 /* input refresh period is in terms of seconds */
3194 /* Move pointer to ahead of SETROAMSCANREFRESHPERIOD<delimiter> */
3195 value = value + command_len + 1;
3196
3197 /* Convert the value from ascii to integer */
3198 ret = kstrtou8(value, 10, &roamScanRefreshPeriod);
3199 if (ret < 0) {
3200 /*
3201 * If the input value is greater than max value of datatype,
3202 * then also kstrtou8 fails
3203 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003204 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
3205 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN / 1000,
3206 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX / 1000);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003207 ret = -EINVAL;
3208 goto exit;
3209 }
3210
3211 if ((roamScanRefreshPeriod <
3212 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN / 1000))
3213 || (roamScanRefreshPeriod >
3214 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX / 1000))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003215 hdd_err("Neighbor scan results refresh period value %d is out of range (Min: %d Max: %d)",
3216 roamScanRefreshPeriod,
3217 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN
3218 / 1000),
3219 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX
3220 / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003221 ret = -EINVAL;
3222 goto exit;
3223 }
3224 neighborScanRefreshPeriod = roamScanRefreshPeriod * 1000;
3225
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003226 hdd_info("Received Command to Set roam scan refresh period (Scan refresh period) = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003227 roamScanRefreshPeriod);
3228
3229 hdd_ctx->config->nNeighborResultsRefreshPeriod =
3230 neighborScanRefreshPeriod;
3231 sme_set_neighbor_scan_refresh_period(hdd_ctx->hHal,
3232 adapter->sessionId,
3233 neighborScanRefreshPeriod);
3234
3235exit:
3236 return ret;
3237}
3238
3239static int drv_cmd_get_roam_scan_refresh_period(hdd_adapter_t *adapter,
3240 hdd_context_t *hdd_ctx,
3241 uint8_t *command,
3242 uint8_t command_len,
3243 hdd_priv_data_t *priv_data)
3244{
3245 int ret = 0;
3246 uint16_t value =
3247 sme_get_neighbor_scan_refresh_period(hdd_ctx->hHal);
3248 char extra[32];
3249 uint8_t len = 0;
3250
3251 len = scnprintf(extra, sizeof(extra), "%s %d",
3252 "GETROAMSCANREFRESHPERIOD",
3253 (value / 1000));
3254 /* Returned value is in units of seconds */
Anurag Chouhan6d760662016-02-20 16:05:43 +05303255 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003256 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003257 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003258 ret = -EFAULT;
3259 }
3260
3261 return ret;
3262}
3263
3264static int drv_cmd_set_roam_mode(hdd_adapter_t *adapter,
3265 hdd_context_t *hdd_ctx,
3266 uint8_t *command,
3267 uint8_t command_len,
3268 hdd_priv_data_t *priv_data)
3269{
3270 int ret = 0;
3271 uint8_t *value = command;
3272 uint8_t roamMode = CFG_LFR_FEATURE_ENABLED_DEFAULT;
3273
3274 /* Move pointer to ahead of SETROAMMODE<delimiter> */
3275 value = value + SIZE_OF_SETROAMMODE + 1;
3276
3277 /* Convert the value from ascii to integer */
3278 ret = kstrtou8(value, SIZE_OF_SETROAMMODE, &roamMode);
3279 if (ret < 0) {
3280 /*
3281 * If the input value is greater than max value of datatype,
3282 * then also kstrtou8 fails
3283 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003284 hdd_err("kstrtou8 failed range [%d - %d]",
3285 CFG_LFR_FEATURE_ENABLED_MIN,
3286 CFG_LFR_FEATURE_ENABLED_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003287 ret = -EINVAL;
3288 goto exit;
3289 }
3290 if ((roamMode < CFG_LFR_FEATURE_ENABLED_MIN) ||
3291 (roamMode > CFG_LFR_FEATURE_ENABLED_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003292 hdd_err("Roam Mode value %d is out of range (Min: %d Max: %d)",
3293 roamMode,
3294 CFG_LFR_FEATURE_ENABLED_MIN,
3295 CFG_LFR_FEATURE_ENABLED_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003296 ret = -EINVAL;
3297 goto exit;
3298 }
3299
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003300 hdd_debug("Received Command to Set Roam Mode = %d",
3301 roamMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003302 /*
3303 * Note that
3304 * SETROAMMODE 0 is to enable LFR while
3305 * SETROAMMODE 1 is to disable LFR, but
3306 * notify_is_fast_roam_ini_feature_enabled 0/1 is to
3307 * enable/disable. So, we have to invert the value
3308 * to call sme_update_is_fast_roam_ini_feature_enabled.
3309 */
3310 if (CFG_LFR_FEATURE_ENABLED_MIN == roamMode)
3311 roamMode = CFG_LFR_FEATURE_ENABLED_MAX; /* Roam enable */
3312 else
3313 roamMode = CFG_LFR_FEATURE_ENABLED_MIN; /* Roam disable */
3314
3315 hdd_ctx->config->isFastRoamIniFeatureEnabled = roamMode;
3316 if (roamMode) {
3317 hdd_ctx->config->isRoamOffloadScanEnabled = roamMode;
3318 sme_update_roam_scan_offload_enabled(
3319 (tHalHandle)(hdd_ctx->hHal),
3320 hdd_ctx->config->isRoamOffloadScanEnabled);
3321 sme_update_is_fast_roam_ini_feature_enabled(
3322 hdd_ctx->hHal,
3323 adapter->sessionId,
3324 roamMode);
3325 } else {
3326 sme_update_is_fast_roam_ini_feature_enabled(
3327 hdd_ctx->hHal,
3328 adapter->sessionId,
3329 roamMode);
3330 hdd_ctx->config->isRoamOffloadScanEnabled = roamMode;
3331 sme_update_roam_scan_offload_enabled(
3332 (tHalHandle)(hdd_ctx->hHal),
3333 hdd_ctx->config->isRoamOffloadScanEnabled);
3334 }
3335
3336
3337exit:
3338 return ret;
3339}
3340
3341static int drv_cmd_get_roam_mode(hdd_adapter_t *adapter,
3342 hdd_context_t *hdd_ctx,
3343 uint8_t *command,
3344 uint8_t command_len,
3345 hdd_priv_data_t *priv_data)
3346{
3347 int ret = 0;
3348 bool roamMode = sme_get_is_lfr_feature_enabled(hdd_ctx->hHal);
3349 char extra[32];
3350 uint8_t len = 0;
3351
3352 /*
3353 * roamMode value shall be inverted because the sementics is different.
3354 */
3355 if (CFG_LFR_FEATURE_ENABLED_MIN == roamMode)
3356 roamMode = CFG_LFR_FEATURE_ENABLED_MAX;
3357 else
3358 roamMode = CFG_LFR_FEATURE_ENABLED_MIN;
3359
3360 len = scnprintf(extra, sizeof(extra), "%s %d", command, roamMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303361 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003362 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003363 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003364 ret = -EFAULT;
3365 }
3366
3367 return ret;
3368}
3369
3370static int drv_cmd_set_roam_delta(hdd_adapter_t *adapter,
3371 hdd_context_t *hdd_ctx,
3372 uint8_t *command,
3373 uint8_t command_len,
3374 hdd_priv_data_t *priv_data)
3375{
3376 int ret = 0;
3377 uint8_t *value = command;
3378 uint8_t roamRssiDiff = CFG_ROAM_RSSI_DIFF_DEFAULT;
3379
3380 /* Move pointer to ahead of SETROAMDELTA<delimiter> */
3381 value = value + command_len + 1;
3382
3383 /* Convert the value from ascii to integer */
3384 ret = kstrtou8(value, 10, &roamRssiDiff);
3385 if (ret < 0) {
3386 /*
3387 * If the input value is greater than max value of datatype,
3388 * then also kstrtou8 fails
3389 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003390 hdd_err("kstrtou8 failed range [%d - %d]",
3391 CFG_ROAM_RSSI_DIFF_MIN,
3392 CFG_ROAM_RSSI_DIFF_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003393 ret = -EINVAL;
3394 goto exit;
3395 }
3396
3397 if ((roamRssiDiff < CFG_ROAM_RSSI_DIFF_MIN) ||
3398 (roamRssiDiff > CFG_ROAM_RSSI_DIFF_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003399 hdd_err("Roam rssi diff value %d is out of range (Min: %d Max: %d)",
3400 roamRssiDiff,
3401 CFG_ROAM_RSSI_DIFF_MIN,
3402 CFG_ROAM_RSSI_DIFF_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003403 ret = -EINVAL;
3404 goto exit;
3405 }
3406
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003407 hdd_info("Received Command to Set roam rssi diff = %d",
3408 roamRssiDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003409
3410 hdd_ctx->config->RoamRssiDiff = roamRssiDiff;
3411 sme_update_roam_rssi_diff(hdd_ctx->hHal,
3412 adapter->sessionId,
3413 roamRssiDiff);
3414
3415exit:
3416 return ret;
3417}
3418
3419static int drv_cmd_get_roam_delta(hdd_adapter_t *adapter,
3420 hdd_context_t *hdd_ctx,
3421 uint8_t *command,
3422 uint8_t command_len,
3423 hdd_priv_data_t *priv_data)
3424{
3425 int ret = 0;
3426 uint8_t roamRssiDiff =
3427 sme_get_roam_rssi_diff(hdd_ctx->hHal);
3428 char extra[32];
3429 uint8_t len = 0;
3430
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303431 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003432 TRACE_CODE_HDD_GETROAMDELTA_IOCTL,
3433 adapter->sessionId, roamRssiDiff));
3434
3435 len = scnprintf(extra, sizeof(extra), "%s %d",
3436 command, roamRssiDiff);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303437 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003438
3439 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003440 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003441 ret = -EFAULT;
3442 }
3443
3444 return ret;
3445}
3446
3447static int drv_cmd_get_band(hdd_adapter_t *adapter,
3448 hdd_context_t *hdd_ctx,
3449 uint8_t *command,
3450 uint8_t command_len,
3451 hdd_priv_data_t *priv_data)
3452{
3453 int ret = 0;
3454 int band = -1;
3455 char extra[32];
3456 uint8_t len = 0;
3457
3458 hdd_get_band_helper(hdd_ctx, &band);
3459
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303460 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003461 TRACE_CODE_HDD_GETBAND_IOCTL,
3462 adapter->sessionId, band));
3463
3464 len = scnprintf(extra, sizeof(extra), "%s %d", command, band);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303465 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003466
3467 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003468 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003469 ret = -EFAULT;
3470 }
3471
3472 return ret;
3473}
3474
3475static int drv_cmd_set_roam_scan_channels(hdd_adapter_t *adapter,
3476 hdd_context_t *hdd_ctx,
3477 uint8_t *command,
3478 uint8_t command_len,
3479 hdd_priv_data_t *priv_data)
3480{
3481 return hdd_parse_set_roam_scan_channels(adapter, command);
3482}
3483
3484static int drv_cmd_get_roam_scan_channels(hdd_adapter_t *adapter,
3485 hdd_context_t *hdd_ctx,
3486 uint8_t *command,
3487 uint8_t command_len,
3488 hdd_priv_data_t *priv_data)
3489{
3490 int ret = 0;
3491 uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
3492 uint8_t numChannels = 0;
3493 uint8_t j = 0;
3494 char extra[128] = { 0 };
3495 int len;
3496
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303497 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003498 sme_get_roam_scan_channel_list(hdd_ctx->hHal,
3499 ChannelList,
3500 &numChannels,
3501 adapter->sessionId)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003502 hdd_alert("failed to get roam scan channel list");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003503 ret = -EFAULT;
3504 goto exit;
3505 }
3506
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303507 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003508 TRACE_CODE_HDD_GETROAMSCANCHANNELS_IOCTL,
3509 adapter->sessionId, numChannels));
3510 /*
3511 * output channel list is of the format
3512 * [Number of roam scan channels][Channel1][Channel2]...
3513 * copy the number of channels in the 0th index
3514 */
3515 len = scnprintf(extra, sizeof(extra), "%s %d", command,
3516 numChannels);
3517 for (j = 0; (j < numChannels); j++)
3518 len += scnprintf(extra + len, sizeof(extra) - len,
3519 " %d", ChannelList[j]);
3520
Anurag Chouhan6d760662016-02-20 16:05:43 +05303521 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003522 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003523 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003524 ret = -EFAULT;
3525 goto exit;
3526 }
3527
3528exit:
3529 return ret;
3530}
3531
3532static int drv_cmd_get_ccx_mode(hdd_adapter_t *adapter,
3533 hdd_context_t *hdd_ctx,
3534 uint8_t *command,
3535 uint8_t command_len,
3536 hdd_priv_data_t *priv_data)
3537{
3538 int ret = 0;
3539 bool eseMode = sme_get_is_ese_feature_enabled(hdd_ctx->hHal);
3540 char extra[32];
3541 uint8_t len = 0;
3542
3543 /*
3544 * Check if the features OKC/ESE/11R are supported simultaneously,
3545 * then this operation is not permitted (return FAILURE)
3546 */
3547 if (eseMode &&
3548 hdd_is_okc_mode_enabled(hdd_ctx) &&
3549 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003550 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003551 ret = -EPERM;
3552 goto exit;
3553 }
3554
3555 len = scnprintf(extra, sizeof(extra), "%s %d",
3556 "GETCCXMODE", eseMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303557 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003558 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003559 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003560 ret = -EFAULT;
3561 goto exit;
3562 }
3563
3564exit:
3565 return ret;
3566}
3567
3568static int drv_cmd_get_okc_mode(hdd_adapter_t *adapter,
3569 hdd_context_t *hdd_ctx,
3570 uint8_t *command,
3571 uint8_t command_len,
3572 hdd_priv_data_t *priv_data)
3573{
3574 int ret = 0;
3575 bool okcMode = hdd_is_okc_mode_enabled(hdd_ctx);
3576 char extra[32];
3577 uint8_t len = 0;
3578
3579 /*
3580 * Check if the features OKC/ESE/11R are supported simultaneously,
3581 * then this operation is not permitted (return FAILURE)
3582 */
3583 if (okcMode &&
3584 sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
3585 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003586 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003587 ret = -EPERM;
3588 goto exit;
3589 }
3590
3591 len = scnprintf(extra, sizeof(extra), "%s %d",
3592 "GETOKCMODE", okcMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303593 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003594
3595 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003596 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003597 ret = -EFAULT;
3598 goto exit;
3599 }
3600
3601exit:
3602 return ret;
3603}
3604
3605static int drv_cmd_get_fast_roam(hdd_adapter_t *adapter,
3606 hdd_context_t *hdd_ctx,
3607 uint8_t *command,
3608 uint8_t command_len,
3609 hdd_priv_data_t *priv_data)
3610{
3611 int ret = 0;
3612 bool lfrMode = sme_get_is_lfr_feature_enabled(hdd_ctx->hHal);
3613 char extra[32];
3614 uint8_t len = 0;
3615
3616 len = scnprintf(extra, sizeof(extra), "%s %d",
3617 "GETFASTROAM", lfrMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303618 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003619
3620 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003621 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003622 ret = -EFAULT;
3623 }
3624
3625 return ret;
3626}
3627
3628static int drv_cmd_get_fast_transition(hdd_adapter_t *adapter,
3629 hdd_context_t *hdd_ctx,
3630 uint8_t *command,
3631 uint8_t command_len,
3632 hdd_priv_data_t *priv_data)
3633{
3634 int ret = 0;
3635 bool ft = sme_get_is_ft_feature_enabled(hdd_ctx->hHal);
3636 char extra[32];
3637 uint8_t len = 0;
3638
3639 len = scnprintf(extra, sizeof(extra), "%s %d",
3640 "GETFASTTRANSITION", ft);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303641 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003642
3643 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003644 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003645 ret = -EFAULT;
3646 }
3647
3648 return ret;
3649}
3650
3651static int drv_cmd_set_roam_scan_channel_min_time(hdd_adapter_t *adapter,
3652 hdd_context_t *hdd_ctx,
3653 uint8_t *command,
3654 uint8_t command_len,
3655 hdd_priv_data_t *priv_data)
3656{
3657 int ret = 0;
3658 uint8_t *value = command;
3659 uint8_t minTime = CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_DEFAULT;
3660
3661 /* Move pointer to ahead of SETROAMSCANCHANNELMINTIME<delimiter> */
3662 value = value + command_len + 1;
3663
3664 /* Convert the value from ascii to integer */
3665 ret = kstrtou8(value, 10, &minTime);
3666 if (ret < 0) {
3667 /*
3668 * If the input value is greater than max value of datatype,
3669 * then also kstrtou8 fails
3670 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003671 hdd_err("kstrtou8 failed range [%d - %d]",
3672 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN,
3673 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003674 ret = -EINVAL;
3675 goto exit;
3676 }
3677
3678 if ((minTime < CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN) ||
3679 (minTime > CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003680 hdd_err("scan min channel time value %d is out of range (Min: %d Max: %d)",
3681 minTime,
3682 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN,
3683 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003684 ret = -EINVAL;
3685 goto exit;
3686 }
3687
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303688 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003689 TRACE_CODE_HDD_SETROAMSCANCHANNELMINTIME_IOCTL,
3690 adapter->sessionId, minTime));
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003691 hdd_info("Received Command to change channel min time = %d",
3692 minTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003693
3694 hdd_ctx->config->nNeighborScanMinChanTime = minTime;
3695 sme_set_neighbor_scan_min_chan_time(hdd_ctx->hHal,
3696 minTime,
3697 adapter->sessionId);
3698
3699exit:
3700 return ret;
3701}
3702
3703static int drv_cmd_send_action_frame(hdd_adapter_t *adapter,
3704 hdd_context_t *hdd_ctx,
3705 uint8_t *command,
3706 uint8_t command_len,
3707 hdd_priv_data_t *priv_data)
3708{
3709 return hdd_parse_sendactionframe(adapter, command);
3710}
3711
3712static int drv_cmd_get_roam_scan_channel_min_time(hdd_adapter_t *adapter,
3713 hdd_context_t *hdd_ctx,
3714 uint8_t *command,
3715 uint8_t command_len,
3716 hdd_priv_data_t *priv_data)
3717{
3718 int ret = 0;
3719 uint16_t val = sme_get_neighbor_scan_min_chan_time(hdd_ctx->hHal,
3720 adapter->sessionId);
3721 char extra[32];
3722 uint8_t len = 0;
3723
3724 /* value is interms of msec */
3725 len = scnprintf(extra, sizeof(extra), "%s %d",
3726 "GETROAMSCANCHANNELMINTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303727 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003728
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303729 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003730 TRACE_CODE_HDD_GETROAMSCANCHANNELMINTIME_IOCTL,
3731 adapter->sessionId, val));
3732
3733 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003734 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003735 ret = -EFAULT;
3736 }
3737
3738 return ret;
3739}
3740
3741static int drv_cmd_set_scan_channel_time(hdd_adapter_t *adapter,
3742 hdd_context_t *hdd_ctx,
3743 uint8_t *command,
3744 uint8_t command_len,
3745 hdd_priv_data_t *priv_data)
3746{
3747 int ret = 0;
3748 uint8_t *value = command;
3749 uint16_t maxTime = CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_DEFAULT;
3750
3751 /* Move pointer to ahead of SETSCANCHANNELTIME<delimiter> */
3752 value = value + command_len + 1;
3753
3754 /* Convert the value from ascii to integer */
3755 ret = kstrtou16(value, 10, &maxTime);
3756 if (ret < 0) {
3757 /*
3758 * If the input value is greater than max value of datatype,
3759 * then also kstrtou8 fails
3760 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003761 hdd_err("kstrtou16 failed range [%d - %d]",
3762 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN,
3763 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003764 ret = -EINVAL;
3765 goto exit;
3766 }
3767
3768 if ((maxTime < CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN) ||
3769 (maxTime > CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003770 hdd_err("lfr mode value %d is out of range (Min: %d Max: %d)",
3771 maxTime,
3772 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN,
3773 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003774 ret = -EINVAL;
3775 goto exit;
3776 }
3777
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003778 hdd_info("Received Command to change channel max time = %d",
3779 maxTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003780
3781 hdd_ctx->config->nNeighborScanMaxChanTime = maxTime;
3782 sme_set_neighbor_scan_max_chan_time(hdd_ctx->hHal,
3783 adapter->sessionId,
3784 maxTime);
3785
3786exit:
3787 return ret;
3788}
3789
3790static int drv_cmd_get_scan_channel_time(hdd_adapter_t *adapter,
3791 hdd_context_t *hdd_ctx,
3792 uint8_t *command,
3793 uint8_t command_len,
3794 hdd_priv_data_t *priv_data)
3795{
3796 int ret = 0;
3797 uint16_t val = sme_get_neighbor_scan_max_chan_time(hdd_ctx->hHal,
3798 adapter->sessionId);
3799 char extra[32];
3800 uint8_t len = 0;
3801
3802 /* value is interms of msec */
3803 len = scnprintf(extra, sizeof(extra), "%s %d",
3804 "GETSCANCHANNELTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303805 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003806
3807 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003808 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003809 ret = -EFAULT;
3810 }
3811
3812 return ret;
3813}
3814
3815static int drv_cmd_set_scan_home_time(hdd_adapter_t *adapter,
3816 hdd_context_t *hdd_ctx,
3817 uint8_t *command,
3818 uint8_t command_len,
3819 hdd_priv_data_t *priv_data)
3820{
3821 int ret = 0;
3822 uint8_t *value = command;
3823 uint16_t val = CFG_NEIGHBOR_SCAN_TIMER_PERIOD_DEFAULT;
3824
3825 /* Move pointer to ahead of SETSCANHOMETIME<delimiter> */
3826 value = value + command_len + 1;
3827
3828 /* Convert the value from ascii to integer */
3829 ret = kstrtou16(value, 10, &val);
3830 if (ret < 0) {
3831 /*
3832 * If the input value is greater than max value of datatype,
3833 * then also kstrtou8 fails
3834 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003835 hdd_err("kstrtou16 failed range [%d - %d]",
3836 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN,
3837 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003838 ret = -EINVAL;
3839 goto exit;
3840 }
3841
3842 if ((val < CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN) ||
3843 (val > CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003844 hdd_err("scan home time value %d is out of range (Min: %d Max: %d)",
3845 val,
3846 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN,
3847 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003848 ret = -EINVAL;
3849 goto exit;
3850 }
3851
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003852 hdd_info("Received Command to change scan home time = %d",
3853 val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003854
3855 hdd_ctx->config->nNeighborScanPeriod = val;
3856 sme_set_neighbor_scan_period(hdd_ctx->hHal,
3857 adapter->sessionId, val);
3858
3859exit:
3860 return ret;
3861}
3862
3863static int drv_cmd_get_scan_home_time(hdd_adapter_t *adapter,
3864 hdd_context_t *hdd_ctx,
3865 uint8_t *command,
3866 uint8_t command_len,
3867 hdd_priv_data_t *priv_data)
3868{
3869 int ret = 0;
3870 uint16_t val = sme_get_neighbor_scan_period(hdd_ctx->hHal,
3871 adapter->
3872 sessionId);
3873 char extra[32];
3874 uint8_t len = 0;
3875
3876 /* value is interms of msec */
3877 len = scnprintf(extra, sizeof(extra), "%s %d",
3878 "GETSCANHOMETIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303879 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003880
3881 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003882 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003883 ret = -EFAULT;
3884 }
3885
3886 return ret;
3887}
3888
3889static int drv_cmd_set_roam_intra_band(hdd_adapter_t *adapter,
3890 hdd_context_t *hdd_ctx,
3891 uint8_t *command,
3892 uint8_t command_len,
3893 hdd_priv_data_t *priv_data)
3894{
3895 int ret = 0;
3896 uint8_t *value = command;
3897 uint8_t val = CFG_ROAM_INTRA_BAND_DEFAULT;
3898
3899 /* Move pointer to ahead of SETROAMINTRABAND<delimiter> */
3900 value = value + command_len + 1;
3901
3902 /* Convert the value from ascii to integer */
3903 ret = kstrtou8(value, 10, &val);
3904 if (ret < 0) {
3905 /*
3906 * If the input value is greater than max value of datatype,
3907 * then also kstrtou8 fails
3908 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003909 hdd_err("kstrtou8 failed range [%d - %d]",
3910 CFG_ROAM_INTRA_BAND_MIN,
3911 CFG_ROAM_INTRA_BAND_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003912 ret = -EINVAL;
3913 goto exit;
3914 }
3915
3916 if ((val < CFG_ROAM_INTRA_BAND_MIN) ||
3917 (val > CFG_ROAM_INTRA_BAND_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003918 hdd_err("intra band mode value %d is out of range (Min: %d Max: %d)",
3919 val,
3920 CFG_ROAM_INTRA_BAND_MIN,
3921 CFG_ROAM_INTRA_BAND_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003922 ret = -EINVAL;
3923 goto exit;
3924 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003925 hdd_info("Received Command to change intra band = %d",
3926 val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003927
3928 hdd_ctx->config->nRoamIntraBand = val;
3929 sme_set_roam_intra_band(hdd_ctx->hHal, val);
3930
3931exit:
3932 return ret;
3933}
3934
3935static int drv_cmd_get_roam_intra_band(hdd_adapter_t *adapter,
3936 hdd_context_t *hdd_ctx,
3937 uint8_t *command,
3938 uint8_t command_len,
3939 hdd_priv_data_t *priv_data)
3940{
3941 int ret = 0;
3942 uint16_t val = sme_get_roam_intra_band(hdd_ctx->hHal);
3943 char extra[32];
3944 uint8_t len = 0;
3945
3946 /* value is interms of msec */
3947 len = scnprintf(extra, sizeof(extra), "%s %d",
3948 "GETROAMINTRABAND", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303949 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003950 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003951 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003952 ret = -EFAULT;
3953 }
3954
3955 return ret;
3956}
3957
3958static int drv_cmd_set_scan_n_probes(hdd_adapter_t *adapter,
3959 hdd_context_t *hdd_ctx,
3960 uint8_t *command,
3961 uint8_t command_len,
3962 hdd_priv_data_t *priv_data)
3963{
3964 int ret = 0;
3965 uint8_t *value = command;
3966 uint8_t nProbes = CFG_ROAM_SCAN_N_PROBES_DEFAULT;
3967
3968 /* Move pointer to ahead of SETSCANNPROBES<delimiter> */
3969 value = value + command_len + 1;
3970
3971 /* Convert the value from ascii to integer */
3972 ret = kstrtou8(value, 10, &nProbes);
3973 if (ret < 0) {
3974 /*
3975 * If the input value is greater than max value of datatype,
3976 * then also kstrtou8 fails
3977 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003978 hdd_err("kstrtou8 failed range [%d - %d]",
3979 CFG_ROAM_SCAN_N_PROBES_MIN,
3980 CFG_ROAM_SCAN_N_PROBES_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003981 ret = -EINVAL;
3982 goto exit;
3983 }
3984
3985 if ((nProbes < CFG_ROAM_SCAN_N_PROBES_MIN) ||
3986 (nProbes > CFG_ROAM_SCAN_N_PROBES_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003987 hdd_err("NProbes value %d is out of range (Min: %d Max: %d)",
3988 nProbes,
3989 CFG_ROAM_SCAN_N_PROBES_MIN,
3990 CFG_ROAM_SCAN_N_PROBES_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003991 ret = -EINVAL;
3992 goto exit;
3993 }
3994
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003995 hdd_info("Received Command to Set nProbes = %d",
3996 nProbes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003997
3998 hdd_ctx->config->nProbes = nProbes;
3999 sme_update_roam_scan_n_probes(hdd_ctx->hHal,
4000 adapter->sessionId, nProbes);
4001
4002exit:
4003 return ret;
4004}
4005
4006static int drv_cmd_get_scan_n_probes(hdd_adapter_t *adapter,
4007 hdd_context_t *hdd_ctx,
4008 uint8_t *command,
4009 uint8_t command_len,
4010 hdd_priv_data_t *priv_data)
4011{
4012 int ret = 0;
4013 uint8_t val = sme_get_roam_scan_n_probes(hdd_ctx->hHal);
4014 char extra[32];
4015 uint8_t len = 0;
4016
4017 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304018 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004019 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004020 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004021 ret = -EFAULT;
4022 }
4023
4024 return ret;
4025}
4026
4027static int drv_cmd_set_scan_home_away_time(hdd_adapter_t *adapter,
4028 hdd_context_t *hdd_ctx,
4029 uint8_t *command,
4030 uint8_t command_len,
4031 hdd_priv_data_t *priv_data)
4032{
4033 int ret = 0;
4034 uint8_t *value = command;
4035 uint16_t homeAwayTime = CFG_ROAM_SCAN_HOME_AWAY_TIME_DEFAULT;
4036
4037 /* input value is in units of msec */
4038
4039 /* Move pointer to ahead of SETSCANHOMEAWAYTIME<delimiter> */
4040 value = value + command_len + 1;
4041
4042 /* Convert the value from ascii to integer */
4043 ret = kstrtou16(value, 10, &homeAwayTime);
4044 if (ret < 0) {
4045 /*
4046 * If the input value is greater than max value of datatype,
4047 * then also kstrtou8 fails
4048 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004049 hdd_err("kstrtou8 failed range [%d - %d]",
4050 CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN,
4051 CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004052 ret = -EINVAL;
4053 goto exit;
4054 }
4055
4056 if ((homeAwayTime < CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN) ||
4057 (homeAwayTime > CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004058 hdd_err("homeAwayTime value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004059 homeAwayTime,
4060 CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN,
4061 CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX);
4062 ret = -EINVAL;
4063 goto exit;
4064 }
4065
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004066 hdd_info("Received Command to Set scan away time = %d",
4067 homeAwayTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004068
4069 if (hdd_ctx->config->nRoamScanHomeAwayTime !=
4070 homeAwayTime) {
4071 hdd_ctx->config->nRoamScanHomeAwayTime = homeAwayTime;
4072 sme_update_roam_scan_home_away_time(hdd_ctx->hHal,
4073 adapter->sessionId,
4074 homeAwayTime,
4075 true);
4076 }
4077
4078exit:
4079 return ret;
4080}
4081
4082static int drv_cmd_get_scan_home_away_time(hdd_adapter_t *adapter,
4083 hdd_context_t *hdd_ctx,
4084 uint8_t *command,
4085 uint8_t command_len,
4086 hdd_priv_data_t *priv_data)
4087{
4088 int ret = 0;
4089 uint16_t val = sme_get_roam_scan_home_away_time(hdd_ctx->hHal);
4090 char extra[32];
4091 uint8_t len = 0;
4092
4093 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304094 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004095
4096 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004097 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004098 ret = -EFAULT;
4099 }
4100
4101 return ret;
4102}
4103
4104static int drv_cmd_reassoc(hdd_adapter_t *adapter,
4105 hdd_context_t *hdd_ctx,
4106 uint8_t *command,
4107 uint8_t command_len,
4108 hdd_priv_data_t *priv_data)
4109{
4110 return hdd_parse_reassoc(adapter, command);
4111}
4112
4113static int drv_cmd_set_wes_mode(hdd_adapter_t *adapter,
4114 hdd_context_t *hdd_ctx,
4115 uint8_t *command,
4116 uint8_t command_len,
4117 hdd_priv_data_t *priv_data)
4118{
4119 int ret = 0;
4120 uint8_t *value = command;
4121 uint8_t wesMode = CFG_ENABLE_WES_MODE_NAME_DEFAULT;
4122
4123 /* Move pointer to ahead of SETWESMODE<delimiter> */
4124 value = value + command_len + 1;
4125
4126 /* Convert the value from ascii to integer */
4127 ret = kstrtou8(value, 10, &wesMode);
4128 if (ret < 0) {
4129 /*
4130 * If the input value is greater than max value of datatype,
4131 * then also kstrtou8 fails
4132 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004133 hdd_err("kstrtou8 failed range [%d - %d]",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004134 CFG_ENABLE_WES_MODE_NAME_MIN,
4135 CFG_ENABLE_WES_MODE_NAME_MAX);
4136 ret = -EINVAL;
4137 goto exit;
4138 }
4139
4140 if ((wesMode < CFG_ENABLE_WES_MODE_NAME_MIN) ||
4141 (wesMode > CFG_ENABLE_WES_MODE_NAME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004142 hdd_err("WES Mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004143 wesMode,
4144 CFG_ENABLE_WES_MODE_NAME_MIN,
4145 CFG_ENABLE_WES_MODE_NAME_MAX);
4146 ret = -EINVAL;
4147 goto exit;
4148 }
4149
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004150 hdd_info("Received Command to Set WES Mode rssi diff = %d",
4151 wesMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004152
4153 hdd_ctx->config->isWESModeEnabled = wesMode;
4154 sme_update_wes_mode(hdd_ctx->hHal, wesMode, adapter->sessionId);
4155
4156exit:
4157 return ret;
4158}
4159
4160static int drv_cmd_get_wes_mode(hdd_adapter_t *adapter,
4161 hdd_context_t *hdd_ctx,
4162 uint8_t *command,
4163 uint8_t command_len,
4164 hdd_priv_data_t *priv_data)
4165{
4166 int ret = 0;
4167 bool wesMode = sme_get_wes_mode(hdd_ctx->hHal);
4168 char extra[32];
4169 uint8_t len = 0;
4170
4171 len = scnprintf(extra, sizeof(extra), "%s %d", command, wesMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304172 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004173 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004174 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004175 ret = -EFAULT;
4176 }
4177
4178 return ret;
4179}
4180
4181static int drv_cmd_set_opportunistic_rssi_diff(hdd_adapter_t *adapter,
4182 hdd_context_t *hdd_ctx,
4183 uint8_t *command,
4184 uint8_t command_len,
4185 hdd_priv_data_t *priv_data)
4186{
4187 int ret = 0;
4188 uint8_t *value = command;
4189 uint8_t nOpportunisticThresholdDiff =
4190 CFG_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF_DEFAULT;
4191
4192 /* Move pointer to ahead of SETOPPORTUNISTICRSSIDIFF<delimiter> */
4193 value = value + command_len + 1;
4194
4195 /* Convert the value from ascii to integer */
4196 ret = kstrtou8(value, 10, &nOpportunisticThresholdDiff);
4197 if (ret < 0) {
4198 /*
4199 * If the input value is greater than max value of datatype,
4200 * then also kstrtou8 fails
4201 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004202 hdd_err("kstrtou8 failed.");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004203 ret = -EINVAL;
4204 goto exit;
4205 }
4206
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004207 hdd_info("Received Command to Set Opportunistic Threshold diff = %d",
4208 nOpportunisticThresholdDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004209
4210 sme_set_roam_opportunistic_scan_threshold_diff(hdd_ctx->hHal,
4211 adapter->sessionId,
4212 nOpportunisticThresholdDiff);
4213
4214exit:
4215 return ret;
4216}
4217
4218static int drv_cmd_get_opportunistic_rssi_diff(hdd_adapter_t *adapter,
4219 hdd_context_t *hdd_ctx,
4220 uint8_t *command,
4221 uint8_t command_len,
4222 hdd_priv_data_t *priv_data)
4223{
4224 int ret = 0;
4225 int8_t val = sme_get_roam_opportunistic_scan_threshold_diff(
4226 hdd_ctx->hHal);
4227 char extra[32];
4228 uint8_t len = 0;
4229
4230 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304231 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004232 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004233 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004234 ret = -EFAULT;
4235 }
4236
4237 return ret;
4238}
4239
4240static int drv_cmd_set_roam_rescan_rssi_diff(hdd_adapter_t *adapter,
4241 hdd_context_t *hdd_ctx,
4242 uint8_t *command,
4243 uint8_t command_len,
4244 hdd_priv_data_t *priv_data)
4245{
4246 int ret = 0;
4247 uint8_t *value = command;
4248 uint8_t nRoamRescanRssiDiff = CFG_ROAM_RESCAN_RSSI_DIFF_DEFAULT;
4249
4250 /* Move pointer to ahead of SETROAMRESCANRSSIDIFF<delimiter> */
4251 value = value + command_len + 1;
4252
4253 /* Convert the value from ascii to integer */
4254 ret = kstrtou8(value, 10, &nRoamRescanRssiDiff);
4255 if (ret < 0) {
4256 /*
4257 * If the input value is greater than max value of datatype,
4258 * then also kstrtou8 fails
4259 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004260 hdd_err("kstrtou8 failed.");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004261 ret = -EINVAL;
4262 goto exit;
4263 }
4264
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004265 hdd_info("Received Command to Set Roam Rescan RSSI Diff = %d",
4266 nRoamRescanRssiDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004267
4268 sme_set_roam_rescan_rssi_diff(hdd_ctx->hHal,
4269 adapter->sessionId,
4270 nRoamRescanRssiDiff);
4271
4272exit:
4273 return ret;
4274}
4275
4276static int drv_cmd_get_roam_rescan_rssi_diff(hdd_adapter_t *adapter,
4277 hdd_context_t *hdd_ctx,
4278 uint8_t *command,
4279 uint8_t command_len,
4280 hdd_priv_data_t *priv_data)
4281{
4282 int ret = 0;
4283 uint8_t val = sme_get_roam_rescan_rssi_diff(hdd_ctx->hHal);
4284 char extra[32];
4285 uint8_t len = 0;
4286
4287 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304288 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004289 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004290 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004291 ret = -EFAULT;
4292 }
4293
4294 return ret;
4295}
4296
4297static int drv_cmd_set_fast_roam(hdd_adapter_t *adapter,
4298 hdd_context_t *hdd_ctx,
4299 uint8_t *command,
4300 uint8_t command_len,
4301 hdd_priv_data_t *priv_data)
4302{
4303 int ret = 0;
4304 uint8_t *value = command;
4305 uint8_t lfrMode = CFG_LFR_FEATURE_ENABLED_DEFAULT;
4306
4307 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4308 value = value + command_len + 1;
4309
4310 /* Convert the value from ascii to integer */
4311 ret = kstrtou8(value, 10, &lfrMode);
4312 if (ret < 0) {
4313 /*
4314 * If the input value is greater than max value of datatype,
4315 * then also kstrtou8 fails
4316 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004317 hdd_err("kstrtou8 failed range [%d - %d]",
4318 CFG_LFR_FEATURE_ENABLED_MIN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004319 CFG_LFR_FEATURE_ENABLED_MAX);
4320 ret = -EINVAL;
4321 goto exit;
4322 }
4323
4324 if ((lfrMode < CFG_LFR_FEATURE_ENABLED_MIN) ||
4325 (lfrMode > CFG_LFR_FEATURE_ENABLED_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004326 hdd_err("lfr mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004327 lfrMode,
4328 CFG_LFR_FEATURE_ENABLED_MIN,
4329 CFG_LFR_FEATURE_ENABLED_MAX);
4330 ret = -EINVAL;
4331 goto exit;
4332 }
4333
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004334 hdd_info("Received Command to change lfr mode = %d",
4335 lfrMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004336
4337 hdd_ctx->config->isFastRoamIniFeatureEnabled = lfrMode;
4338 sme_update_is_fast_roam_ini_feature_enabled(hdd_ctx->hHal,
4339 adapter->
4340 sessionId,
4341 lfrMode);
4342
4343exit:
4344 return ret;
4345}
4346
4347static int drv_cmd_set_fast_transition(hdd_adapter_t *adapter,
4348 hdd_context_t *hdd_ctx,
4349 uint8_t *command,
4350 uint8_t command_len,
4351 hdd_priv_data_t *priv_data)
4352{
4353 int ret = 0;
4354 uint8_t *value = command;
4355 uint8_t ft = CFG_FAST_TRANSITION_ENABLED_NAME_DEFAULT;
4356
4357 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4358 value = value + command_len + 1;
4359
4360 /* Convert the value from ascii to integer */
4361 ret = kstrtou8(value, 10, &ft);
4362 if (ret < 0) {
4363 /*
4364 * If the input value is greater than max value of datatype,
4365 * then also kstrtou8 fails
4366 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004367 hdd_err("kstrtou8 failed range [%d - %d]",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004368 CFG_FAST_TRANSITION_ENABLED_NAME_MIN,
4369 CFG_FAST_TRANSITION_ENABLED_NAME_MAX);
4370 ret = -EINVAL;
4371 goto exit;
4372 }
4373
4374 if ((ft < CFG_FAST_TRANSITION_ENABLED_NAME_MIN) ||
4375 (ft > CFG_FAST_TRANSITION_ENABLED_NAME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004376 hdd_err("ft mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004377 ft,
4378 CFG_FAST_TRANSITION_ENABLED_NAME_MIN,
4379 CFG_FAST_TRANSITION_ENABLED_NAME_MAX);
4380 ret = -EINVAL;
4381 goto exit;
4382 }
4383
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004384 hdd_info("Received Command to change ft mode = %d", ft);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004385
4386 hdd_ctx->config->isFastTransitionEnabled = ft;
4387 sme_update_fast_transition_enabled(hdd_ctx->hHal, ft);
4388
4389exit:
4390 return ret;
4391}
4392
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004393static int drv_cmd_fast_reassoc(hdd_adapter_t *adapter,
4394 hdd_context_t *hdd_ctx,
4395 uint8_t *command,
4396 uint8_t command_len,
4397 hdd_priv_data_t *priv_data)
4398{
4399 int ret = 0;
4400 uint8_t *value = command;
4401 uint8_t channel = 0;
4402 tSirMacAddr targetApBssid;
4403 uint32_t roamId = 0;
4404 tCsrRoamModifyProfileFields modProfileFields;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004405 tCsrHandoffRequest handoffInfo;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004406 hdd_station_ctx_t *pHddStaCtx;
4407
Krunal Sonibe766b02016-03-10 13:00:44 -08004408 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004409 hdd_warn("Unsupported in mode %s(%d)",
4410 hdd_device_mode_to_string(adapter->device_mode),
4411 adapter->device_mode);
4412 return -EINVAL;
4413 }
4414
4415 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
4416
4417 /* if not associated, no need to proceed with reassoc */
4418 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004419 hdd_info("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004420 ret = -EINVAL;
4421 goto exit;
4422 }
4423
4424 ret = hdd_parse_reassoc_command_v1_data(value, targetApBssid,
4425 &channel);
4426 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004427 hdd_err("Failed to parse reassoc command data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004428 goto exit;
4429 }
4430
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304431 /* Check channel number is a valid channel number */
4432 if (QDF_STATUS_SUCCESS !=
4433 wlan_hdd_validate_operation_channel(adapter, channel)) {
4434 hdd_err("Invalid Channel [%d]", channel);
4435 return -EINVAL;
4436 }
4437
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004438 /*
4439 * if the target bssid is same as currently associated AP,
4440 * issue reassoc to same AP
4441 */
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304442 if (true != qdf_mem_cmp(targetApBssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004443 pHddStaCtx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05304444 QDF_MAC_ADDR_SIZE)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004445 hdd_info("Reassoc BSSID is same as currently associated AP bssid");
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304446 if (roaming_offload_enabled(hdd_ctx)) {
4447 hdd_wma_send_fastreassoc_cmd((int)adapter->sessionId,
4448 targetApBssid, (int)channel);
4449 } else {
4450 sme_get_modify_profile_fields(hdd_ctx->hHal,
4451 adapter->sessionId,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004452 &modProfileFields);
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304453 sme_roam_reassoc(hdd_ctx->hHal, adapter->sessionId,
4454 NULL, modProfileFields, &roamId, 1);
4455 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004456 return 0;
4457 }
4458
Varun Reddy Yeturud351a6c2016-03-16 14:01:00 -07004459 if (roaming_offload_enabled(hdd_ctx)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004460 hdd_wma_send_fastreassoc_cmd((int)adapter->sessionId,
4461 targetApBssid, (int)channel);
4462 goto exit;
4463 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004464 /* Proceed with reassoc */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004465 handoffInfo.channel = channel;
4466 handoffInfo.src = FASTREASSOC;
Varun Reddy Yeturua66f9c52016-02-17 09:58:40 -08004467 qdf_mem_copy(handoffInfo.bssid.bytes, targetApBssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004468 sizeof(tSirMacAddr));
4469 sme_handoff_request(hdd_ctx->hHal, adapter->sessionId,
4470 &handoffInfo);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004471exit:
4472 return ret;
4473}
4474
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004475static int drv_cmd_set_roam_scan_control(hdd_adapter_t *adapter,
4476 hdd_context_t *hdd_ctx,
4477 uint8_t *command,
4478 uint8_t command_len,
4479 hdd_priv_data_t *priv_data)
4480{
4481 int ret = 0;
4482 uint8_t *value = command;
4483 uint8_t roamScanControl = 0;
4484
4485 /* Move pointer to ahead of SETROAMSCANCONTROL<delimiter> */
4486 value = value + command_len + 1;
4487
4488 /* Convert the value from ascii to integer */
4489 ret = kstrtou8(value, 10, &roamScanControl);
4490 if (ret < 0) {
4491 /*
4492 * If the input value is greater than max value of datatype,
4493 * then also kstrtou8 fails
4494 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004495 hdd_err("kstrtou8 failed ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004496 ret = -EINVAL;
4497 goto exit;
4498 }
4499
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004500 hdd_info("Received Command to Set roam scan control = %d",
4501 roamScanControl);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004502
4503 if (0 != roamScanControl) {
4504 ret = 0; /* return success but ignore param value "true" */
4505 goto exit;
4506 }
4507
4508 sme_set_roam_scan_control(hdd_ctx->hHal,
4509 adapter->sessionId,
4510 roamScanControl);
4511
4512exit:
4513 return ret;
4514}
4515
4516static int drv_cmd_set_okc_mode(hdd_adapter_t *adapter,
4517 hdd_context_t *hdd_ctx,
4518 uint8_t *command,
4519 uint8_t command_len,
4520 hdd_priv_data_t *priv_data)
4521{
4522 int ret = 0;
4523 uint8_t *value = command;
4524 uint8_t okcMode = CFG_OKC_FEATURE_ENABLED_DEFAULT;
4525
4526 /*
4527 * Check if the features OKC/ESE/11R are supported simultaneously,
4528 * then this operation is not permitted (return FAILURE)
4529 */
4530 if (sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
4531 hdd_is_okc_mode_enabled(hdd_ctx) &&
4532 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004533 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004534 ret = -EPERM;
4535 goto exit;
4536 }
4537
4538 /* Move pointer to ahead of SETOKCMODE<delimiter> */
4539 value = value + command_len + 1;
4540
4541 /* Convert the value from ascii to integer */
4542 ret = kstrtou8(value, 10, &okcMode);
4543 if (ret < 0) {
4544 /*
4545 * If the input value is greater than max value of datatype,
4546 * then also kstrtou8 fails
4547 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004548 hdd_err("kstrtou8 failed range [%d - %d]",
4549 CFG_OKC_FEATURE_ENABLED_MIN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004550 CFG_OKC_FEATURE_ENABLED_MAX);
4551 ret = -EINVAL;
4552 goto exit;
4553 }
4554
4555 if ((okcMode < CFG_OKC_FEATURE_ENABLED_MIN) ||
4556 (okcMode > CFG_OKC_FEATURE_ENABLED_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004557 hdd_err("Okc mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004558 okcMode,
4559 CFG_OKC_FEATURE_ENABLED_MIN,
4560 CFG_OKC_FEATURE_ENABLED_MAX);
4561 ret = -EINVAL;
4562 goto exit;
4563 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004564 hdd_info("Received Command to change okc mode = %d",
4565 okcMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004566
4567 hdd_ctx->config->isOkcIniFeatureEnabled = okcMode;
4568
4569exit:
4570 return ret;
4571}
4572
4573static int drv_cmd_get_roam_scan_control(hdd_adapter_t *adapter,
4574 hdd_context_t *hdd_ctx,
4575 uint8_t *command,
4576 uint8_t command_len,
4577 hdd_priv_data_t *priv_data)
4578{
4579 int ret = 0;
4580 bool roamScanControl = sme_get_roam_scan_control(hdd_ctx->hHal);
4581 char extra[32];
4582 uint8_t len = 0;
4583
4584 len = scnprintf(extra, sizeof(extra), "%s %d",
4585 command, roamScanControl);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304586 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004587 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004588 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004589 ret = -EFAULT;
4590 }
4591
4592 return ret;
4593}
4594
4595static int drv_cmd_bt_coex_mode(hdd_adapter_t *adapter,
4596 hdd_context_t *hdd_ctx,
4597 uint8_t *command,
4598 uint8_t command_len,
4599 hdd_priv_data_t *priv_data)
4600{
4601 int ret = 0;
4602 char *bcMode;
4603
4604 bcMode = command + 11;
4605 if ('1' == *bcMode) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004606 hdd_debug("BTCOEXMODE %d", *bcMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004607 hdd_ctx->btCoexModeSet = true;
4608 ret = wlan_hdd_scan_abort(adapter);
4609 if (ret < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004610 hdd_err("Failed to abort existing scan status: %d",
4611 ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004612 }
4613 } else if ('2' == *bcMode) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004614 hdd_debug("BTCOEXMODE %d", *bcMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004615 hdd_ctx->btCoexModeSet = false;
4616 }
4617
4618 return ret;
4619}
4620
4621static int drv_cmd_scan_active(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 hdd_ctx->ioctl_scan_mode = eSIR_ACTIVE_SCAN;
4628 return 0;
4629}
4630
4631static int drv_cmd_scan_passive(hdd_adapter_t *adapter,
4632 hdd_context_t *hdd_ctx,
4633 uint8_t *command,
4634 uint8_t command_len,
4635 hdd_priv_data_t *priv_data)
4636{
4637 hdd_ctx->ioctl_scan_mode = eSIR_PASSIVE_SCAN;
4638 return 0;
4639}
4640
4641static int drv_cmd_get_dwell_time(hdd_adapter_t *adapter,
4642 hdd_context_t *hdd_ctx,
4643 uint8_t *command,
4644 uint8_t command_len,
4645 hdd_priv_data_t *priv_data)
4646{
4647 int ret = 0;
4648 struct hdd_config *pCfg =
4649 (WLAN_HDD_GET_CTX(adapter))->config;
4650 char extra[32];
4651 uint8_t len = 0;
4652
4653 memset(extra, 0, sizeof(extra));
4654 ret = hdd_get_dwell_time(pCfg, command, extra, sizeof(extra), &len);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304655 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004656 if (ret != 0 || copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004657 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004658 ret = -EFAULT;
4659 goto exit;
4660 }
4661 ret = len;
4662exit:
4663 return ret;
4664}
4665
4666static int drv_cmd_set_dwell_time(hdd_adapter_t *adapter,
4667 hdd_context_t *hdd_ctx,
4668 uint8_t *command,
4669 uint8_t command_len,
4670 hdd_priv_data_t *priv_data)
4671{
4672 return hdd_set_dwell_time(adapter, command);
4673}
4674
4675static int drv_cmd_miracast(hdd_adapter_t *adapter,
4676 hdd_context_t *hdd_ctx,
4677 uint8_t *command,
4678 uint8_t command_len,
4679 hdd_priv_data_t *priv_data)
4680{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304681 QDF_STATUS ret_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004682 int ret = 0;
4683 tHalHandle hHal;
4684 uint8_t filterType = 0;
4685 hdd_context_t *pHddCtx = NULL;
4686 uint8_t *value;
4687
4688 pHddCtx = WLAN_HDD_GET_CTX(adapter);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05304689 if (wlan_hdd_validate_context(pHddCtx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004690 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004691
4692 hHal = pHddCtx->hHal;
4693 value = command + 9;
4694
4695 /* Convert the value from ascii to integer */
4696 ret = kstrtou8(value, 10, &filterType);
4697 if (ret < 0) {
4698 /*
4699 * If the input value is greater than max value of datatype,
4700 * then also kstrtou8 fails
4701 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004702 hdd_err("kstrtou8 failed range ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004703 ret = -EINVAL;
4704 goto exit;
4705 }
4706 if ((filterType < WLAN_HDD_DRIVER_MIRACAST_CFG_MIN_VAL)
4707 || (filterType >
4708 WLAN_HDD_DRIVER_MIRACAST_CFG_MAX_VAL)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004709 hdd_err("Accepted Values are 0 to 2. 0-Disabled, 1-Source, 2-Sink ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004710 ret = -EINVAL;
4711 goto exit;
4712 }
4713 /* Filtertype value should be either 0-Disabled, 1-Source, 2-sink */
4714 pHddCtx->miracast_value = filterType;
4715
4716 ret_status = sme_set_miracast(hHal, filterType);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304717 if (QDF_STATUS_SUCCESS != ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004718 hdd_err("Failed to set miracast");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004719 return -EBUSY;
4720 }
4721
Tushnim Bhattacharyyaca50b322015-12-28 17:14:36 -08004722 if (cds_is_mcc_in_24G())
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004723 return cds_set_mas(adapter, filterType);
4724
4725exit:
4726 return ret;
4727}
4728
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004729/* Function header is left blank intentionally */
4730static int hdd_parse_set_ibss_oui_data_command(uint8_t *command, uint8_t *ie,
4731 int32_t *oui_length, int32_t limit)
4732{
4733 uint8_t len;
4734 uint8_t data;
4735
4736 while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) {
4737 command++;
4738 limit--;
4739 }
4740
4741 len = 2;
4742
4743 while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) &&
4744 (limit > 1)) {
4745 sscanf(command, "%02x", (unsigned int *)&data);
4746 ie[len++] = data;
4747 command += 2;
4748 limit -= 2;
4749 }
4750
4751 *oui_length = len - 2;
4752
4753 while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) {
4754 command++;
4755 limit--;
4756 }
4757
4758 while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) &&
4759 (limit > 1)) {
4760 sscanf(command, "%02x", (unsigned int *)&data);
4761 ie[len++] = data;
4762 command += 2;
4763 limit -= 2;
4764 }
4765
4766 ie[0] = IE_EID_VENDOR;
4767 ie[1] = len - 2;
4768
4769 return len;
4770}
4771
4772/**
4773 * drv_cmd_set_ibss_beacon_oui_data() - set ibss oui data command
4774 * @adapter: Pointer to adapter
4775 * @hdd_ctx: Pointer to HDD context
4776 * @command: Pointer to command string
4777 * @command_len : Command length
4778 * @priv_data : Pointer to priv data
4779 *
4780 * Return:
4781 * int status code
4782 */
4783static int drv_cmd_set_ibss_beacon_oui_data(hdd_adapter_t *adapter,
4784 hdd_context_t *hdd_ctx,
4785 uint8_t *command,
4786 uint8_t command_len,
4787 hdd_priv_data_t *priv_data)
4788{
4789 int i = 0;
4790 int status;
4791 int ret = 0;
4792 uint8_t *ibss_ie;
4793 int32_t oui_length = 0;
4794 uint32_t ibss_ie_length;
4795 uint8_t *value = command;
4796 tSirModifyIE ibssModifyIE;
4797 tCsrRoamProfile *pRoamProfile;
4798 hdd_wext_state_t *pWextState;
4799
4800
Krunal Sonibe766b02016-03-10 13:00:44 -08004801 if (QDF_IBSS_MODE != adapter->device_mode) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004802 hdd_info("Device_mode %s(%d) not IBSS",
4803 hdd_device_mode_to_string(adapter->device_mode),
4804 adapter->device_mode);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004805 return ret;
4806 }
4807
4808 pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(adapter);
4809
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004810 hdd_info("received command %s", ((char *)value));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004811
4812
4813 /* validate argument of command */
4814 if (strlen(value) <= command_len) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004815 hdd_err("No arguments in command length %zu",
4816 strlen(value));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004817 ret = -EFAULT;
4818 goto exit;
4819 }
4820
4821 /* moving to arguments of commands */
4822 value = value + command_len;
4823 command_len = strlen(value);
4824
4825 /* oui_data can't be less than 3 bytes */
4826 if (command_len < (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004827 hdd_err("Invalid SETIBSSBEACONOUIDATA command length %d",
4828 command_len);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004829 ret = -EFAULT;
4830 goto exit;
4831 }
4832
4833 ibss_ie = qdf_mem_malloc(command_len);
4834 if (!ibss_ie) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004835 hdd_err("Could not allocate memory for command length %d",
4836 command_len);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004837 ret = -ENOMEM;
4838 goto exit;
4839 }
4840 qdf_mem_zero(ibss_ie, command_len);
4841
4842 ibss_ie_length = hdd_parse_set_ibss_oui_data_command(value, ibss_ie,
4843 &oui_length,
4844 command_len);
4845 if (ibss_ie_length <= (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004846 hdd_err("Could not parse command %s return length %d",
4847 value, ibss_ie_length);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004848 ret = -EFAULT;
4849 qdf_mem_free(ibss_ie);
4850 goto exit;
4851 }
4852
4853 pRoamProfile = &pWextState->roamProfile;
4854
4855 qdf_copy_macaddr(&ibssModifyIE.bssid,
4856 pRoamProfile->BSSIDs.bssid);
4857
4858 ibssModifyIE.smeSessionId = adapter->sessionId;
4859 ibssModifyIE.notify = true;
4860 ibssModifyIE.ieID = IE_EID_VENDOR;
4861 ibssModifyIE.ieIDLen = ibss_ie_length;
4862 ibssModifyIE.ieBufferlength = ibss_ie_length;
4863 ibssModifyIE.pIEBuffer = ibss_ie;
4864 ibssModifyIE.oui_length = oui_length;
4865
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004866 hdd_warn("ibss_ie length %d oui_length %d ibss_ie:",
4867 ibss_ie_length, oui_length);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004868 while (i < ibssModifyIE.ieBufferlength)
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004869 hdd_warn("0x%x", ibss_ie[i++]);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004870
4871 /* Probe Bcn modification */
4872 sme_modify_add_ie(WLAN_HDD_GET_HAL_CTX(adapter),
4873 &ibssModifyIE, eUPDATE_IE_PROBE_BCN);
4874
4875 /* Populating probe resp frame */
4876 sme_modify_add_ie(WLAN_HDD_GET_HAL_CTX(adapter),
4877 &ibssModifyIE, eUPDATE_IE_PROBE_RESP);
4878
4879 qdf_mem_free(ibss_ie);
4880
4881 status = sme_send_cesium_enable_ind((tHalHandle)(hdd_ctx->hHal),
4882 adapter->sessionId);
4883 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004884 hdd_err("Could not send cesium enable indication %d",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004885 status);
4886 ret = -EINVAL;
4887 goto exit;
4888 }
4889
4890exit:
4891 return ret;
4892}
4893
4894static int drv_cmd_set_rmc_enable(hdd_adapter_t *adapter,
4895 hdd_context_t *hdd_ctx,
4896 uint8_t *command,
4897 uint8_t command_len,
4898 hdd_priv_data_t *priv_data)
4899{
4900 int ret = 0;
4901 uint8_t *value = command;
4902 uint8_t ucRmcEnable = 0;
4903 int status;
4904
Krunal Sonibe766b02016-03-10 13:00:44 -08004905 if ((QDF_IBSS_MODE != adapter->device_mode) &&
4906 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004907 hdd_err("Received SETRMCENABLE cmd in invalid mode %s(%d)",
4908 hdd_device_mode_to_string(adapter->device_mode),
4909 adapter->device_mode);
4910 hdd_err("SETRMCENABLE cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004911 ret = -EINVAL;
4912 goto exit;
4913 }
4914
4915 status = hdd_parse_setrmcenable_command(value, &ucRmcEnable);
4916 if (status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004917 hdd_err("Invalid SETRMCENABLE command ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004918 ret = -EINVAL;
4919 goto exit;
4920 }
4921
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004922 hdd_info("ucRmcEnable %d ", ucRmcEnable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004923
4924 if (true == ucRmcEnable) {
4925 status = sme_enable_rmc((tHalHandle)
4926 (hdd_ctx->hHal),
4927 adapter->sessionId);
4928 } else if (false == ucRmcEnable) {
4929 status = sme_disable_rmc((tHalHandle)
4930 (hdd_ctx->hHal),
4931 adapter->sessionId);
4932 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004933 hdd_err("Invalid SETRMCENABLE command %d",
4934 ucRmcEnable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004935 ret = -EINVAL;
4936 goto exit;
4937 }
4938
4939 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004940 hdd_err("SETRMC %d failed status %d",
4941 ucRmcEnable, status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004942 ret = -EINVAL;
4943 goto exit;
4944 }
4945
4946exit:
4947 return ret;
4948}
4949
4950static int drv_cmd_set_rmc_action_period(hdd_adapter_t *adapter,
4951 hdd_context_t *hdd_ctx,
4952 uint8_t *command,
4953 uint8_t command_len,
4954 hdd_priv_data_t *priv_data)
4955{
4956 int ret = 0;
4957 uint8_t *value = command;
4958 uint32_t uActionPeriod = 0;
4959 int status;
4960
Krunal Sonibe766b02016-03-10 13:00:44 -08004961 if ((QDF_IBSS_MODE != adapter->device_mode) &&
4962 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004963 hdd_err("Received SETRMC cmd in invalid mode %s(%d)",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004964 hdd_device_mode_to_string(adapter->device_mode),
4965 adapter->device_mode);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004966 hdd_err("SETRMC cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004967 ret = -EINVAL;
4968 goto exit;
4969 }
4970
4971 status = hdd_parse_setrmcactionperiod_command(value, &uActionPeriod);
4972 if (status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004973 hdd_err("Invalid SETRMCACTIONPERIOD command ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004974 ret = -EINVAL;
4975 goto exit;
4976 }
4977
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004978 hdd_info("uActionPeriod %d ",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004979 uActionPeriod);
4980
4981 if (sme_cfg_set_int(hdd_ctx->hHal,
4982 WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY,
4983 uActionPeriod)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004984 hdd_err("Could not set SETRMCACTIONPERIOD %d",
4985 uActionPeriod);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004986 ret = -EINVAL;
4987 goto exit;
4988 }
4989
4990 status = sme_send_rmc_action_period((tHalHandle)(hdd_ctx->hHal),
4991 adapter->sessionId);
4992 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004993 hdd_err("Could not send cesium enable indication %d",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004994 status);
4995 ret = -EINVAL;
4996 goto exit;
4997 }
4998
4999exit:
5000 return ret;
5001}
5002
5003static int drv_cmd_get_ibss_peer_info_all(hdd_adapter_t *adapter,
5004 hdd_context_t *hdd_ctx,
5005 uint8_t *command,
5006 uint8_t command_len,
5007 hdd_priv_data_t *priv_data)
5008{
5009 int ret = 0;
5010 int status = QDF_STATUS_SUCCESS;
5011 hdd_station_ctx_t *pHddStaCtx = NULL;
5012 char *extra = NULL;
5013 int idx = 0;
5014 int length = 0;
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005015 uint8_t mac_addr[QDF_MAC_ADDR_SIZE];
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005016 uint32_t numOfBytestoPrint = 0;
5017
Krunal Sonibe766b02016-03-10 13:00:44 -08005018 if (QDF_IBSS_MODE != adapter->device_mode) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005019 hdd_warn("Unsupported in mode %s(%d)",
5020 hdd_device_mode_to_string(adapter->device_mode),
5021 adapter->device_mode);
5022 return -EINVAL;
5023 }
5024
5025 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005026 hdd_info("Received GETIBSSPEERINFOALL Command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005027
5028 /* Handle the command */
5029 status = hdd_cfg80211_get_ibss_peer_info_all(adapter);
5030 if (QDF_STATUS_SUCCESS == status) {
5031 /*
5032 * The variable extra needed to be allocated on the heap since
5033 * amount of memory required to copy the data for 32 devices
5034 * exceeds the size of 1024 bytes of default stack size. On
5035 * 64 bit devices, the default max stack size of 2048 bytes
5036 */
5037 extra = kmalloc(WLAN_MAX_BUF_SIZE, GFP_KERNEL);
5038
5039 if (NULL == extra) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005040 hdd_err("kmalloc failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005041 ret = -EINVAL;
5042 goto exit;
5043 }
5044
5045 /* Copy number of stations */
5046 length = scnprintf(extra, WLAN_MAX_BUF_SIZE, "%d ",
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005047 pHddStaCtx->ibss_peer_info.numPeers);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005048 numOfBytestoPrint = length;
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005049 for (idx = 0; idx < pHddStaCtx->ibss_peer_info.numPeers;
5050 idx++) {
5051 int8_t rssi;
5052 uint32_t tx_rate;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005053
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005054 qdf_mem_copy(mac_addr,
5055 pHddStaCtx->ibss_peer_info.peerInfoParams[idx].
5056 mac_addr, sizeof(mac_addr));
5057
5058 tx_rate =
5059 pHddStaCtx->ibss_peer_info.peerInfoParams[idx].
5060 txRate;
5061 rssi = pHddStaCtx->ibss_peer_info.peerInfoParams[idx].
5062 rssi;
5063
5064 length += scnprintf((extra + length),
5065 WLAN_MAX_BUF_SIZE - length,
5066 "%02x:%02x:%02x:%02x:%02x:%02x %d %d ",
5067 mac_addr[0], mac_addr[1], mac_addr[2],
5068 mac_addr[3], mac_addr[4], mac_addr[5],
5069 tx_rate, rssi);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005070 /*
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005071 * cdf_trace_msg has limitation of 512 bytes for the
5072 * print buffer. Hence printing the data in two chunks.
5073 * The first chunk will have the data for 16 devices
5074 * and the second chunk will have the rest.
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005075 */
5076 if (idx < NUM_OF_STA_DATA_TO_PRINT)
5077 numOfBytestoPrint = length;
5078 }
5079
5080 /*
5081 * Copy the data back into buffer, if the data to copy is
5082 * more than 512 bytes than we will split the data and do
5083 * it in two shots
5084 */
5085 if (copy_to_user(priv_data->buf, extra, numOfBytestoPrint)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005086 hdd_err("Copy into user data buffer failed ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005087 ret = -EFAULT;
5088 goto exit;
5089 }
5090
5091 priv_data->buf[numOfBytestoPrint] = '\0';
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005092 hdd_debug("%s", priv_data->buf);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005093
5094 if (length > numOfBytestoPrint) {
5095 if (copy_to_user
5096 (priv_data->buf + numOfBytestoPrint,
5097 extra + numOfBytestoPrint,
5098 length - numOfBytestoPrint + 1)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005099 hdd_err("Copy into user data buffer failed ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005100 ret = -EFAULT;
5101 goto exit;
5102 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005103 hdd_debug("%s", &priv_data->buf[numOfBytestoPrint]);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005104 }
5105
5106 /* Free temporary buffer */
5107 kfree(extra);
5108 } else {
5109 /* Command failed, log error */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005110 hdd_err("GETIBSSPEERINFOALL command failed with status code %d",
5111 status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005112 ret = -EINVAL;
5113 goto exit;
5114 }
5115 ret = 0;
5116
5117exit:
5118 return ret;
5119}
5120
5121/* Peer Info <Peer Addr> command */
5122static int drv_cmd_get_ibss_peer_info(hdd_adapter_t *adapter,
5123 hdd_context_t *hdd_ctx,
5124 uint8_t *command,
5125 uint8_t command_len,
5126 hdd_priv_data_t *priv_data)
5127{
5128 int ret = 0;
5129 uint8_t *value = command;
5130 QDF_STATUS status;
5131 hdd_station_ctx_t *pHddStaCtx = NULL;
5132 char extra[128] = { 0 };
5133 uint32_t length = 0;
5134 uint8_t staIdx = 0;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005135 struct qdf_mac_addr peerMacAddr;
5136
Krunal Sonibe766b02016-03-10 13:00:44 -08005137 if (QDF_IBSS_MODE != adapter->device_mode) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005138 hdd_warn("Unsupported in mode %s(%d)",
5139 hdd_device_mode_to_string(adapter->device_mode),
5140 adapter->device_mode);
5141 return -EINVAL;
5142 }
5143
5144 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5145
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005146 hdd_info("Received GETIBSSPEERINFO Command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005147
5148 /* if there are no peers, no need to continue with the command */
5149 if (eConnectionState_IbssConnected !=
5150 pHddStaCtx->conn_info.connState) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005151 hdd_info("No IBSS Peers coalesced");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005152 ret = -EINVAL;
5153 goto exit;
5154 }
5155
5156 /* Parse the incoming command buffer */
5157 status = hdd_parse_get_ibss_peer_info(value, &peerMacAddr);
5158 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005159 hdd_err("Invalid GETIBSSPEERINFO command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005160 ret = -EINVAL;
5161 goto exit;
5162 }
5163
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005164 /* Get station index for the peer mac address and sanitize it */
Deepak Dhamdhere5872c8c2016-06-02 15:51:47 -07005165 hdd_get_peer_sta_id(pHddStaCtx, &peerMacAddr, &staIdx);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005166
Naveen Rawatc45d1622016-07-05 12:20:09 -07005167 if (staIdx > MAX_PEERS) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005168 hdd_err("Invalid StaIdx %d returned", staIdx);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005169 ret = -EINVAL;
5170 goto exit;
5171 }
5172
5173 /* Handle the command */
5174 status = hdd_cfg80211_get_ibss_peer_info(adapter, staIdx);
5175 if (QDF_STATUS_SUCCESS == status) {
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005176 uint32_t txRate =
5177 pHddStaCtx->ibss_peer_info.peerInfoParams[0].txRate;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005178
5179 length = scnprintf(extra, sizeof(extra), "%d %d",
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005180 (int)txRate,
5181 (int)pHddStaCtx->ibss_peer_info.
5182 peerInfoParams[0].rssi);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005183
5184 /* Copy the data back into buffer */
5185 if (copy_to_user(priv_data->buf, &extra, length + 1)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005186 hdd_err("copy data to user buffer failed GETIBSSPEERINFO command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005187 ret = -EFAULT;
5188 goto exit;
5189 }
5190 } else {
5191 /* Command failed, log error */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005192 hdd_err("GETIBSSPEERINFO command failed with status code %d",
5193 status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005194 ret = -EINVAL;
5195 goto exit;
5196 }
5197
5198 /* Success ! */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005199 hdd_debug("%s", priv_data->buf);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005200 ret = 0;
5201
5202exit:
5203 return ret;
5204}
5205
5206static int drv_cmd_set_rmc_tx_rate(hdd_adapter_t *adapter,
5207 hdd_context_t *hdd_ctx,
5208 uint8_t *command,
5209 uint8_t command_len,
5210 hdd_priv_data_t *priv_data)
5211{
5212 int ret = 0;
5213 uint8_t *value = command;
5214 uint32_t uRate = 0;
5215 tTxrateinfoflags txFlags = 0;
5216 tSirRateUpdateInd rateUpdateParams = {0};
5217 int status;
5218 struct hdd_config *pConfig = hdd_ctx->config;
5219
Krunal Sonibe766b02016-03-10 13:00:44 -08005220 if ((QDF_IBSS_MODE != adapter->device_mode) &&
5221 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005222 hdd_err("Received SETRMCTXRATE cmd in invalid mode %s(%d)",
5223 hdd_device_mode_to_string(adapter->device_mode),
5224 adapter->device_mode);
5225 hdd_err("SETRMCTXRATE cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005226 ret = -EINVAL;
5227 goto exit;
5228 }
5229
5230 status = hdd_parse_setrmcrate_command(value, &uRate, &txFlags);
5231 if (status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005232 hdd_err("Invalid SETRMCTXRATE command ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005233 ret = -EINVAL;
5234 goto exit;
5235 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005236 hdd_info("uRate %d ", uRate);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005237 /* -1 implies ignore this param */
5238 rateUpdateParams.ucastDataRate = -1;
5239
5240 /*
5241 * Fill the user specifieed RMC rate param
5242 * and the derived tx flags.
5243 */
5244 rateUpdateParams.nss = (pConfig->enable2x2 == 0) ? 0 : 1;
5245 rateUpdateParams.reliableMcastDataRate = uRate;
5246 rateUpdateParams.reliableMcastDataRateTxFlag = txFlags;
5247 rateUpdateParams.dev_mode = adapter->device_mode;
5248 rateUpdateParams.bcastDataRate = -1;
5249 memcpy(rateUpdateParams.bssid.bytes,
5250 adapter->macAddressCurrent.bytes,
5251 sizeof(rateUpdateParams.bssid));
5252 status = sme_send_rate_update_ind((tHalHandle) (hdd_ctx->hHal),
5253 &rateUpdateParams);
5254
5255exit:
5256 return ret;
5257}
5258
5259static int drv_cmd_set_ibss_tx_fail_event(hdd_adapter_t *adapter,
5260 hdd_context_t *hdd_ctx,
5261 uint8_t *command,
5262 uint8_t command_len,
5263 hdd_priv_data_t *priv_data)
5264{
5265 int ret = 0;
5266 char *value;
5267 uint8_t tx_fail_count = 0;
5268 uint16_t pid = 0;
5269
5270 value = command;
5271
5272 ret = hdd_parse_ibsstx_fail_event_params(value, &tx_fail_count, &pid);
5273
5274 if (0 != ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005275 hdd_info("Failed to parse SETIBSSTXFAILEVENT arguments");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005276 goto exit;
5277 }
5278
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005279 hdd_info("tx_fail_cnt=%hhu, pid=%hu", tx_fail_count, pid);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005280
5281 if (0 == tx_fail_count) {
5282 /* Disable TX Fail Indication */
5283 if (QDF_STATUS_SUCCESS ==
5284 sme_tx_fail_monitor_start_stop_ind(hdd_ctx->hHal,
5285 tx_fail_count,
5286 NULL)) {
5287 cesium_pid = 0;
5288 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005289 hdd_err("failed to disable TX Fail Event ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005290 ret = -EINVAL;
5291 }
5292 } else {
5293 if (QDF_STATUS_SUCCESS ==
5294 sme_tx_fail_monitor_start_stop_ind(hdd_ctx->hHal,
5295 tx_fail_count,
5296 (void *)hdd_tx_fail_ind_callback)) {
5297 cesium_pid = pid;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005298 hdd_info("Registered Cesium pid %u",
5299 cesium_pid);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005300 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005301 hdd_err("Failed to enable TX Fail Monitoring");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005302 ret = -EINVAL;
5303 }
5304 }
5305
5306exit:
5307 return ret;
5308}
5309
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08005310#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005311static int drv_cmd_set_ccx_roam_scan_channels(hdd_adapter_t *adapter,
5312 hdd_context_t *hdd_ctx,
5313 uint8_t *command,
5314 uint8_t command_len,
5315 hdd_priv_data_t *priv_data)
5316{
5317 int ret = 0;
5318 uint8_t *value = command;
5319 uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
5320 uint8_t numChannels = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305321 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005322
5323 ret = hdd_parse_channellist(value, ChannelList, &numChannels);
5324 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005325 hdd_err("Failed to parse channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005326 goto exit;
5327 }
5328 if (numChannels > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005329 hdd_err("number of channels (%d) supported exceeded max (%d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005330 numChannels,
5331 WNI_CFG_VALID_CHANNEL_LIST_LEN);
5332 ret = -EINVAL;
5333 goto exit;
5334 }
5335 status = sme_set_ese_roam_scan_channel_list(hdd_ctx->hHal,
5336 adapter->sessionId,
5337 ChannelList,
5338 numChannels);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305339 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005340 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005341 ret = -EINVAL;
5342 goto exit;
5343 }
5344
5345exit:
5346 return ret;
5347}
5348
5349static int drv_cmd_get_tsm_stats(hdd_adapter_t *adapter,
5350 hdd_context_t *hdd_ctx,
5351 uint8_t *command,
5352 uint8_t command_len,
5353 hdd_priv_data_t *priv_data)
5354{
5355 int ret = 0;
5356 uint8_t *value = command;
5357 char extra[128] = { 0 };
5358 int len = 0;
5359 uint8_t tid = 0;
5360 hdd_station_ctx_t *pHddStaCtx;
5361 tAniTrafStrmMetrics tsm_metrics;
5362
Krunal Sonibe766b02016-03-10 13:00:44 -08005363 if ((QDF_STA_MODE != adapter->device_mode) &&
5364 (QDF_P2P_CLIENT_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005365 hdd_warn("Unsupported in mode %s(%d)",
5366 hdd_device_mode_to_string(adapter->device_mode),
5367 adapter->device_mode);
5368 return -EINVAL;
5369 }
5370
5371 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5372
5373 /* if not associated, return error */
5374 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005375 hdd_err("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005376 ret = -EINVAL;
5377 goto exit;
5378 }
5379
5380 /* Move pointer to ahead of GETTSMSTATS<delimiter> */
5381 value = value + command_len + 1;
5382
5383 /* Convert the value from ascii to integer */
5384 ret = kstrtou8(value, 10, &tid);
5385 if (ret < 0) {
5386 /*
5387 * If the input value is greater than max value of datatype,
5388 * then also kstrtou8 fails
5389 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005390 hdd_err("kstrtou8 failed range [%d - %d]",
5391 TID_MIN_VALUE,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005392 TID_MAX_VALUE);
5393 ret = -EINVAL;
5394 goto exit;
5395 }
5396 if ((tid < TID_MIN_VALUE) || (tid > TID_MAX_VALUE)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005397 hdd_err("tid value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005398 tid, TID_MIN_VALUE, TID_MAX_VALUE);
5399 ret = -EINVAL;
5400 goto exit;
5401 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005402 hdd_info("Received Command to get tsm stats tid = %d",
5403 tid);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305404 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005405 hdd_get_tsm_stats(adapter, tid, &tsm_metrics)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005406 hdd_err("failed to get tsm stats");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005407 ret = -EFAULT;
5408 goto exit;
5409 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005410 hdd_info(
5411 "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 -08005412 tsm_metrics.UplinkPktQueueDly,
5413 tsm_metrics.UplinkPktQueueDlyHist[0],
5414 tsm_metrics.UplinkPktQueueDlyHist[1],
5415 tsm_metrics.UplinkPktQueueDlyHist[2],
5416 tsm_metrics.UplinkPktQueueDlyHist[3],
5417 tsm_metrics.UplinkPktTxDly,
5418 tsm_metrics.UplinkPktLoss,
5419 tsm_metrics.UplinkPktCount,
5420 tsm_metrics.RoamingCount,
5421 tsm_metrics.RoamingDly);
5422 /*
5423 * Output TSM stats is of the format
5424 * GETTSMSTATS [PktQueueDly]
5425 * [PktQueueDlyHist[0]]:[PktQueueDlyHist[1]] ...[RoamingDly]
5426 * eg., GETTSMSTATS 10 1:0:0:161 20 1 17 8 39800
5427 */
5428 len = scnprintf(extra,
5429 sizeof(extra),
5430 "%s %d %d:%d:%d:%d %u %d %d %d %d",
5431 command,
5432 tsm_metrics.UplinkPktQueueDly,
5433 tsm_metrics.UplinkPktQueueDlyHist[0],
5434 tsm_metrics.UplinkPktQueueDlyHist[1],
5435 tsm_metrics.UplinkPktQueueDlyHist[2],
5436 tsm_metrics.UplinkPktQueueDlyHist[3],
5437 tsm_metrics.UplinkPktTxDly,
5438 tsm_metrics.UplinkPktLoss,
5439 tsm_metrics.UplinkPktCount,
5440 tsm_metrics.RoamingCount,
5441 tsm_metrics.RoamingDly);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305442 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005443 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005444 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005445 ret = -EFAULT;
5446 goto exit;
5447 }
5448
5449exit:
5450 return ret;
5451}
5452
5453static int drv_cmd_set_cckm_ie(hdd_adapter_t *adapter,
5454 hdd_context_t *hdd_ctx,
5455 uint8_t *command,
5456 uint8_t command_len,
5457 hdd_priv_data_t *priv_data)
5458{
5459 int ret;
5460 uint8_t *value = command;
5461 uint8_t *cckmIe = NULL;
5462 uint8_t cckmIeLen = 0;
5463
5464 ret = hdd_parse_get_cckm_ie(value, &cckmIe, &cckmIeLen);
5465 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005466 hdd_err("Failed to parse cckm ie data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005467 goto exit;
5468 }
5469
5470 if (cckmIeLen > DOT11F_IE_RSN_MAX_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005471 hdd_err("CCKM Ie input length is more than max[%d]",
5472 DOT11F_IE_RSN_MAX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005473 if (NULL != cckmIe) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305474 qdf_mem_free(cckmIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005475 cckmIe = NULL;
5476 }
5477 ret = -EINVAL;
5478 goto exit;
5479 }
5480
5481 sme_set_cckm_ie(hdd_ctx->hHal, adapter->sessionId,
5482 cckmIe, cckmIeLen);
5483 if (NULL != cckmIe) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305484 qdf_mem_free(cckmIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005485 cckmIe = NULL;
5486 }
5487
5488exit:
5489 return ret;
5490}
5491
5492static int drv_cmd_ccx_beacon_req(hdd_adapter_t *adapter,
5493 hdd_context_t *hdd_ctx,
5494 uint8_t *command,
5495 uint8_t command_len,
5496 hdd_priv_data_t *priv_data)
5497{
5498 int ret;
5499 uint8_t *value = command;
5500 tCsrEseBeaconReq eseBcnReq;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305501 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005502
Krunal Sonibe766b02016-03-10 13:00:44 -08005503 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005504 hdd_warn("Unsupported in mode %s(%d)",
5505 hdd_device_mode_to_string(adapter->device_mode),
5506 adapter->device_mode);
5507 return -EINVAL;
5508 }
5509
5510 ret = hdd_parse_ese_beacon_req(value, &eseBcnReq);
5511 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005512 hdd_err("Failed to parse ese beacon req");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005513 goto exit;
5514 }
5515
5516 if (!hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005517 hdd_info("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005518 hdd_indicate_ese_bcn_report_no_results(adapter,
5519 eseBcnReq.bcnReq[0].measurementToken,
5520 0x02, /* BIT(1) set for measurement done */
5521 0); /* no BSS */
5522 goto exit;
5523 }
5524
5525 status = sme_set_ese_beacon_request(hdd_ctx->hHal,
5526 adapter->sessionId,
5527 &eseBcnReq);
5528
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305529 if (QDF_STATUS_E_RESOURCES == status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005530 hdd_info("sme_set_ese_beacon_request failed (%d), a request already in progress",
5531 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005532 ret = -EBUSY;
5533 goto exit;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305534 } else if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005535 hdd_err("sme_set_ese_beacon_request failed (%d)",
5536 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005537 ret = -EINVAL;
5538 goto exit;
5539 }
5540
5541exit:
5542 return ret;
5543}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08005544#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005545
5546static int drv_cmd_set_mc_rate(hdd_adapter_t *adapter,
5547 hdd_context_t *hdd_ctx,
5548 uint8_t *command,
5549 uint8_t command_len,
5550 hdd_priv_data_t *priv_data)
5551{
5552 int ret = 0;
5553 uint8_t *value = command;
5554 int targetRate;
5555
5556 /* input value is in units of hundred kbps */
5557
5558 /* Move pointer to ahead of SETMCRATE<delimiter> */
5559 value = value + command_len + 1;
5560
5561 /* Convert the value from ascii to integer, decimal base */
5562 ret = kstrtouint(value, 10, &targetRate);
5563
5564 ret = wlan_hdd_set_mc_rate(adapter, targetRate);
5565 return ret;
5566}
5567
5568static int drv_cmd_max_tx_power(hdd_adapter_t *adapter,
5569 hdd_context_t *hdd_ctx,
5570 uint8_t *command,
5571 uint8_t command_len,
5572 hdd_priv_data_t *priv_data)
5573{
5574 int ret = 0;
5575 int status;
5576 int txPower;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305577 QDF_STATUS qdf_status;
5578 QDF_STATUS smeStatus;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005579 uint8_t *value = command;
Anurag Chouhan6d760662016-02-20 16:05:43 +05305580 struct qdf_mac_addr bssid = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
5581 struct qdf_mac_addr selfMac = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005582 hdd_adapter_list_node_t *pAdapterNode = NULL;
5583 hdd_adapter_list_node_t *pNext = NULL;
5584
5585 status = hdd_parse_setmaxtxpower_command(value, &txPower);
5586 if (status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005587 hdd_err("Invalid MAXTXPOWER command ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005588 ret = -EINVAL;
5589 goto exit;
5590 }
5591
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305592 qdf_status = hdd_get_front_adapter(hdd_ctx, &pAdapterNode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005593 while (NULL != pAdapterNode
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305594 && QDF_STATUS_SUCCESS == qdf_status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005595 adapter = pAdapterNode->pAdapter;
5596 /* Assign correct self MAC address */
Anurag Chouhanc5548422016-02-24 18:33:27 +05305597 qdf_copy_macaddr(&bssid,
Srinivas Girigowda97215232015-09-24 12:26:28 -07005598 &adapter->macAddressCurrent);
Anurag Chouhanc5548422016-02-24 18:33:27 +05305599 qdf_copy_macaddr(&selfMac,
Srinivas Girigowda97215232015-09-24 12:26:28 -07005600 &adapter->macAddressCurrent);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005601
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005602 hdd_info("Device mode %d max tx power %d selfMac: "
5603 MAC_ADDRESS_STR " bssId: " MAC_ADDRESS_STR " ",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005604 adapter->device_mode, txPower,
Srinivas Girigowda97215232015-09-24 12:26:28 -07005605 MAC_ADDR_ARRAY(selfMac.bytes),
5606 MAC_ADDR_ARRAY(bssid.bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005607
Srinivas Girigowda97215232015-09-24 12:26:28 -07005608 smeStatus = sme_set_max_tx_power(hdd_ctx->hHal,
5609 bssid, selfMac, txPower);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305610 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005611 hdd_err("Set max tx power failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005612 ret = -EINVAL;
5613 goto exit;
5614 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005615 hdd_info("Set max tx power success");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305616 qdf_status = hdd_get_next_adapter(hdd_ctx, pAdapterNode,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005617 &pNext);
5618 pAdapterNode = pNext;
5619 }
5620
5621exit:
5622 return ret;
5623}
5624
5625static int drv_cmd_set_dfs_scan_mode(hdd_adapter_t *adapter,
5626 hdd_context_t *hdd_ctx,
5627 uint8_t *command,
5628 uint8_t command_len,
5629 hdd_priv_data_t *priv_data)
5630{
5631 int ret = 0;
5632 uint8_t *value = command;
5633 uint8_t dfsScanMode = CFG_ROAMING_DFS_CHANNEL_DEFAULT;
5634
5635 /* Move pointer to ahead of SETDFSSCANMODE<delimiter> */
5636 value = value + command_len + 1;
5637
5638 /* Convert the value from ascii to integer */
5639 ret = kstrtou8(value, 10, &dfsScanMode);
5640 if (ret < 0) {
5641 /*
5642 * If the input value is greater than max value of datatype,
5643 * then also kstrtou8 fails
5644 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005645 hdd_err("kstrtou8 failed range [%d - %d]",
5646 CFG_ROAMING_DFS_CHANNEL_MIN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005647 CFG_ROAMING_DFS_CHANNEL_MAX);
5648 ret = -EINVAL;
5649 goto exit;
5650 }
5651
5652 if ((dfsScanMode < CFG_ROAMING_DFS_CHANNEL_MIN) ||
5653 (dfsScanMode > CFG_ROAMING_DFS_CHANNEL_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005654 hdd_err("dfsScanMode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005655 dfsScanMode,
5656 CFG_ROAMING_DFS_CHANNEL_MIN,
5657 CFG_ROAMING_DFS_CHANNEL_MAX);
5658 ret = -EINVAL;
5659 goto exit;
5660 }
5661
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005662 hdd_info("Received Command to Set DFS Scan Mode = %d",
5663 dfsScanMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005664
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005665 /* When DFS scanning is disabled, the DFS channels need to be
5666 * removed from the operation of device.
5667 */
5668 ret = wlan_hdd_disable_dfs_chan_scan(hdd_ctx, adapter,
5669 (dfsScanMode == CFG_ROAMING_DFS_CHANNEL_DISABLED));
5670 if (ret < 0) {
5671 /* Some conditions prevented it from disabling DFS channels */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005672 hdd_err("disable/enable DFS channel request was denied");
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005673 goto exit;
5674 }
5675
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005676 hdd_ctx->config->allowDFSChannelRoam = dfsScanMode;
5677 sme_update_dfs_scan_mode(hdd_ctx->hHal, adapter->sessionId,
5678 dfsScanMode);
5679
5680exit:
5681 return ret;
5682}
5683
5684static int drv_cmd_get_dfs_scan_mode(hdd_adapter_t *adapter,
5685 hdd_context_t *hdd_ctx,
5686 uint8_t *command,
5687 uint8_t command_len,
5688 hdd_priv_data_t *priv_data)
5689{
5690 int ret = 0;
5691 uint8_t dfsScanMode = sme_get_dfs_scan_mode(hdd_ctx->hHal);
5692 char extra[32];
5693 uint8_t len = 0;
5694
5695 len = scnprintf(extra, sizeof(extra), "%s %d", command, dfsScanMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305696 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005697 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005698 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005699 ret = -EFAULT;
5700 }
5701
5702 return ret;
5703}
5704
5705static int drv_cmd_get_link_status(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 int value = wlan_hdd_get_link_status(adapter);
5713 char extra[32];
5714 uint8_t len;
5715
5716 len = scnprintf(extra, sizeof(extra), "%s %d", command, value);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305717 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005718 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005719 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005720 ret = -EFAULT;
5721 }
5722
5723 return ret;
5724}
5725
5726#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
5727static int drv_cmd_enable_ext_wow(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 uint8_t *value = command;
5734 int set_value;
5735
5736 /* Move pointer to ahead of ENABLEEXTWOW */
5737 value = value + command_len;
5738
Anurag Chouhan43e0c752016-09-03 16:17:02 +05305739 if (!(sscanf(value, "%d", &set_value))) {
5740 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
5741 ("No input identified"));
5742 return -EINVAL;
5743 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005744
5745 return hdd_enable_ext_wow_parser(adapter,
5746 adapter->sessionId,
5747 set_value);
5748}
5749
5750static int drv_cmd_set_app1_params(hdd_adapter_t *adapter,
5751 hdd_context_t *hdd_ctx,
5752 uint8_t *command,
5753 uint8_t command_len,
5754 hdd_priv_data_t *priv_data)
5755{
5756 int ret;
5757 uint8_t *value = command;
5758
5759 /* Move pointer to ahead of SETAPP1PARAMS */
5760 value = value + command_len;
5761
5762 ret = hdd_set_app_type1_parser(adapter,
5763 value, strlen(value));
5764 if (ret >= 0)
5765 hdd_ctx->is_extwow_app_type1_param_set = true;
5766
5767 return ret;
5768}
5769
5770static int drv_cmd_set_app2_params(hdd_adapter_t *adapter,
5771 hdd_context_t *hdd_ctx,
5772 uint8_t *command,
5773 uint8_t command_len,
5774 hdd_priv_data_t *priv_data)
5775{
5776 int ret;
5777 uint8_t *value = command;
5778
5779 /* Move pointer to ahead of SETAPP2PARAMS */
5780 value = value + command_len;
5781
5782 ret = hdd_set_app_type2_parser(adapter, value, strlen(value));
5783 if (ret >= 0)
5784 hdd_ctx->is_extwow_app_type2_param_set = true;
5785
5786 return ret;
5787}
5788#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
5789
5790#ifdef FEATURE_WLAN_TDLS
5791/**
5792 * drv_cmd_tdls_secondary_channel_offset() - secondary tdls off channel offset
5793 * @adapter: Pointer to the HDD adapter
5794 * @hdd_ctx: Pointer to the HDD context
5795 * @command: Driver command string
5796 * @command_len: Driver command string length
5797 * @priv_data: Private data coming with the driver command. Unused here
5798 *
5799 * This function handles driver command that sets the secondary tdls off channel
5800 * offset
5801 *
5802 * Return: 0 on success; negative errno otherwise
5803 */
5804static int drv_cmd_tdls_secondary_channel_offset(hdd_adapter_t *adapter,
5805 hdd_context_t *hdd_ctx,
5806 uint8_t *command,
5807 uint8_t command_len,
5808 hdd_priv_data_t *priv_data)
5809{
5810 int ret;
5811 uint8_t *value = command;
5812 int set_value;
5813
5814 /* Move pointer to point the string */
5815 value += command_len;
5816
5817 ret = sscanf(value, "%d", &set_value);
5818 if (ret != 1)
5819 return -EINVAL;
5820
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005821 hdd_info("Tdls offchannel offset:%d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005822
5823 ret = hdd_set_tdls_secoffchanneloffset(hdd_ctx, set_value);
5824
5825 return ret;
5826}
5827
5828/**
5829 * drv_cmd_tdls_off_channel_mode() - set tdls off channel mode
5830 * @adapter: Pointer to the HDD adapter
5831 * @hdd_ctx: Pointer to the HDD context
5832 * @command: Driver command string
5833 * @command_len: Driver command string length
5834 * @priv_data: Private data coming with the driver command. Unused here
5835 *
5836 * This function handles driver command that sets tdls off channel mode
5837 *
5838 * Return: 0 on success; negative errno otherwise
5839 */
5840static int drv_cmd_tdls_off_channel_mode(hdd_adapter_t *adapter,
5841 hdd_context_t *hdd_ctx,
5842 uint8_t *command,
5843 uint8_t command_len,
5844 hdd_priv_data_t *priv_data)
5845{
5846 int ret;
5847 uint8_t *value = command;
5848 int set_value;
5849
5850 /* Move pointer to point the string */
5851 value += command_len;
5852
5853 ret = sscanf(value, "%d", &set_value);
5854 if (ret != 1)
5855 return -EINVAL;
5856
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005857 hdd_info("Tdls offchannel mode:%d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005858
5859 ret = hdd_set_tdls_offchannelmode(adapter, set_value);
5860
5861 return ret;
5862}
5863
5864/**
5865 * drv_cmd_tdls_off_channel() - set tdls off channel number
5866 * @adapter: Pointer to the HDD adapter
5867 * @hdd_ctx: Pointer to the HDD context
5868 * @command: Driver command string
5869 * @command_len: Driver command string length
5870 * @priv_data: Private data coming with the driver command. Unused here
5871 *
5872 * This function handles driver command that sets tdls off channel number
5873 *
5874 * Return: 0 on success; negative errno otherwise
5875 */
5876static int drv_cmd_tdls_off_channel(hdd_adapter_t *adapter,
5877 hdd_context_t *hdd_ctx,
5878 uint8_t *command,
5879 uint8_t command_len,
5880 hdd_priv_data_t *priv_data)
5881{
5882 int ret;
5883 uint8_t *value = command;
5884 int set_value;
5885
5886 /* Move pointer to point the string */
5887 value += command_len;
5888
5889 ret = sscanf(value, "%d", &set_value);
5890 if (ret != 1)
5891 return -EINVAL;
5892
Krishna Kumaar Natarajan4d090352015-10-26 18:30:53 -07005893 if (CDS_IS_DFS_CH(set_value)) {
5894 hdd_err("DFS channel %d is passed for hdd_set_tdls_offchannel",
5895 set_value);
5896 return -EINVAL;
5897 }
5898
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005899 hdd_info("Tdls offchannel num: %d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005900
5901 ret = hdd_set_tdls_offchannel(hdd_ctx, set_value);
5902
5903 return ret;
5904}
5905
5906/**
5907 * drv_cmd_tdls_scan() - set tdls scan type
5908 * @adapter: Pointer to the HDD adapter
5909 * @hdd_ctx: Pointer to the HDD context
5910 * @command: Driver command string
5911 * @command_len: Driver command string length
5912 * @priv_data: Private data coming with the driver command. Unused here
5913 *
5914 * This function handles driver command that sets tdls scan type
5915 *
5916 * Return: 0 on success; negative errno otherwise
5917 */
5918static int drv_cmd_tdls_scan(hdd_adapter_t *adapter,
5919 hdd_context_t *hdd_ctx,
5920 uint8_t *command,
5921 uint8_t command_len,
5922 hdd_priv_data_t *priv_data)
5923{
5924 int ret;
5925 uint8_t *value = command;
5926 int set_value;
5927
5928 /* Move pointer to point the string */
5929 value += command_len;
5930
5931 ret = sscanf(value, "%d", &set_value);
5932 if (ret != 1)
5933 return -EINVAL;
5934
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005935 hdd_info("Tdls scan type val: %d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005936
5937 ret = hdd_set_tdls_scan_type(hdd_ctx, set_value);
5938
5939 return ret;
5940}
5941#endif
5942
5943static int drv_cmd_get_rssi(hdd_adapter_t *adapter,
5944 hdd_context_t *hdd_ctx,
5945 uint8_t *command,
5946 uint8_t command_len,
5947 hdd_priv_data_t *priv_data)
5948{
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08005949 int ret = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005950 int8_t rssi = 0;
5951 char extra[32];
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08005952
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005953 uint8_t len = 0;
5954
5955 wlan_hdd_get_rssi(adapter, &rssi);
5956
5957 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305958 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005959
5960 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005961 hdd_err("Failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005962 ret = -EFAULT;
5963 }
5964
5965 return ret;
5966}
5967
5968static int drv_cmd_get_linkspeed(hdd_adapter_t *adapter,
5969 hdd_context_t *hdd_ctx,
5970 uint8_t *command,
5971 uint8_t command_len,
5972 hdd_priv_data_t *priv_data)
5973{
5974 int ret;
5975 uint32_t link_speed = 0;
5976 char extra[32];
5977 uint8_t len = 0;
5978
5979 ret = wlan_hdd_get_link_speed(adapter, &link_speed);
5980 if (0 != ret)
5981 return ret;
5982
5983 len = scnprintf(extra, sizeof(extra), "%s %d", command, link_speed);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305984 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005985 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005986 hdd_err("Failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005987 ret = -EFAULT;
5988 }
5989
5990 return ret;
5991}
5992
5993#ifdef FEATURE_NAPI
5994/**
5995 * hdd_parse_napi() - helper functions to drv_cmd_napi
5996 * @str : source string to parse
5997 * @cmd : pointer to cmd part after parsing
5998 * @sub : pointer to subcmd part after parsing
5999 * @aux : pointer to optional aux part after parsing
6000 *
6001 * Example:
6002 * NAPI SCALE <n> +-- IN str
6003 * | | +------ OUT aux
6004 * | +------------ OUT subcmd
6005 * +----------------- OUT cmd
6006 *
6007 * Return: ==0: success; !=0: failure
6008 */
6009static int hdd_parse_napi(char **str, char **cmd, char **sub, char **aux)
6010{
6011 int rc;
6012 char *token, *lcmd = NULL, *lsub = NULL, *laux = NULL;
6013
6014 NAPI_DEBUG("-->\n");
6015
6016 token = strsep(str, " \t");
6017 if (NULL == token) {
6018 hdd_err("cannot parse cmd");
6019 goto parse_end;
6020 }
6021 lcmd = token;
6022
6023 token = strsep(str, " \t");
6024 if (NULL == token) {
6025 hdd_err("cannot parse subcmd");
6026 goto parse_end;
6027 }
6028 lsub = token;
6029
6030 token = strsep(str, " \t");
6031 if (NULL == token)
6032 hdd_warn("cannot parse aux\n");
6033 else
6034 laux = token;
6035
6036parse_end:
6037 if ((NULL == lcmd) || (NULL == lsub))
6038 rc = -EINVAL;
6039 else {
6040 rc = 0;
6041 *cmd = lcmd;
6042 *sub = lsub;
6043 if (NULL != aux)
6044 *aux = laux;
6045 }
6046 NAPI_DEBUG("<--[rc=%d]\n", rc);
6047 return rc;
6048}
6049
6050
6051/**
6052 * hdd_parse_stats() - print NAPI stats into a buffer
6053 * @buf : buffer to write stats into
6054 * @max : "size of buffer"
6055 * @idp : NULL: all stats, otherwise, ptr to the NAPI instance
6056 * @napid: binary structure to retrieve the stats from
6057 *
6058 * Return: number of bytes written into the buffer
6059 */
6060int hdd_napi_stats(char *buf,
6061 int max,
6062 char *indp,
6063 struct qca_napi_data *napid)
6064{
6065 int n = 0;
6066 int i, j, k; /* NAPI, CPU, bucket indices */
6067 int from, to;
6068 struct qca_napi_info *napii;
6069 struct qca_napi_stat *napis;
6070
6071 NAPI_DEBUG("-->\n");
6072
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006073 if (NULL == napid)
6074 return n;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006075 if (NULL == indp) {
6076 from = 0;
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006077 to = CE_COUNT_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006078 } else {
6079 if (0 > kstrtoint(indp, 10, &to)) {
6080 from = 0;
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006081 to = CE_COUNT_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006082 } else
6083 from = to;
6084 }
6085
6086 for (i = from; i < to; i++)
6087 if (napid->ce_map & (0x01 << i)) {
6088 napii = &(napid->napis[i]);
6089 for (j = 0; j < NR_CPUS; j++) {
6090 napis = &(napii->stats[j]);
6091 n += scnprintf(buf + n, max - n,
6092 "STATS: NAPI[%d] CPU: %d scheds: %d polls: %d completes: %d done: %d ",
6093 i, j,
6094 napis->napi_schedules,
6095 napis->napi_polls,
6096 napis->napi_completes,
6097 napis->napi_workdone);
6098
6099 for (k = 0; k < QCA_NAPI_NUM_BUCKETS; k++) {
6100 n += scnprintf(
6101 buf + n, max - n,
6102 " %d",
6103 napis->napi_budget_uses[k]);
6104 }
6105 n += scnprintf(buf+n, max - n, "\n");
6106 }
6107 }
6108
6109 NAPI_DEBUG("<--[n=%d]\n", n);
6110 return n;
6111}
6112
6113/**
6114 * napi_set_scale() - sets the scale attribute in all NAPI entries
6115 * @sc : scale to set
6116 *
6117 * Return: void
6118 */
6119static void napi_set_scale(uint8_t sc)
6120{
6121 uint32_t i;
6122 struct qca_napi_data *napi_data;
6123
6124 napi_data = hdd_napi_get_all();
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006125 if (likely(NULL != napi_data))
6126 for (i = 0; i < CE_COUNT_MAX; i++)
6127 if (napi_data->ce_map & (0x01 << i))
6128 napi_data->napis[i].scale = sc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006129
6130 return;
6131}
6132/**
6133 * drv_cmd_napi() - processes NAPI commands
6134 * @adapter : net_device
6135 * @hdd_ctx : HDD context
6136 * @command : command string from user command (including "NAPI")
6137 * @command_len: length of command
6138 * @priv_data : ifr_data
6139 *
6140 * Commands supported:
6141 * NAPI ENABLE : enables NAPI administratively. Note that this may not
6142 * enable NAPI functionally, as some other conditions
6143 * may not have been satisfied yet
6144 * NAPI DISABLE : reverse operation of "enable"
6145 * NAPI STATUS : get global status of NAPI instances
6146 * NAPI STATS [<n>] : get the stats for a given NAPI instance
6147 * NAPI SCALE <n> : set the scale factor
6148 *
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006149 * Return: 0: success; !0: failure
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006150 */
6151static int drv_cmd_napi(hdd_adapter_t *adapter,
6152 hdd_context_t *hdd_ctx,
6153 uint8_t *command,
6154 uint8_t command_len,
6155 hdd_priv_data_t *priv_data)
6156{
6157 int rc = 0;
6158 int n, l;
6159 char *cmd = NULL, *subcmd = NULL, *aux = NULL;
6160 char *synopsis = "NAPI ENABLE\n"
6161 "NAPI DISABLE\n"
6162 "NAPI STATUS\n"
6163 "NAPI STATS [<n>] -- if no <n> then all\n"
6164 "NAPI SCALE <n> -- set the scale\n";
6165 char *reply = NULL;
6166
6167 /* make a local copy, as strsep modifies the str in place */
6168 char *str = NULL;
6169
6170 NAPI_DEBUG("-->\n");
6171
6172 /**
6173 * NOTE TO MAINTAINER: from this point to the end of the function,
6174 * please do not return anywhere in the code except the very end
6175 * to avoid memory leakage (goto end_drv_napi instead)
6176 * or make sure that reply+str is freed
6177 */
6178 reply = kmalloc(MAX_USER_COMMAND_SIZE, GFP_KERNEL);
6179 if (NULL == reply) {
6180 hdd_err("could not allocate reply buffer");
6181 rc = -ENOMEM;
6182 goto end_drv_napi;
6183 }
6184
6185 str = kmalloc(strlen(command) + 1, GFP_KERNEL);
6186 if (NULL == str) {
6187 hdd_err("could not allocate copy of input buffer");
6188 rc = -ENOMEM;
6189 goto end_drv_napi;
6190 }
6191
6192 strlcpy(str, command, strlen(command) + 1);
6193 hdd_debug("parsing command into cmd=0x%p sub=0x%p aux=0x%p\n",
6194 cmd, subcmd, aux);
6195
6196
6197 rc = hdd_parse_napi(&str, &cmd, &subcmd, &aux);
6198
6199 if (0 != rc) {
6200 const char *msg = "unknown or badly formatted cmd\n%s";
Anurag Chouhan6d760662016-02-20 16:05:43 +05306201 l = QDF_MIN(MAX_USER_COMMAND_SIZE,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006202 strlen(msg)+strlen(synopsis));
6203 n = scnprintf(reply, l, msg, synopsis);
6204
6205 if (copy_to_user(priv_data->buf, reply,
Anurag Chouhan6d760662016-02-20 16:05:43 +05306206 QDF_MIN(priv_data->total_len, l)))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006207 hdd_err("failed to copy data to user buffer");
6208 hdd_debug("reply: %s", reply);
6209
6210 rc = -EINVAL;
6211 } else {
6212 hdd_debug("cmd=(%s) subcmd=(%s) aux=(%s)\n",
6213 cmd, subcmd, aux);
6214 if (!strcmp(subcmd, "ENABLE"))
6215 hdd_napi_event(NAPI_EVT_CMD_STATE, (void *)1);
6216 else if (!strcmp(subcmd, "DISABLE"))
6217 hdd_napi_event(NAPI_EVT_CMD_STATE, (void *)0);
6218 else if (!strcmp(subcmd, "STATUS")) {
6219 int n = 0;
6220 uint32_t i;
6221 struct qca_napi_data *napi_data;
6222
6223 napi_data = hdd_napi_get_all();
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006224 if (unlikely(NULL == napi_data))
6225 goto status_end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006226 n += scnprintf(reply+n, MAX_USER_COMMAND_SIZE - n,
6227 "NAPI state: 0x%08x map: 0x%08x\n",
6228 napi_data->state,
6229 napi_data->ce_map);
6230
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006231 for (i = 0; i < CE_COUNT_MAX; i++)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006232 if (napi_data->ce_map & (0x01 << i)) {
6233 n += scnprintf(
6234 reply + n,
6235 MAX_USER_COMMAND_SIZE - n,
6236 "#%d: id: %d, scale=%d\n",
6237 i,
6238 napi_data->napis[i].id,
6239 napi_data->napis[i].scale);
6240 }
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006241 status_end:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006242 hdd_info("wlan: STATUS DATA:\n%s", reply);
6243 if (copy_to_user(priv_data->buf, reply,
Anurag Chouhan6d760662016-02-20 16:05:43 +05306244 QDF_MIN(n, priv_data->total_len)))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006245 rc = -EINVAL;
6246 } else if (!strcmp(subcmd, "STATS")) {
6247 int n = 0;
6248 struct qca_napi_data *napi_data;
6249
6250 napi_data = hdd_napi_get_all();
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006251 if (NULL != napi_data) {
6252 n = hdd_napi_stats(reply, MAX_USER_COMMAND_SIZE,
6253 aux, napi_data);
6254 NAPI_DEBUG("STATS: returns %d\n", n);
6255 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006256 if (n > 0) {
6257 if (copy_to_user(priv_data->buf, reply,
Anurag Chouhan6d760662016-02-20 16:05:43 +05306258 QDF_MIN(priv_data->total_len,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006259 n)))
6260 rc = -EINVAL;
6261 hdd_info("wlan: STATS_DATA\n%s\n", reply);
6262 } else
6263 rc = -EINVAL;
6264 } else if (!strcmp(subcmd, "SCALE")) {
6265 if (NULL == aux) {
6266 rc = -EINVAL;
6267 hdd_err("wlan: SCALE cmd requires <n>");
6268 } else {
6269 uint8_t sc;
6270 rc = kstrtou8(aux, 10, &sc);
6271 if (rc) {
6272 hdd_err("wlan: bad scale (%s)", aux);
6273 rc = -EINVAL;
6274 } else
6275 napi_set_scale(sc);
6276 }
6277 } /* SCALE */
6278 }
6279end_drv_napi:
6280 if (NULL != str)
6281 kfree(str);
6282 if (NULL != reply)
6283 kfree(reply);
6284
6285 NAPI_DEBUG("<--[rc=%d]\n", rc);
6286 return rc;
6287}
6288#endif /* FEATURE_NAPI */
6289
6290/**
6291 * hdd_set_rx_filter() - set RX filter
6292 * @adapter: Pointer to adapter
6293 * @action: Filter action
6294 * @pattern: Address pattern
6295 *
6296 * Address pattern is most significant byte of address for example
6297 * 0x01 for IPV4 multicast address
6298 * 0x33 for IPV6 multicast address
6299 * 0xFF for broadcast address
6300 *
6301 * Return: 0 for success, non-zero for failure
6302 */
6303static int hdd_set_rx_filter(hdd_adapter_t *adapter, bool action,
6304 uint8_t pattern)
6305{
6306 int ret;
6307 uint8_t i;
6308 tHalHandle handle;
6309 tSirRcvFltMcAddrList *filter;
6310 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
6311
6312 ret = wlan_hdd_validate_context(hdd_ctx);
6313 if (0 != ret)
6314 return ret;
6315
6316 handle = hdd_ctx->hHal;
6317
6318 if (NULL == handle) {
6319 hdd_err("HAL Handle is NULL");
6320 return -EINVAL;
6321 }
6322
6323 /*
6324 * If action is false it means start dropping packets
6325 * Set addr_filter_pattern which will be used when sending
6326 * MC/BC address list to target
6327 */
6328 if (!action)
6329 adapter->addr_filter_pattern = pattern;
6330 else
6331 adapter->addr_filter_pattern = 0;
6332
Krunal Sonibe766b02016-03-10 13:00:44 -08006333 if (((adapter->device_mode == QDF_STA_MODE) ||
6334 (adapter->device_mode == QDF_P2P_CLIENT_MODE)) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006335 adapter->mc_addr_list.mc_cnt &&
6336 hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
6337
6338
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306339 filter = qdf_mem_malloc(sizeof(*filter));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006340 if (NULL == filter) {
6341 hdd_err("Could not allocate Memory");
6342 return -ENOMEM;
6343 }
6344 filter->action = action;
6345 for (i = 0; i < adapter->mc_addr_list.mc_cnt; i++) {
6346 if (!memcmp(adapter->mc_addr_list.addr[i],
6347 &pattern, 1)) {
Srinivas Girigowda98530492015-11-20 17:39:24 -08006348 memcpy(filter->multicastAddr[i].bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006349 adapter->mc_addr_list.addr[i],
6350 sizeof(adapter->mc_addr_list.addr[i]));
6351 filter->ulMulticastAddrCnt++;
Srinivas Girigowdaf2599dd2015-11-16 18:20:46 -08006352 hdd_info("%s RX filter : addr ="
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006353 MAC_ADDRESS_STR,
6354 action ? "setting" : "clearing",
Srinivas Girigowda98530492015-11-20 17:39:24 -08006355 MAC_ADDR_ARRAY(filter->multicastAddr[i].bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006356 }
6357 }
6358 /* Set rx filter */
6359 sme_8023_multicast_list(handle, adapter->sessionId, filter);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306360 qdf_mem_free(filter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006361 } else {
Srinivas Girigowdaf2599dd2015-11-16 18:20:46 -08006362 hdd_info("mode %d mc_cnt %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006363 adapter->device_mode, adapter->mc_addr_list.mc_cnt);
6364 }
6365
6366 return 0;
6367}
6368
6369/**
6370 * hdd_driver_rxfilter_comand_handler() - RXFILTER driver command handler
6371 * @command: Pointer to input string driver command
6372 * @adapter: Pointer to adapter
6373 * @action: Action to enable/disable filtering
6374 *
6375 * If action == false
6376 * Start filtering out data packets based on type
6377 * RXFILTER-REMOVE 0 -> Start filtering out unicast data packets
6378 * RXFILTER-REMOVE 1 -> Start filtering out broadcast data packets
6379 * RXFILTER-REMOVE 2 -> Start filtering out IPV4 mcast data packets
6380 * RXFILTER-REMOVE 3 -> Start filtering out IPV6 mcast data packets
6381 *
6382 * if action == true
6383 * Stop filtering data packets based on type
6384 * RXFILTER-ADD 0 -> Stop filtering unicast data packets
6385 * RXFILTER-ADD 1 -> Stop filtering broadcast data packets
6386 * RXFILTER-ADD 2 -> Stop filtering IPV4 mcast data packets
6387 * RXFILTER-ADD 3 -> Stop filtering IPV6 mcast data packets
6388 *
6389 * Current implementation only supports IPV4 address filtering by
6390 * selectively allowing IPV4 multicast data packest based on
6391 * address list received in .ndo_set_rx_mode
6392 *
6393 * Return: 0 for success, non-zero for failure
6394 */
6395static int hdd_driver_rxfilter_comand_handler(uint8_t *command,
6396 hdd_adapter_t *adapter,
6397 bool action)
6398{
6399 int ret = 0;
6400 uint8_t *value;
6401 uint8_t type;
6402
6403 value = command;
6404 /* Skip space after RXFILTER-REMOVE OR RXFILTER-ADD based on action */
6405 if (!action)
6406 value = command + 16;
6407 else
6408 value = command + 13;
6409 ret = kstrtou8(value, 10, &type);
6410 if (ret < 0) {
6411 hdd_err("kstrtou8 failed invalid input value %d", type);
6412 return -EINVAL;
6413 }
6414
6415 switch (type) {
6416 case 2:
6417 /* Set rx filter for IPV4 multicast data packets */
6418 ret = hdd_set_rx_filter(adapter, action, 0x01);
6419 break;
6420 default:
6421 hdd_info("Unsupported RXFILTER type %d", type);
6422 break;
6423 }
6424
6425 return ret;
6426}
6427
6428/**
6429 * drv_cmd_rx_filter_remove() - RXFILTER REMOVE driver command handler
6430 * @adapter: Pointer to network adapter
6431 * @hdd_ctx: Pointer to hdd context
6432 * @command: Pointer to input command
6433 * @command_len: Command length
6434 * @priv_data: Pointer to private data in command
6435 */
6436static int drv_cmd_rx_filter_remove(hdd_adapter_t *adapter,
6437 hdd_context_t *hdd_ctx,
6438 uint8_t *command,
6439 uint8_t command_len,
6440 hdd_priv_data_t *priv_data)
6441{
6442 return hdd_driver_rxfilter_comand_handler(command, adapter, false);
6443}
6444
6445/**
6446 * drv_cmd_rx_filter_add() - RXFILTER ADD driver command handler
6447 * @adapter: Pointer to network adapter
6448 * @hdd_ctx: Pointer to hdd context
6449 * @command: Pointer to input command
6450 * @command_len: Command length
6451 * @priv_data: Pointer to private data in command
6452 */
6453static int drv_cmd_rx_filter_add(hdd_adapter_t *adapter,
6454 hdd_context_t *hdd_ctx,
6455 uint8_t *command,
6456 uint8_t command_len,
6457 hdd_priv_data_t *priv_data)
6458{
6459 return hdd_driver_rxfilter_comand_handler(command, adapter, true);
6460}
6461
Archana Ramachandran393f3792015-11-13 17:13:21 -08006462/**
6463 * hdd_parse_setantennamode_command() - HDD Parse SETANTENNAMODE
6464 * command
6465 * @value: Pointer to SETANTENNAMODE command
6466 * @mode: Pointer to antenna mode
6467 * @reason: Pointer to reason for set antenna mode
6468 *
6469 * This function parses the SETANTENNAMODE command passed in the format
6470 * SETANTENNAMODE<space>mode
6471 *
6472 * Return: 0 for success non-zero for failure
6473 */
6474static int hdd_parse_setantennamode_command(const uint8_t *value)
6475{
6476 const uint8_t *in_ptr = value;
6477 int tmp, v;
6478 char arg1[32];
6479
6480 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
6481
6482 /* no argument after the command */
6483 if (NULL == in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006484 hdd_err("No argument after the command");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006485 return -EINVAL;
6486 }
6487
6488 /* no space after the command */
6489 if (SPACE_ASCII_VALUE != *in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006490 hdd_err("No space after the command");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006491 return -EINVAL;
6492 }
6493
6494 /* remove empty spaces */
6495 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
6496 in_ptr++;
6497
6498 /* no argument followed by spaces */
6499 if ('\0' == *in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006500 hdd_err("No argument followed by spaces");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006501 return -EINVAL;
6502 }
6503
6504 /* get the argument i.e. antenna mode */
6505 v = sscanf(in_ptr, "%31s ", arg1);
6506 if (1 != v) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006507 hdd_err("argument retrieval from cmd string failed");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006508 return -EINVAL;
6509 }
6510
6511 v = kstrtos32(arg1, 10, &tmp);
6512 if (v < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006513 hdd_err("argument string to int conversion failed");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006514 return -EINVAL;
6515 }
6516
6517 return tmp;
6518}
6519
6520/**
6521 * hdd_is_supported_chain_mask_2x2() - Verify if supported chain
6522 * mask is 2x2 mode
6523 * @hdd_ctx: Pointer to hdd contex
6524 *
6525 * Return: true if supported chain mask 2x2 else false
6526 */
6527static bool hdd_is_supported_chain_mask_2x2(hdd_context_t *hdd_ctx)
6528{
6529 /*
6530 * Revisit and the update logic to determine the number
6531 * of TX/RX chains supported in the system when
6532 * antenna sharing per band chain mask support is
6533 * brought in
6534 */
6535 return (hdd_ctx->config->enable2x2 == 0x01) ? true : false;
6536}
6537
6538/**
6539 * hdd_is_supported_chain_mask_1x1() - Verify if the supported
6540 * chain mask is 1x1
6541 * @hdd_ctx: Pointer to hdd contex
6542 *
6543 * Return: true if supported chain mask 1x1 else false
6544 */
6545static bool hdd_is_supported_chain_mask_1x1(hdd_context_t *hdd_ctx)
6546{
6547 /*
6548 * Revisit and update the logic to determine the number
6549 * of TX/RX chains supported in the system when
6550 * antenna sharing per band chain mask support is
6551 * brought in
6552 */
6553 return (!hdd_ctx->config->enable2x2) ? true : false;
6554}
6555
6556/**
6557 * drv_cmd_set_antenna_mode() - SET ANTENNA MODE driver command
6558 * handler
6559 * @adapter: Pointer to network adapter
6560 * @hdd_ctx: Pointer to hdd context
6561 * @command: Pointer to input command
6562 * @command_len: Command length
6563 * @priv_data: Pointer to private data in command
6564 */
6565static int drv_cmd_set_antenna_mode(hdd_adapter_t *adapter,
6566 hdd_context_t *hdd_ctx,
6567 uint8_t *command,
6568 uint8_t command_len,
6569 hdd_priv_data_t *priv_data)
6570{
6571 struct sir_antenna_mode_param params;
6572 QDF_STATUS status;
6573 int ret = 0;
6574 int mode;
6575 uint8_t *value = command;
6576 uint8_t smps_mode;
6577 uint8_t smps_enable;
6578
6579 if (((1 << QDF_STA_MODE) != hdd_ctx->concurrency_mode) ||
6580 (hdd_ctx->no_of_active_sessions[QDF_STA_MODE] > 1)) {
6581 hdd_err("Operation invalid in non sta or concurrent mode");
6582 ret = -EPERM;
6583 goto exit;
6584 }
6585
6586 mode = hdd_parse_setantennamode_command(value);
6587 if (mode < 0) {
6588 hdd_err("Invalid SETANTENNA command");
6589 ret = mode;
6590 goto exit;
6591 }
6592
6593 hdd_info("Processing antenna mode switch to: %d", mode);
6594
6595 if (hdd_ctx->current_antenna_mode == mode) {
6596 hdd_err("System already in the requested mode");
6597 ret = 0;
6598 goto exit;
6599 }
6600
6601 if ((HDD_ANTENNA_MODE_2X2 == mode) &&
6602 (!hdd_is_supported_chain_mask_2x2(hdd_ctx))) {
6603 hdd_err("System does not support 2x2 mode");
6604 ret = -EPERM;
6605 goto exit;
6606 }
6607
6608 if ((HDD_ANTENNA_MODE_1X1 == mode) &&
6609 hdd_is_supported_chain_mask_1x1(hdd_ctx)) {
6610 hdd_err("System only supports 1x1 mode");
6611 ret = 0;
6612 goto exit;
6613 }
6614
6615 switch (mode) {
6616 case HDD_ANTENNA_MODE_1X1:
6617 params.num_rx_chains = 1;
6618 params.num_tx_chains = 1;
6619 break;
6620 case HDD_ANTENNA_MODE_2X2:
6621 params.num_rx_chains = 2;
6622 params.num_tx_chains = 2;
6623 break;
6624 default:
6625 hdd_err("unsupported antenna mode");
6626 ret = -EINVAL;
6627 goto exit;
6628 }
6629
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006630 /* Check TDLS status and update antenna mode */
6631 if ((QDF_STA_MODE == adapter->device_mode) &&
6632 cds_is_sta_active_connection_exists() &&
6633 (hdd_ctx->connected_peer_count > 0)) {
Archana Ramachandran2ad7de22016-04-22 16:53:25 -07006634 ret = wlan_hdd_tdls_antenna_switch(hdd_ctx, adapter,
6635 mode);
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006636 if (0 != ret)
6637 goto exit;
6638 }
6639
Archana Ramachandran393f3792015-11-13 17:13:21 -08006640 params.set_antenna_mode_resp =
6641 (void *)wlan_hdd_soc_set_antenna_mode_cb;
6642 hdd_info("Set antenna mode rx chains: %d tx chains: %d",
6643 params.num_rx_chains,
6644 params.num_tx_chains);
6645
6646
6647 INIT_COMPLETION(hdd_ctx->set_antenna_mode_cmpl);
6648 status = sme_soc_set_antenna_mode(hdd_ctx->hHal, &params);
6649 if (QDF_STATUS_SUCCESS != status) {
6650 hdd_err("set antenna mode failed status : %d", status);
6651 ret = -EFAULT;
6652 goto exit;
6653 }
6654
6655 ret = wait_for_completion_timeout(
6656 &hdd_ctx->set_antenna_mode_cmpl,
6657 msecs_to_jiffies(WLAN_WAIT_TIME_ANTENNA_MODE_REQ));
6658 if (!ret) {
6659 ret = -EFAULT;
6660 hdd_err("send set antenna mode timed out");
6661 goto exit;
6662 }
6663
6664 /* Update SME SMPS config */
6665 if (HDD_ANTENNA_MODE_1X1 == mode) {
6666 smps_enable = true;
6667 smps_mode = HDD_SMPS_MODE_STATIC;
6668 } else {
6669 smps_enable = false;
6670 smps_mode = HDD_SMPS_MODE_DISABLED;
6671 }
6672
6673 hdd_info("Update SME SMPS enable: %d mode: %d",
6674 smps_enable, smps_mode);
6675 status = sme_update_mimo_power_save(
6676 hdd_ctx->hHal, smps_enable, smps_mode, false);
6677 if (QDF_STATUS_SUCCESS != status) {
6678 hdd_err("Update SMPS config failed enable: %d mode: %d status: %d",
6679 smps_enable, smps_mode, status);
6680 ret = -EFAULT;
6681 goto exit;
6682 }
6683
Archana Ramachandran393f3792015-11-13 17:13:21 -08006684 hdd_ctx->current_antenna_mode = mode;
Archana Ramachandran5041b252016-04-25 14:29:25 -07006685 /* Update the user requested nss in the mac context.
6686 * This will be used in tdls protocol engine to form tdls
6687 * Management frames.
6688 */
6689 sme_update_user_configured_nss(
6690 hdd_ctx->hHal,
6691 hdd_ctx->current_antenna_mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006692
Archana Ramachandran5041b252016-04-25 14:29:25 -07006693 hdd_info("Successfully switched to mode: %d x %d",
6694 hdd_ctx->current_antenna_mode,
6695 hdd_ctx->current_antenna_mode);
6696 ret = 0;
Archana Ramachandran393f3792015-11-13 17:13:21 -08006697exit:
Kabilan Kannanff89f742016-08-15 18:14:10 -07006698#ifdef FEATURE_WLAN_TDLS
6699 /* Reset tdls NSS flags */
6700 if (hdd_ctx->tdls_nss_switch_in_progress &&
6701 hdd_ctx->tdls_nss_teardown_complete) {
6702 hdd_ctx->tdls_nss_switch_in_progress = false;
6703 hdd_ctx->tdls_nss_teardown_complete = false;
6704 }
6705 hdd_info("tdls_nss_switch_in_progress: %d tdls_nss_teardown_complete: %d",
6706 hdd_ctx->tdls_nss_switch_in_progress,
6707 hdd_ctx->tdls_nss_teardown_complete);
6708#endif
Archana Ramachandran393f3792015-11-13 17:13:21 -08006709 hdd_info("Set antenna status: %d current mode: %d",
6710 ret, hdd_ctx->current_antenna_mode);
6711 return ret;
6712
6713}
6714
6715/**
6716 * drv_cmd_get_antenna_mode() - GET ANTENNA MODE driver command
6717 * handler
6718 * @adapter: Pointer to hdd adapter
6719 * @hdd_ctx: Pointer to hdd context
6720 * @command: Pointer to input command
6721 * @command_len: length of the command
6722 * @priv_data: private data coming with the driver command
6723 *
6724 * Return: 0 for success non-zero for failure
6725 */
6726static inline int drv_cmd_get_antenna_mode(hdd_adapter_t *adapter,
6727 hdd_context_t *hdd_ctx,
6728 uint8_t *command,
6729 uint8_t command_len,
6730 hdd_priv_data_t *priv_data)
6731{
6732 uint32_t antenna_mode = 0;
6733 char extra[32];
6734 uint8_t len = 0;
6735
6736 antenna_mode = hdd_ctx->current_antenna_mode;
6737 len = scnprintf(extra, sizeof(extra), "%s %d", command,
6738 antenna_mode);
6739 len = QDF_MIN(priv_data->total_len, len + 1);
6740 if (copy_to_user(priv_data->buf, &extra, len)) {
6741 hdd_err("Failed to copy data to user buffer");
6742 return -EFAULT;
6743 }
6744
6745 hdd_info("Get antenna mode: %d", antenna_mode);
6746
6747 return 0;
6748}
6749
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006750/*
6751 * dummy (no-op) hdd driver command handler
6752 */
6753static int drv_cmd_dummy(hdd_adapter_t *adapter,
6754 hdd_context_t *hdd_ctx,
6755 uint8_t *command,
6756 uint8_t command_len,
6757 hdd_priv_data_t *priv_data)
6758{
6759 hdd_info("%s: Ignoring driver command \"%s\"",
6760 adapter->dev->name, command);
6761 return 0;
6762}
6763
6764/*
6765 * handler for any unsupported wlan hdd driver command
6766 */
6767static int drv_cmd_invalid(hdd_adapter_t *adapter,
6768 hdd_context_t *hdd_ctx,
6769 uint8_t *command,
6770 uint8_t command_len,
6771 hdd_priv_data_t *priv_data)
6772{
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306773 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006774 TRACE_CODE_HDD_UNSUPPORTED_IOCTL,
6775 adapter->sessionId, 0));
6776
6777 hdd_warn("%s: Unsupported driver command \"%s\"",
6778 adapter->dev->name, command);
6779
6780 return -ENOTSUPP;
6781}
6782
6783/**
6784 * drv_cmd_set_fcc_channel() - handle fcc constraint request
6785 * @adapter: HDD adapter
6786 * @hdd_ctx: HDD context
6787 * @command: command ptr, SET_FCC_CHANNEL 0/1 is the command
6788 * @command_len: command len
6789 * @priv_data: private data
6790 *
6791 * Return: status
6792 */
6793static int drv_cmd_set_fcc_channel(hdd_adapter_t *adapter,
6794 hdd_context_t *hdd_ctx,
6795 uint8_t *command,
6796 uint8_t command_len,
6797 hdd_priv_data_t *priv_data)
6798{
6799 uint8_t *value;
6800 uint8_t fcc_constraint;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306801 QDF_STATUS status;
Amar Singhal83a047a2016-05-19 15:56:11 -07006802 bool scan_pending;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006803 int ret = 0;
6804
6805 /*
6806 * this command would be called by user-space when it detects WLAN
6807 * ON after airplane mode is set. When APM is set, WLAN turns off.
6808 * But it can be turned back on. Otherwise; when APM is turned back
6809 * off, WLAN would turn back on. So at that point the command is
6810 * expected to come down. 0 means disable, 1 means enable. The
6811 * constraint is removed when parameter 1 is set or different
6812 * country code is set
6813 */
6814
6815 value = command + command_len + 1;
6816
6817 ret = kstrtou8(value, 10, &fcc_constraint);
6818 if ((ret < 0) || (fcc_constraint > 1)) {
6819 /*
6820 * If the input value is greater than max value of datatype,
6821 * then also it is a failure
6822 */
6823 hdd_err("value out of range");
6824 return -EINVAL;
6825 }
6826
Amar Singhal83a047a2016-05-19 15:56:11 -07006827 scan_pending = !qdf_list_empty(&hdd_ctx->hdd_scan_req_q);
6828 status = sme_handle_set_fcc_channel(hdd_ctx->hHal, !fcc_constraint,
6829 scan_pending);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306830 if (status != QDF_STATUS_SUCCESS) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006831 hdd_err("sme disable fn. returned err");
6832 ret = -EPERM;
6833 }
6834
6835 return ret;
6836}
6837
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306838/**
6839 * hdd_parse_set_channel_switch_command() - Parse and validate CHANNEL_SWITCH
6840 * command
6841 * @value: Pointer to the command
6842 * @chan_number: Pointer to the channel number
6843 * @chan_bw: Pointer to the channel bandwidth
6844 *
6845 * Parses and provides the channel number and channel width from the input
6846 * command which is expected to be of the format: CHANNEL_SWITCH <CH> <BW>
6847 * <CH> is channel number to move (where 1 = channel 1, 149 = channel 149, ...)
6848 * <BW> is bandwidth to move (where 20 = BW 20, 40 = BW 40, 80 = BW 80)
6849 *
6850 * Return: 0 for success, non-zero for failure
6851 */
6852static int hdd_parse_set_channel_switch_command(uint8_t *value,
6853 uint32_t *chan_number,
6854 uint32_t *chan_bw)
6855{
6856 const uint8_t *in_ptr = value;
6857 int ret;
6858
6859 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
6860
6861 /* no argument after the command */
6862 if (NULL == in_ptr) {
6863 hdd_err("No argument after the command");
6864 return -EINVAL;
6865 }
6866
6867 /* no space after the command */
6868 if (SPACE_ASCII_VALUE != *in_ptr) {
6869 hdd_err("No space after the command ");
6870 return -EINVAL;
6871 }
6872
6873 /* remove empty spaces and move the next argument */
6874 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
6875 in_ptr++;
6876
6877 /* no argument followed by spaces */
6878 if ('\0' == *in_ptr) {
6879 hdd_err("No argument followed by spaces");
6880 return -EINVAL;
6881 }
6882
6883 /* get the two arguments: channel number and bandwidth */
6884 ret = sscanf(in_ptr, "%u %u", chan_number, chan_bw);
6885 if (ret != 2) {
6886 hdd_err("Arguments retrieval from cmd string failed");
6887 return -EINVAL;
6888 }
6889
6890 return 0;
6891}
6892
6893/**
6894 * drv_cmd_set_channel_switch() - Switch SAP/P2P-GO operating channel
6895 * @adapter: HDD adapter
6896 * @hdd_ctx: HDD context
6897 * @command: Pointer to the input command CHANNEL_SWITCH
6898 * @command_len: Command len
6899 * @priv_data: Private data
6900 *
6901 * Handles private IOCTL CHANNEL_SWITCH command to switch the operating channel
6902 * of SAP/P2P-GO
6903 *
6904 * Return: 0 for success, non-zero for failure
6905 */
6906static int drv_cmd_set_channel_switch(hdd_adapter_t *adapter,
6907 hdd_context_t *hdd_ctx,
6908 uint8_t *command,
6909 uint8_t command_len,
6910 hdd_priv_data_t *priv_data)
6911{
6912 struct net_device *dev = adapter->dev;
6913 int status;
6914 uint32_t chan_number = 0, chan_bw = 0;
6915 uint8_t *value = command;
Kiran Kumar Lokere13644672016-02-29 15:40:10 -08006916 enum phy_ch_width width;
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306917
Krunal Sonibe766b02016-03-10 13:00:44 -08006918 if ((adapter->device_mode != QDF_P2P_GO_MODE) &&
6919 (adapter->device_mode != QDF_SAP_MODE)) {
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306920 hdd_err("IOCTL CHANNEL_SWITCH not supported for mode %d",
6921 adapter->device_mode);
6922 return -EINVAL;
6923 }
6924
6925 status = hdd_parse_set_channel_switch_command(value,
6926 &chan_number, &chan_bw);
6927 if (status) {
6928 hdd_err("Invalid CHANNEL_SWITCH command");
6929 return status;
6930 }
6931
6932 if ((chan_bw != 20) && (chan_bw != 40) && (chan_bw != 80)) {
6933 hdd_err("BW %d is not allowed for CHANNEL_SWITCH", chan_bw);
6934 return -EINVAL;
6935 }
6936
6937 if (chan_bw == 80)
6938 width = CH_WIDTH_80MHZ;
6939 else if (chan_bw == 40)
6940 width = CH_WIDTH_40MHZ;
6941 else
6942 width = CH_WIDTH_20MHZ;
6943
6944 hdd_info("CH:%d BW:%d", chan_number, chan_bw);
6945
6946 status = hdd_softap_set_channel_change(dev, chan_number, width);
6947 if (status) {
6948 hdd_err("Set channel change fail");
6949 return status;
6950 }
6951
6952 return 0;
6953}
6954
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006955/*
6956 * The following table contains all supported WLAN HDD
6957 * IOCTL driver commands and the handler for each of them.
6958 */
6959static const hdd_drv_cmd_t hdd_drv_cmds[] = {
6960 {"P2P_DEV_ADDR", drv_cmd_p2p_dev_addr},
6961 {"P2P_SET_NOA", drv_cmd_p2p_set_noa},
6962 {"P2P_SET_PS", drv_cmd_p2p_set_ps},
6963 {"SETBAND", drv_cmd_set_band},
6964 {"SETWMMPS", drv_cmd_set_wmmps},
6965 {"COUNTRY", drv_cmd_country},
6966 {"SETSUSPENDMODE", drv_cmd_dummy},
6967 {"SET_AP_WPS_P2P_IE", drv_cmd_dummy},
6968 {"BTCOEXSCAN", drv_cmd_dummy},
6969 {"RXFILTER", drv_cmd_dummy},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006970 {"SETROAMTRIGGER", drv_cmd_set_roam_trigger},
6971 {"GETROAMTRIGGER", drv_cmd_get_roam_trigger},
6972 {"SETROAMSCANPERIOD", drv_cmd_set_roam_scan_period},
6973 {"GETROAMSCANPERIOD", drv_cmd_get_roam_scan_period},
6974 {"SETROAMSCANREFRESHPERIOD", drv_cmd_set_roam_scan_refresh_period},
6975 {"GETROAMSCANREFRESHPERIOD", drv_cmd_get_roam_scan_refresh_period},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006976 {"SETROAMMODE", drv_cmd_set_roam_mode},
6977 {"GETROAMMODE", drv_cmd_get_roam_mode},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006978 {"SETROAMDELTA", drv_cmd_set_roam_delta},
6979 {"GETROAMDELTA", drv_cmd_get_roam_delta},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006980 {"GETBAND", drv_cmd_get_band},
6981 {"SETROAMSCANCHANNELS", drv_cmd_set_roam_scan_channels},
6982 {"GETROAMSCANCHANNELS", drv_cmd_get_roam_scan_channels},
6983 {"GETCCXMODE", drv_cmd_get_ccx_mode},
6984 {"GETOKCMODE", drv_cmd_get_okc_mode},
6985 {"GETFASTROAM", drv_cmd_get_fast_roam},
6986 {"GETFASTTRANSITION", drv_cmd_get_fast_transition},
6987 {"SETROAMSCANCHANNELMINTIME", drv_cmd_set_roam_scan_channel_min_time},
6988 {"SENDACTIONFRAME", drv_cmd_send_action_frame},
6989 {"GETROAMSCANCHANNELMINTIME", drv_cmd_get_roam_scan_channel_min_time},
6990 {"SETSCANCHANNELTIME", drv_cmd_set_scan_channel_time},
6991 {"GETSCANCHANNELTIME", drv_cmd_get_scan_channel_time},
6992 {"SETSCANHOMETIME", drv_cmd_set_scan_home_time},
6993 {"GETSCANHOMETIME", drv_cmd_get_scan_home_time},
6994 {"SETROAMINTRABAND", drv_cmd_set_roam_intra_band},
6995 {"GETROAMINTRABAND", drv_cmd_get_roam_intra_band},
6996 {"SETSCANNPROBES", drv_cmd_set_scan_n_probes},
6997 {"GETSCANNPROBES", drv_cmd_get_scan_n_probes},
6998 {"SETSCANHOMEAWAYTIME", drv_cmd_set_scan_home_away_time},
6999 {"GETSCANHOMEAWAYTIME", drv_cmd_get_scan_home_away_time},
7000 {"REASSOC", drv_cmd_reassoc},
7001 {"SETWESMODE", drv_cmd_set_wes_mode},
7002 {"GETWESMODE", drv_cmd_get_wes_mode},
7003 {"SETOPPORTUNISTICRSSIDIFF", drv_cmd_set_opportunistic_rssi_diff},
7004 {"GETOPPORTUNISTICRSSIDIFF", drv_cmd_get_opportunistic_rssi_diff},
7005 {"SETROAMRESCANRSSIDIFF", drv_cmd_set_roam_rescan_rssi_diff},
7006 {"GETROAMRESCANRSSIDIFF", drv_cmd_get_roam_rescan_rssi_diff},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007007 {"SETFASTROAM", drv_cmd_set_fast_roam},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007008 {"SETFASTTRANSITION", drv_cmd_set_fast_transition},
7009 {"FASTREASSOC", drv_cmd_fast_reassoc},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007010 {"SETROAMSCANCONTROL", drv_cmd_set_roam_scan_control},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007011 {"SETOKCMODE", drv_cmd_set_okc_mode},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007012 {"GETROAMSCANCONTROL", drv_cmd_get_roam_scan_control},
7013 {"BTCOEXMODE", drv_cmd_bt_coex_mode},
7014 {"SCAN-ACTIVE", drv_cmd_scan_active},
7015 {"SCAN-PASSIVE", drv_cmd_scan_passive},
7016 {"GETDWELLTIME", drv_cmd_get_dwell_time},
7017 {"SETDWELLTIME", drv_cmd_set_dwell_time},
7018 {"MIRACAST", drv_cmd_miracast},
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08007019 {"SETIBSSBEACONOUIDATA", drv_cmd_set_ibss_beacon_oui_data},
7020 {"SETRMCENABLE", drv_cmd_set_rmc_enable},
7021 {"SETRMCACTIONPERIOD", drv_cmd_set_rmc_action_period},
7022 {"GETIBSSPEERINFOALL", drv_cmd_get_ibss_peer_info_all},
7023 {"GETIBSSPEERINFO", drv_cmd_get_ibss_peer_info},
7024 {"SETRMCTXRATE", drv_cmd_set_rmc_tx_rate},
7025 {"SETIBSSTXFAILEVENT", drv_cmd_set_ibss_tx_fail_event},
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08007026#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007027 {"SETCCXROAMSCANCHANNELS", drv_cmd_set_ccx_roam_scan_channels},
7028 {"GETTSMSTATS", drv_cmd_get_tsm_stats},
7029 {"SETCCKMIE", drv_cmd_set_cckm_ie},
7030 {"CCXBEACONREQ", drv_cmd_ccx_beacon_req},
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08007031#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007032 {"SETMCRATE", drv_cmd_set_mc_rate},
7033 {"MAXTXPOWER", drv_cmd_max_tx_power},
7034 {"SETDFSSCANMODE", drv_cmd_set_dfs_scan_mode},
7035 {"GETDFSSCANMODE", drv_cmd_get_dfs_scan_mode},
7036 {"GETLINKSTATUS", drv_cmd_get_link_status},
7037#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
7038 {"ENABLEEXTWOW", drv_cmd_enable_ext_wow},
7039 {"SETAPP1PARAMS", drv_cmd_set_app1_params},
7040 {"SETAPP2PARAMS", drv_cmd_set_app2_params},
7041#endif
7042#ifdef FEATURE_WLAN_TDLS
7043 {"TDLSSECONDARYCHANNELOFFSET", drv_cmd_tdls_secondary_channel_offset},
7044 {"TDLSOFFCHANNELMODE", drv_cmd_tdls_off_channel_mode},
7045 {"TDLSOFFCHANNEL", drv_cmd_tdls_off_channel},
7046 {"TDLSSCAN", drv_cmd_tdls_scan},
7047#endif
7048 {"RSSI", drv_cmd_get_rssi},
7049 {"LINKSPEED", drv_cmd_get_linkspeed},
7050#ifdef FEATURE_NAPI
7051 {"NAPI", drv_cmd_napi},
7052#endif /* FEATURE_NAPI */
7053 {"RXFILTER-REMOVE", drv_cmd_rx_filter_remove},
7054 {"RXFILTER-ADD", drv_cmd_rx_filter_add},
7055 {"SET_FCC_CHANNEL", drv_cmd_set_fcc_channel},
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307056 {"CHANNEL_SWITCH", drv_cmd_set_channel_switch},
Archana Ramachandran393f3792015-11-13 17:13:21 -08007057 {"SETANTENNAMODE", drv_cmd_set_antenna_mode},
7058 {"GETANTENNAMODE", drv_cmd_get_antenna_mode},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007059};
7060
7061/**
7062 * hdd_drv_cmd_process() - chooses and runs the proper
7063 * handler based on the input command
7064 * @adapter: Pointer to the hdd adapter
7065 * @cmd: Pointer to the driver command
7066 * @priv_data: Pointer to the data associated with the command
7067 *
7068 * This function parses the input hdd driver command and runs
7069 * the proper handler
7070 *
7071 * Return: 0 for success non-zero for failure
7072 */
7073static int hdd_drv_cmd_process(hdd_adapter_t *adapter,
7074 uint8_t *cmd,
7075 hdd_priv_data_t *priv_data)
7076{
7077 hdd_context_t *hdd_ctx;
7078 int i;
7079 const int cmd_num_total = ARRAY_SIZE(hdd_drv_cmds);
7080 uint8_t *cmd_i = NULL;
7081 hdd_drv_cmd_handler_t handler = NULL;
7082 int len = 0;
7083
7084 if (!adapter || !cmd || !priv_data) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007085 hdd_err("at least 1 param is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007086 return -EINVAL;
7087 }
7088
7089 hdd_ctx = (hdd_context_t *)adapter->pHddCtx;
7090
7091 for (i = 0; i < cmd_num_total; i++) {
7092
7093 cmd_i = (uint8_t *)hdd_drv_cmds[i].cmd;
7094 handler = hdd_drv_cmds[i].handler;
7095 len = strlen(cmd_i);
7096
7097 if (!handler) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007098 hdd_err("no. %d handler is NULL", i);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007099 return -EINVAL;
7100 }
7101
7102 if (strncasecmp(cmd, cmd_i, len) == 0)
7103 return handler(adapter, hdd_ctx,
7104 cmd, len, priv_data);
7105 }
7106
7107 return drv_cmd_invalid(adapter, hdd_ctx, cmd, len, priv_data);
7108}
7109
7110/**
7111 * hdd_driver_command() - top level wlan hdd driver command handler
7112 * @adapter: Pointer to the hdd adapter
7113 * @priv_data: Pointer to the raw command data
7114 *
7115 * This function is the top level wlan hdd driver command handler. It
7116 * handles the command with the help of hdd_drv_cmd_process()
7117 *
7118 * Return: 0 for success non-zero for failure
7119 */
7120static int hdd_driver_command(hdd_adapter_t *adapter,
7121 hdd_priv_data_t *priv_data)
7122{
7123 uint8_t *command = NULL;
7124 int ret = 0;
7125
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307126 ENTER();
7127
Anurag Chouhan6d760662016-02-20 16:05:43 +05307128 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007129 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007130 return -EINVAL;
7131 }
7132
7133 /*
7134 * Note that valid pointers are provided by caller
7135 */
7136
7137 /* copy to local struct to avoid numerous changes to legacy code */
7138 if (priv_data->total_len <= 0 ||
7139 priv_data->total_len > WLAN_PRIV_DATA_MAX_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007140 hdd_warn("Invalid priv_data.total_len(%d)!!!",
7141 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007142 ret = -EINVAL;
7143 goto exit;
7144 }
7145
7146 /* Allocate +1 for '\0' */
7147 command = kmalloc(priv_data->total_len + 1, GFP_KERNEL);
7148 if (!command) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007149 hdd_err("failed to allocate memory");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007150 ret = -ENOMEM;
7151 goto exit;
7152 }
7153
7154 if (copy_from_user(command, priv_data->buf, priv_data->total_len)) {
7155 ret = -EFAULT;
7156 goto exit;
7157 }
7158
7159 /* Make sure the command is NUL-terminated */
7160 command[priv_data->total_len] = '\0';
7161
7162 hdd_info("%s: %s", adapter->dev->name, command);
7163 ret = hdd_drv_cmd_process(adapter, command, priv_data);
7164
7165exit:
7166 if (command)
7167 kfree(command);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307168 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007169 return ret;
7170}
7171
7172#ifdef CONFIG_COMPAT
7173static int hdd_driver_compat_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
7174{
7175 struct {
7176 compat_uptr_t buf;
7177 int used_len;
7178 int total_len;
7179 } compat_priv_data;
7180 hdd_priv_data_t priv_data;
7181 int ret = 0;
7182
7183 /*
7184 * Note that adapter and ifr have already been verified by caller,
7185 * and HDD context has also been validated
7186 */
7187 if (copy_from_user(&compat_priv_data, ifr->ifr_data,
7188 sizeof(compat_priv_data))) {
7189 ret = -EFAULT;
7190 goto exit;
7191 }
7192 priv_data.buf = compat_ptr(compat_priv_data.buf);
7193 priv_data.used_len = compat_priv_data.used_len;
7194 priv_data.total_len = compat_priv_data.total_len;
7195 ret = hdd_driver_command(adapter, &priv_data);
7196exit:
7197 return ret;
7198}
7199#else /* CONFIG_COMPAT */
7200static int hdd_driver_compat_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
7201{
7202 /* will never be invoked */
7203 return 0;
7204}
7205#endif /* CONFIG_COMPAT */
7206
7207static int hdd_driver_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
7208{
7209 hdd_priv_data_t priv_data;
7210 int ret = 0;
7211
7212 /*
7213 * Note that adapter and ifr have already been verified by caller,
7214 * and HDD context has also been validated
7215 */
7216 if (copy_from_user(&priv_data, ifr->ifr_data, sizeof(priv_data)))
7217 ret = -EFAULT;
7218 else
7219 ret = hdd_driver_command(adapter, &priv_data);
7220
7221 return ret;
7222}
7223
7224/**
7225 * __hdd_ioctl() - ioctl handler for wlan network interfaces
7226 * @dev: device upon which the ioctl was received
7227 * @ifr: ioctl request information
7228 * @cmd: ioctl command
7229 *
7230 * This function does initial processing of wlan device ioctls.
7231 * Currently two flavors of ioctls are supported. The primary ioctl
7232 * that is supported is the (SIOCDEVPRIVATE + 1) ioctl which is used
7233 * for Android "DRIVER" commands. The other ioctl that is
7234 * conditionally supported is the SIOCIOCTLTX99 ioctl which is used
7235 * for FTM on some platforms. This function simply verifies that the
7236 * driver is in a sane state, and that the ioctl is one of the
7237 * supported flavors, in which case flavor-specific handlers are
7238 * dispatched.
7239 *
7240 * Return: 0 on success, non-zero on error
7241 */
7242static int __hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7243{
7244 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
7245 hdd_context_t *hdd_ctx;
7246 int ret;
7247
Jeff Johnson3c3994a2016-02-11 08:12:30 -08007248 ENTER_DEV(dev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307249
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007250 if (dev != adapter->dev) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007251 hdd_alert("HDD adapter/dev inconsistency");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007252 ret = -ENODEV;
7253 goto exit;
7254 }
7255
7256 if ((!ifr) || (!ifr->ifr_data)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007257 hdd_err("invalid data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007258 ret = -EINVAL;
7259 goto exit;
7260 }
7261#if defined(QCA_WIFI_FTM) && defined(LINUX_QCMBR)
Anurag Chouhan6d760662016-02-20 16:05:43 +05307262 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007263 if (SIOCIOCTLTX99 == cmd) {
7264 ret = wlan_hdd_qcmbr_unified_ioctl(adapter, ifr);
7265 goto exit;
7266 }
7267 }
7268#endif
7269
7270 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
7271 ret = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307272 if (ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007273 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007274
7275 switch (cmd) {
7276 case (SIOCDEVPRIVATE + 1):
7277 if (is_compat_task())
7278 ret = hdd_driver_compat_ioctl(adapter, ifr);
7279 else
7280 ret = hdd_driver_ioctl(adapter, ifr);
7281 break;
7282 default:
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007283 hdd_err("unknown ioctl %d", cmd);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007284 ret = -EINVAL;
7285 break;
7286 }
7287exit:
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307288 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007289 return ret;
7290}
7291
7292/**
7293 * hdd_ioctl() - ioctl handler (wrapper) for wlan network interfaces
7294 * @dev: device upon which the ioctl was received
7295 * @ifr: ioctl request information
7296 * @cmd: ioctl command
7297 *
7298 * This function acts as an SSR-protecting wrapper to __hdd_ioctl()
7299 * which is where the ioctls are really handled.
7300 *
7301 * Return: 0 on success, non-zero on error
7302 */
7303int hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7304{
7305 int ret;
7306
7307 cds_ssr_protect(__func__);
7308 ret = __hdd_ioctl(dev, ifr, cmd);
7309 cds_ssr_unprotect(__func__);
7310 return ret;
7311}