blob: e08879e1a6f8ed2f1b34b7c8f64cadffc8fd90db [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 */
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530449 if (pPeerInfo->numPeers > SIR_MAX_NUM_STA_IN_IBSS) {
450 hdd_warn("Limiting num_peers %u to %u",
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700451 pPeerInfo->numPeers, SIR_MAX_NUM_STA_IN_IBSS);
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530452 pPeerInfo->numPeers = SIR_MAX_NUM_STA_IN_IBSS;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800453 }
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530454 pStaCtx->ibss_peer_info.status = pPeerInfo->status;
455 pStaCtx->ibss_peer_info.numPeers = pPeerInfo->numPeers;
456
457 for (i = 0; i < pPeerInfo->numPeers; i++)
458 pStaCtx->ibss_peer_info.peerInfoParams[i] =
459 pPeerInfo->peerInfoParams[i];
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800460 } else {
Sriram Madhvapathi58f0e272016-10-03 11:47:51 +0530461 hdd_err("peerInfo %s: status %u, numPeers %u",
462 pPeerInfo ? "valid" : "null",
463 pPeerInfo ? pPeerInfo->status : QDF_STATUS_E_FAILURE,
464 pPeerInfo ? pPeerInfo->numPeers : 0);
465 pStaCtx->ibss_peer_info.numPeers = 0;
466 pStaCtx->ibss_peer_info.status = QDF_STATUS_E_FAILURE;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800467 }
468
469 complete(&adapter->ibss_peer_info_comp);
470}
471
472/**
473 * hdd_cfg80211_get_ibss_peer_info_all() - get ibss peers' info
474 * @adapter: Adapter context
475 *
476 * Request function to get IBSS peer info from lower layers
477 *
478 * Return: 0 for success non-zero for failure
479 */
480static
481QDF_STATUS hdd_cfg80211_get_ibss_peer_info_all(hdd_adapter_t *adapter)
482{
483 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
484 QDF_STATUS retStatus = QDF_STATUS_E_FAILURE;
485 unsigned long rc;
486
487 INIT_COMPLETION(adapter->ibss_peer_info_comp);
488
489 retStatus = sme_request_ibss_peer_info(hHal, adapter,
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700490 hdd_get_ibss_peer_info_cb,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800491 true, 0xFF);
492
493 if (QDF_STATUS_SUCCESS == retStatus) {
494 rc = wait_for_completion_timeout
495 (&adapter->ibss_peer_info_comp,
496 msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT));
497
498 /* status will be 0 if timed out */
499 if (!rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700500 hdd_warn("Warning: IBSS_PEER_INFO_TIMEOUT");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800501 retStatus = QDF_STATUS_E_FAILURE;
502 return retStatus;
503 }
504 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700505 hdd_warn("Warning: sme_request_ibss_peer_info Request failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800506 }
507
508 return retStatus;
509}
510
511/**
512 * hdd_cfg80211_get_ibss_peer_info() - get ibss peer info
513 * @adapter: Adapter context
514 * @staIdx: Sta index for which the peer info is requested
515 *
516 * Request function to get IBSS peer info from lower layers
517 *
518 * Return: 0 for success non-zero for failure
519 */
520static QDF_STATUS
521hdd_cfg80211_get_ibss_peer_info(hdd_adapter_t *adapter, uint8_t staIdx)
522{
523 unsigned long rc;
524 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
525 QDF_STATUS retStatus = QDF_STATUS_E_FAILURE;
526
527 INIT_COMPLETION(adapter->ibss_peer_info_comp);
528
529 retStatus = sme_request_ibss_peer_info(hHal, adapter,
Rajeev Kumar94c9b452016-03-24 12:58:47 -0700530 hdd_get_ibss_peer_info_cb,
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800531 false, staIdx);
532
533 if (QDF_STATUS_SUCCESS == retStatus) {
534 rc = wait_for_completion_timeout(
535 &adapter->ibss_peer_info_comp,
536 msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT));
537
538 /* status = 0 on timeout */
539 if (!rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700540 hdd_warn("Warning: IBSS_PEER_INFO_TIMEOUT");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800541 retStatus = QDF_STATUS_E_FAILURE;
542 return retStatus;
543 }
544 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700545 hdd_warn("Warning: sme_request_ibss_peer_info Request failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800546 }
547
548 return retStatus;
549}
550
551/* Function header is left blank intentionally */
Jeff Johnsonf731b302016-10-05 16:00:55 -0700552static QDF_STATUS
Rajeev Kumar8e3e2832015-11-06 16:02:54 -0800553hdd_parse_get_ibss_peer_info(uint8_t *pValue, struct qdf_mac_addr *pPeerMacAddr)
554{
555 uint8_t *inPtr = pValue;
556 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
557
558 if (NULL == inPtr) {
559 return QDF_STATUS_E_FAILURE;;
560 }
561
562 else if (SPACE_ASCII_VALUE != *inPtr) {
563 return QDF_STATUS_E_FAILURE;;
564 }
565
566 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
567 inPtr++;
568
569 if ('\0' == *inPtr) {
570 return QDF_STATUS_E_FAILURE;;
571 }
572
573 if (inPtr[2] != ':' || inPtr[5] != ':' || inPtr[8] != ':' ||
574 inPtr[11] != ':' || inPtr[14] != ':') {
575 return QDF_STATUS_E_FAILURE;;
576 }
577 sscanf(inPtr, "%2x:%2x:%2x:%2x:%2x:%2x",
578 (unsigned int *)&pPeerMacAddr->bytes[0],
579 (unsigned int *)&pPeerMacAddr->bytes[1],
580 (unsigned int *)&pPeerMacAddr->bytes[2],
581 (unsigned int *)&pPeerMacAddr->bytes[3],
582 (unsigned int *)&pPeerMacAddr->bytes[4],
583 (unsigned int *)&pPeerMacAddr->bytes[5]);
584
585 return QDF_STATUS_SUCCESS;
586}
587
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800588static void hdd_get_band_helper(hdd_context_t *hdd_ctx, int *pBand)
589{
590 eCsrBand band = -1;
591 sme_get_freq_band((tHalHandle) (hdd_ctx->hHal), &band);
592 switch (band) {
593 case eCSR_BAND_ALL:
594 *pBand = WLAN_HDD_UI_BAND_AUTO;
595 break;
596
597 case eCSR_BAND_24:
598 *pBand = WLAN_HDD_UI_BAND_2_4_GHZ;
599 break;
600
601 case eCSR_BAND_5G:
602 *pBand = WLAN_HDD_UI_BAND_5_GHZ;
603 break;
604
605 default:
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700606 hdd_warn("Invalid Band %d", band);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800607 *pBand = -1;
608 break;
609 }
610}
611
612/**
613 * _hdd_parse_bssid_and_chan() - helper function to parse bssid and channel
614 * @data: input data
615 * @target_ap_bssid: pointer to bssid (output parameter)
616 * @channel: pointer to channel (output parameter)
617 *
618 * Return: 0 if parsing is successful; -EINVAL otherwise
619 */
620static int _hdd_parse_bssid_and_chan(const uint8_t **data,
621 uint8_t *bssid,
622 uint8_t *channel)
623{
624 const uint8_t *in_ptr;
625 int v = 0;
626 int temp_int;
627 uint8_t temp_buf[32];
628
629 /* 12 hexa decimal digits, 5 ':' and '\0' */
630 uint8_t mac_addr[18];
631
632 if (!data || !*data)
633 return -EINVAL;
634
635 in_ptr = *data;
636
637 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
638 /* no argument after the command */
639 if (NULL == in_ptr)
640 goto error;
641 /* no space after the command */
642 else if (SPACE_ASCII_VALUE != *in_ptr)
643 goto error;
644
645 /* remove empty spaces */
646 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
647 in_ptr++;
648
649 /* no argument followed by spaces */
650 if ('\0' == *in_ptr)
651 goto error;
652
653 v = sscanf(in_ptr, "%17s", mac_addr);
654 if (!((1 == v) && hdd_is_valid_mac_address(mac_addr))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700655 hdd_err("Invalid MAC address or All hex inputs are not read (%d)",
656 v);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800657 goto error;
658 }
659
660 bssid[0] = hex_to_bin(mac_addr[0]) << 4 |
661 hex_to_bin(mac_addr[1]);
662 bssid[1] = hex_to_bin(mac_addr[3]) << 4 |
663 hex_to_bin(mac_addr[4]);
664 bssid[2] = hex_to_bin(mac_addr[6]) << 4 |
665 hex_to_bin(mac_addr[7]);
666 bssid[3] = hex_to_bin(mac_addr[9]) << 4 |
667 hex_to_bin(mac_addr[10]);
668 bssid[4] = hex_to_bin(mac_addr[12]) << 4 |
669 hex_to_bin(mac_addr[13]);
670 bssid[5] = hex_to_bin(mac_addr[15]) << 4 |
671 hex_to_bin(mac_addr[16]);
672
673 /* point to the next argument */
674 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
675 /* no argument after the command */
676 if (NULL == in_ptr)
677 goto error;
678
679 /* remove empty spaces */
680 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
681 in_ptr++;
682
683 /* no argument followed by spaces */
684 if ('\0' == *in_ptr)
685 goto error;
686
687 /* get the next argument ie the channel number */
688 v = sscanf(in_ptr, "%31s ", temp_buf);
689 if (1 != v)
690 goto error;
691
692 v = kstrtos32(temp_buf, 10, &temp_int);
693 if ((v < 0) || (temp_int < 0) ||
694 (temp_int > WNI_CFG_CURRENT_CHANNEL_STAMAX))
695 return -EINVAL;
696
697 *channel = temp_int;
698 *data = in_ptr;
699 return 0;
700error:
701 *data = in_ptr;
702 return -EINVAL;
703}
704
705/**
706 * hdd_parse_send_action_frame_data() - HDD Parse send action frame data
707 * @pValue: Pointer to input data
708 * @pTargetApBssid: Pointer to target Ap bssid
709 * @pChannel: Pointer to the Target AP channel
710 * @pDwellTime: Pointer to the time to stay off-channel
711 * after transmitting action frame
712 * @pBuf: Pointer to data
713 * @pBufLen: Pointer to data length
714 *
715 * This function parses the send action frame data passed in the format
716 * SENDACTIONFRAME<space><bssid><space><channel><space><dwelltime><space><data>
717 *
718 * Return: 0 for success non-zero for failure
719 */
720static int
721hdd_parse_send_action_frame_v1_data(const uint8_t *pValue,
722 uint8_t *pTargetApBssid,
723 uint8_t *pChannel, uint8_t *pDwellTime,
724 uint8_t **pBuf, uint8_t *pBufLen)
725{
726 const uint8_t *inPtr = pValue;
727 const uint8_t *dataEnd;
728 int tempInt;
729 int j = 0;
730 int i = 0;
731 int v = 0;
732 uint8_t tempBuf[32];
733 uint8_t tempByte = 0;
734
735 if (_hdd_parse_bssid_and_chan(&inPtr, pTargetApBssid, pChannel))
736 return -EINVAL;
737
738 /* point to the next argument */
739 inPtr = strnchr(inPtr, strlen(inPtr), SPACE_ASCII_VALUE);
740 /* no argument after the command */
741 if (NULL == inPtr)
742 return -EINVAL;
743 /* removing empty spaces */
744 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
745 inPtr++;
746
747 /* no argument followed by spaces */
748 if ('\0' == *inPtr) {
749 return -EINVAL;
750 }
751
752 /* getting the next argument ie the dwell time */
753 v = sscanf(inPtr, "%31s ", tempBuf);
754 if (1 != v)
755 return -EINVAL;
756
757 v = kstrtos32(tempBuf, 10, &tempInt);
758 if (v < 0 || tempInt < 0)
759 return -EINVAL;
760
761 *pDwellTime = tempInt;
762
763 /* point to the next argument */
764 inPtr = strnchr(inPtr, strlen(inPtr), SPACE_ASCII_VALUE);
765 /* no argument after the command */
766 if (NULL == inPtr)
767 return -EINVAL;
768 /* removing empty spaces */
769 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
770 inPtr++;
771
772 /* no argument followed by spaces */
773 if ('\0' == *inPtr) {
774 return -EINVAL;
775 }
776
777 /* find the length of data */
778 dataEnd = inPtr;
779 while (('\0' != *dataEnd)) {
780 dataEnd++;
781 }
782 *pBufLen = dataEnd - inPtr;
783 if (*pBufLen <= 0)
784 return -EINVAL;
785
786 /*
787 * Allocate the number of bytes based on the number of input characters
788 * whether it is even or odd.
789 * if the number of input characters are even, then we need N/2 byte.
790 * if the number of input characters are odd, then we need do (N+1)/2
791 * to compensate rounding off.
792 * For example, if N = 18, then (18 + 1)/2 = 9 bytes are enough.
793 * If N = 19, then we need 10 bytes, hence (19 + 1)/2 = 10 bytes
794 */
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530795 *pBuf = qdf_mem_malloc((*pBufLen + 1) / 2);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800796 if (NULL == *pBuf) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700797 hdd_err("qdf_mem_malloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800798 return -ENOMEM;
799 }
800
801 /* the buffer received from the upper layer is character buffer,
802 * we need to prepare the buffer taking 2 characters in to a U8 hex
803 * decimal number for example 7f0000f0...form a buffer to contain 7f
804 * in 0th location, 00 in 1st and f0 in 3rd location
805 */
806 for (i = 0, j = 0; j < *pBufLen; j += 2) {
807 if (j + 1 == *pBufLen) {
808 tempByte = hex_to_bin(inPtr[j]);
809 } else {
810 tempByte =
811 (hex_to_bin(inPtr[j]) << 4) |
812 (hex_to_bin(inPtr[j + 1]));
813 }
814 (*pBuf)[i++] = tempByte;
815 }
816 *pBufLen = i;
817 return 0;
818}
819
820/**
821 * hdd_parse_reassoc_command_data() - HDD Parse reassoc command data
822 * @pValue: Pointer to input data (its a NULL terminated string)
823 * @pTargetApBssid: Pointer to target Ap bssid
824 * @pChannel: Pointer to the Target AP channel
825 *
826 * This function parses the reasoc command data passed in the format
827 * REASSOC<space><bssid><space><channel>
828 *
829 * Return: 0 for success non-zero for failure
830 */
831static int hdd_parse_reassoc_command_v1_data(const uint8_t *pValue,
832 uint8_t *pTargetApBssid,
833 uint8_t *pChannel)
834{
835 const uint8_t *inPtr = pValue;
836
837 if (_hdd_parse_bssid_and_chan(&inPtr, pTargetApBssid, pChannel))
838 return -EINVAL;
839
840 return 0;
841}
842
Naveen Rawat05376ee2016-07-18 16:43:32 -0700843#ifdef WLAN_FEATURE_ROAM_OFFLOAD
844void hdd_wma_send_fastreassoc_cmd(int sessionId, const tSirMacAddr bssid,
845 int channel)
846{
847 struct wma_roam_invoke_cmd *fastreassoc;
848 cds_msg_t msg = {0};
849
850 fastreassoc = qdf_mem_malloc(sizeof(*fastreassoc));
851 if (NULL == fastreassoc) {
852 hdd_err("qdf_mem_malloc failed for fastreassoc");
853 return;
854 }
855 fastreassoc->vdev_id = sessionId;
856 fastreassoc->channel = channel;
857 fastreassoc->bssid[0] = bssid[0];
858 fastreassoc->bssid[1] = bssid[1];
859 fastreassoc->bssid[2] = bssid[2];
860 fastreassoc->bssid[3] = bssid[3];
861 fastreassoc->bssid[4] = bssid[4];
862 fastreassoc->bssid[5] = bssid[5];
863
864 msg.type = SIR_HAL_ROAM_INVOKE;
865 msg.reserved = 0;
866 msg.bodyptr = fastreassoc;
867 if (QDF_STATUS_SUCCESS != cds_mq_post_message(QDF_MODULE_ID_WMA,
868 &msg)) {
869 qdf_mem_free(fastreassoc);
870 hdd_err("Not able to post ROAM_INVOKE_CMD message to WMA");
871 }
872}
Naveen Rawat05376ee2016-07-18 16:43:32 -0700873#endif
874
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800875/**
876 * hdd_reassoc() - perform a userspace-directed reassoc
877 * @adapter: Adapter upon which the command was received
878 * @bssid: BSSID with which to reassociate
879 * @channel: channel upon which to reassociate
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700880 * @src: The source for the trigger of this action
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800881 *
882 * This function performs a userspace-directed reassoc operation
883 *
884 * Return: 0 for success non-zero for failure
885 */
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700886int hdd_reassoc(hdd_adapter_t *adapter, const uint8_t *bssid,
887 const uint8_t channel, const handoff_src src)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800888{
889 hdd_station_ctx_t *pHddStaCtx;
Naveen Rawat05376ee2016-07-18 16:43:32 -0700890 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800891 int ret = 0;
892
Naveen Rawat05376ee2016-07-18 16:43:32 -0700893 if (hdd_ctx == NULL) {
894 hdd_err("Invalid hdd ctx");
895 return -EINVAL;
896 }
897
Krunal Sonibe766b02016-03-10 13:00:44 -0800898 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800899 hdd_warn("Unsupported in mode %s(%d)",
900 hdd_device_mode_to_string(adapter->device_mode),
901 adapter->device_mode);
902 return -EINVAL;
903 }
904
905 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
906
907 /* if not associated, no need to proceed with reassoc */
908 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700909 hdd_info("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800910 ret = -EINVAL;
911 goto exit;
912 }
913
914 /*
915 * if the target bssid is same as currently associated AP,
916 * then no need to proceed with reassoc
917 */
918 if (!memcmp(bssid, pHddStaCtx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530919 QDF_MAC_ADDR_SIZE)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700920 hdd_info("Reassoc BSSID is same as currently associated AP bssid");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800921 ret = -EINVAL;
922 goto exit;
923 }
924
925 /* Check channel number is a valid channel number */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530926 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800927 wlan_hdd_validate_operation_channel(adapter, channel)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700928 hdd_err("Invalid Channel %d", channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800929 ret = -EINVAL;
930 goto exit;
931 }
932
933 /* Proceed with reassoc */
Naveen Rawat05376ee2016-07-18 16:43:32 -0700934 if (roaming_offload_enabled(hdd_ctx)) {
935 hdd_wma_send_fastreassoc_cmd((int)adapter->sessionId,
936 bssid, (int)channel);
937 } else {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800938 tCsrHandoffRequest handoffInfo;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800939
940 handoffInfo.channel = channel;
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700941 handoffInfo.src = src;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530942 qdf_mem_copy(handoffInfo.bssid.bytes, bssid, QDF_MAC_ADDR_SIZE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800943 sme_handoff_request(hdd_ctx->hHal, adapter->sessionId,
944 &handoffInfo);
945 }
946exit:
947 return ret;
948}
949
950/**
951 * hdd_parse_reassoc_v1() - parse version 1 of the REASSOC command
952 * @adapter: Adapter upon which the command was received
953 * @command: ASCII text command that was received
954 *
955 * This function parses the v1 REASSOC command with the format
956 *
957 * REASSOC xx:xx:xx:xx:xx:xx CH
958 *
959 * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the
960 * BSSID and CH is the ASCII representation of the channel. For
961 * example
962 *
963 * REASSOC 00:0a:0b:11:22:33 48
964 *
965 * Return: 0 for success non-zero for failure
966 */
967static int hdd_parse_reassoc_v1(hdd_adapter_t *adapter, const char *command)
968{
969 uint8_t channel = 0;
970 tSirMacAddr bssid;
971 int ret;
972
973 ret = hdd_parse_reassoc_command_v1_data(command, bssid, &channel);
974 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -0700975 hdd_err("Failed to parse reassoc command data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800976 } else {
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -0700977 ret = hdd_reassoc(adapter, bssid, channel, REASSOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800978 }
979 return ret;
980}
981
982/**
983 * hdd_parse_reassoc_v2() - parse version 2 of the REASSOC command
984 * @adapter: Adapter upon which the command was received
985 * @command: Command that was received, ASCII command
986 * followed by binary data
987 *
988 * This function parses the v2 REASSOC command with the format
989 *
990 * REASSOC <android_wifi_reassoc_params>
991 *
992 * Return: 0 for success non-zero for failure
993 */
994static int hdd_parse_reassoc_v2(hdd_adapter_t *adapter, const char *command)
995{
996 struct android_wifi_reassoc_params params;
997 tSirMacAddr bssid;
998 int ret;
999
1000 /* The params are located after "REASSOC " */
1001 memcpy(&params, command + 8, sizeof(params));
1002
1003 if (!mac_pton(params.bssid, (u8 *) &bssid)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001004 hdd_err("MAC address parsing failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001005 ret = -EINVAL;
1006 } else {
Varun Reddy Yeturu3e91dad2016-07-18 15:58:47 -07001007 ret = hdd_reassoc(adapter, bssid, params.channel, REASSOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001008 }
1009 return ret;
1010}
1011
1012/**
1013 * hdd_parse_reassoc() - parse the REASSOC command
1014 * @adapter: Adapter upon which the command was received
1015 * @command: Command that was received
1016 *
1017 * There are two different versions of the REASSOC command. Version 1
1018 * of the command contains a parameter list that is ASCII characters
1019 * whereas version 2 contains a combination of ASCII and binary
1020 * payload. Determine if a version 1 or a version 2 command is being
1021 * parsed by examining the parameters, and then dispatch the parser
1022 * that is appropriate for the command.
1023 *
1024 * Return: 0 for success non-zero for failure
1025 */
1026static int hdd_parse_reassoc(hdd_adapter_t *adapter, const char *command)
1027{
1028 int ret;
1029
1030 /* both versions start with "REASSOC "
1031 * v1 has a bssid and channel # as an ASCII string
1032 * REASSOC xx:xx:xx:xx:xx:xx CH
1033 * v2 has a C struct
1034 * REASSOC <binary c struct>
1035 *
1036 * The first field in the v2 struct is also the bssid in ASCII.
1037 * But in the case of a v2 message the BSSID is NUL-terminated.
1038 * Hence we can peek at that offset to see if this is V1 or V2
1039 * REASSOC xx:xx:xx:xx:xx:xx*
1040 * 1111111111222222
1041 * 01234567890123456789012345
1042 */
1043 if (command[25]) {
1044 ret = hdd_parse_reassoc_v1(adapter, command);
1045 } else {
1046 ret = hdd_parse_reassoc_v2(adapter, command);
1047 }
1048
1049 return ret;
1050}
1051
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001052/**
1053 * hdd_sendactionframe() - send a userspace-supplied action frame
1054 * @adapter: Adapter upon which the command was received
1055 * @bssid: BSSID target of the action frame
1056 * @channel: Channel upon which to send the frame
1057 * @dwell_time: Amount of time to dwell when the frame is sent
1058 * @payload_len:Length of the payload
1059 * @payload: Payload of the frame
1060 *
1061 * This function sends a userspace-supplied action frame
1062 *
1063 * Return: 0 for success non-zero for failure
1064 */
1065static int
1066hdd_sendactionframe(hdd_adapter_t *adapter, const uint8_t *bssid,
1067 const uint8_t channel, const uint8_t dwell_time,
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001068 const int payload_len, const uint8_t *payload)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001069{
1070 struct ieee80211_channel chan;
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001071 int frame_len, ret = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001072 uint8_t *frame;
1073 struct ieee80211_hdr_3addr *hdr;
1074 u64 cookie;
1075 hdd_station_ctx_t *pHddStaCtx;
1076 hdd_context_t *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001077 tpSirMacVendorSpecificFrameHdr pVendorSpecific =
1078 (tpSirMacVendorSpecificFrameHdr) payload;
1079#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
1080 struct cfg80211_mgmt_tx_params params;
1081#endif
1082
Krunal Sonibe766b02016-03-10 13:00:44 -08001083 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001084 hdd_warn("Unsupported in mode %s(%d)",
1085 hdd_device_mode_to_string(adapter->device_mode),
1086 adapter->device_mode);
1087 return -EINVAL;
1088 }
1089
1090 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
1091 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1092
1093 /* if not associated, no need to send action frame */
1094 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001095 hdd_info("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001096 ret = -EINVAL;
1097 goto exit;
1098 }
1099
1100 /*
1101 * if the target bssid is different from currently associated AP,
1102 * then no need to send action frame
1103 */
1104 if (memcmp(bssid, pHddStaCtx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05301105 QDF_MAC_ADDR_SIZE)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001106 hdd_info("STA is not associated to this AP");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001107 ret = -EINVAL;
1108 goto exit;
1109 }
1110
1111 chan.center_freq = sme_chn_to_freq(channel);
1112 /* Check if it is specific action frame */
1113 if (pVendorSpecific->category ==
1114 SIR_MAC_ACTION_VENDOR_SPECIFIC_CATEGORY) {
1115 static const uint8_t Oui[] = { 0x00, 0x00, 0xf0 };
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301116 if (!qdf_mem_cmp(pVendorSpecific->Oui, (void *)Oui, 3)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001117 /*
1118 * if the channel number is different from operating
1119 * channel then no need to send action frame
1120 */
1121 if (channel != 0) {
1122 if (channel !=
1123 pHddStaCtx->conn_info.operationChannel) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001124 hdd_info("channel(%d) is different from operating channel(%d)",
1125 channel,
1126 pHddStaCtx->conn_info.
1127 operationChannel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001128 ret = -EINVAL;
1129 goto exit;
1130 }
1131 /*
1132 * If channel number is specified and same
1133 * as home channel, ensure that action frame
1134 * is sent immediately by cancelling
1135 * roaming scans. Otherwise large dwell times
1136 * may cause long delays in sending action
1137 * frames.
1138 */
1139 sme_abort_roam_scan(hdd_ctx->hHal,
1140 adapter->sessionId);
1141 } else {
1142 /*
1143 * 0 is accepted as current home channel,
1144 * delayed transmission of action frame is ok.
1145 */
1146 chan.center_freq =
1147 sme_chn_to_freq(pHddStaCtx->conn_info.
1148 operationChannel);
1149 }
1150 }
1151 }
1152 if (chan.center_freq == 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001153 hdd_err("Invalid channel number %d", channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001154 ret = -EINVAL;
1155 goto exit;
1156 }
1157
1158 frame_len = payload_len + 24;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301159 frame = qdf_mem_malloc(frame_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001160 if (!frame) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001161 hdd_err("memory allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001162 ret = -ENOMEM;
1163 goto exit;
1164 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301165 qdf_mem_zero(frame, frame_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001166
1167 hdr = (struct ieee80211_hdr_3addr *)frame;
1168 hdr->frame_control =
1169 cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301170 qdf_mem_copy(hdr->addr1, bssid, QDF_MAC_ADDR_SIZE);
1171 qdf_mem_copy(hdr->addr2, adapter->macAddressCurrent.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05301172 QDF_MAC_ADDR_SIZE);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301173 qdf_mem_copy(hdr->addr3, bssid, QDF_MAC_ADDR_SIZE);
1174 qdf_mem_copy(hdr + 1, payload, payload_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001175
1176#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
1177 params.chan = &chan;
1178 params.offchan = 0;
1179 params.wait = dwell_time;
1180 params.buf = frame;
1181 params.len = frame_len;
1182 params.no_cck = 1;
1183 params.dont_wait_for_ack = 1;
1184 ret = wlan_hdd_mgmt_tx(NULL, &adapter->wdev, &params, &cookie);
1185#else
1186 ret = wlan_hdd_mgmt_tx(NULL,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001187 &(adapter->wdev),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001188 &chan, 0,
Amar Singhal01098f72015-10-08 11:55:32 -07001189
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001190 dwell_time, frame, frame_len, 1, 1, &cookie);
1191#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
1192
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301193 qdf_mem_free(frame);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001194exit:
1195 return ret;
1196}
1197
1198/**
1199 * hdd_parse_sendactionframe_v1() - parse version 1 of the
1200 * SENDACTIONFRAME command
1201 * @adapter: Adapter upon which the command was received
1202 * @command: ASCII text command that was received
1203 *
1204 * This function parses the v1 SENDACTIONFRAME command with the format
1205 *
1206 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DW xxxxxx
1207 *
1208 * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the
1209 * BSSID, CH is the ASCII representation of the channel, DW is the
1210 * ASCII representation of the dwell time, and xxxxxx is the Hex-ASCII
1211 * payload. For example
1212 *
1213 * SENDACTIONFRAME 00:0a:0b:11:22:33 48 40 aabbccddee
1214 *
1215 * Return: 0 for success non-zero for failure
1216 */
1217static int
1218hdd_parse_sendactionframe_v1(hdd_adapter_t *adapter, const char *command)
1219{
1220 uint8_t channel = 0;
1221 uint8_t dwell_time = 0;
1222 uint8_t payload_len = 0;
1223 uint8_t *payload = NULL;
1224 tSirMacAddr bssid;
1225 int ret;
1226
1227 ret = hdd_parse_send_action_frame_v1_data(command, bssid, &channel,
1228 &dwell_time, &payload,
1229 &payload_len);
1230 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001231 hdd_err("Failed to parse send action frame data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001232 } else {
1233 ret = hdd_sendactionframe(adapter, bssid, channel,
1234 dwell_time, payload_len, payload);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301235 qdf_mem_free(payload);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001236 }
1237
1238 return ret;
1239}
1240
1241/**
1242 * hdd_parse_sendactionframe_v2() - parse version 2 of the
1243 * SENDACTIONFRAME command
1244 * @adapter: Adapter upon which the command was received
1245 * @command: Command that was received, ASCII command
1246 * followed by binary data
1247 *
1248 * This function parses the v2 SENDACTIONFRAME command with the format
1249 *
1250 * SENDACTIONFRAME <android_wifi_af_params>
1251 *
1252 * Return: 0 for success non-zero for failure
1253 */
1254static int
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001255hdd_parse_sendactionframe_v2(hdd_adapter_t *adapter,
1256 const char *command, int total_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001257{
1258 struct android_wifi_af_params *params;
1259 tSirMacAddr bssid;
1260 int ret;
1261
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001262 /* The params are located after "SENDACTIONFRAME " */
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001263 total_len -= 16;
1264 params = (struct android_wifi_af_params *)(command + 16);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001265
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001266 if (params->len <= 0 || params->len > ANDROID_WIFI_ACTION_FRAME_SIZE ||
1267 (params->len > total_len)) {
1268 hdd_err("Invalid payload length: %d", params->len);
1269 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001270 }
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001271
1272 if (!mac_pton(params->bssid, (u8 *)&bssid)) {
1273 hdd_err("MAC address parsing failed");
1274 return -EINVAL;
1275 }
1276
1277 if (params->channel < 0 ||
1278 params->channel > WNI_CFG_CURRENT_CHANNEL_STAMAX) {
1279 hdd_err("Invalid channel: %d", params->channel);
1280 return -EINVAL;
1281 }
1282
1283 if (params->dwell_time < 0) {
1284 hdd_err("Invalid dwell_time: %d", params->dwell_time);
1285 return -EINVAL;
1286 }
1287
1288 ret = hdd_sendactionframe(adapter, bssid, params->channel,
1289 params->dwell_time, params->len, params->data);
1290
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001291 return ret;
1292}
1293
1294/**
1295 * hdd_parse_sendactionframe() - parse the SENDACTIONFRAME command
1296 * @adapter: Adapter upon which the command was received
1297 * @command: Command that was received
1298 *
1299 * There are two different versions of the SENDACTIONFRAME command.
1300 * Version 1 of the command contains a parameter list that is ASCII
1301 * characters whereas version 2 contains a combination of ASCII and
1302 * binary payload. Determine if a version 1 or a version 2 command is
1303 * being parsed by examining the parameters, and then dispatch the
1304 * parser that is appropriate for the version of the command.
1305 *
1306 * Return: 0 for success non-zero for failure
1307 */
1308static int
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001309hdd_parse_sendactionframe(hdd_adapter_t *adapter, const char *command,
1310 int total_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001311{
1312 int ret;
1313
1314 /*
1315 * both versions start with "SENDACTIONFRAME "
1316 * v1 has a bssid and other parameters as an ASCII string
1317 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DWELL LEN FRAME
1318 * v2 has a C struct
1319 * SENDACTIONFRAME <binary c struct>
1320 *
1321 * The first field in the v2 struct is also the bssid in ASCII.
1322 * But in the case of a v2 message the BSSID is NUL-terminated.
1323 * Hence we can peek at that offset to see if this is V1 or V2
1324 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx*
1325 * 111111111122222222223333
1326 * 0123456789012345678901234567890123
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001327 * For both the commands, a valid command must have atleast
1328 * first 34 length of data.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001329 */
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001330 if (total_len < 34) {
1331 hdd_err("Invalid command (total_len=%d)", total_len);
1332 return -EINVAL;
1333 }
1334
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001335 if (command[33]) {
1336 ret = hdd_parse_sendactionframe_v1(adapter, command);
1337 } else {
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001338 ret = hdd_parse_sendactionframe_v2(adapter, command, total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001339 }
1340
1341 return ret;
1342}
1343
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001344/**
1345 * hdd_parse_channellist() - HDD Parse channel list
1346 * @pValue: Pointer to input channel list
1347 * @ChannelList: Pointer to local output array to record
1348 * channel list
1349 * @pNumChannels: Pointer to number of roam scan channels
1350 *
1351 * This function parses the channel list passed in the format
1352 * SETROAMSCANCHANNELS<space><Number of channels><space>Channel 1<space>Channel 2<space>Channel N
1353 * if the Number of channels (N) does not match with the actual number
1354 * of channels passed then take the minimum of N and count of
1355 * (Ch1, Ch2, ...Ch M). For example, if SETROAMSCANCHANNELS 3 36 40 44 48,
1356 * only 36, 40 and 44 shall be taken. If SETROAMSCANCHANNELS 5 36 40 44 48,
1357 * ignore 5 and take 36, 40, 44 and 48. This function does not take care of
1358 * removing duplicate channels from the list
1359 *
1360 * Return: 0 for success non-zero for failure
1361 */
1362static int
1363hdd_parse_channellist(const uint8_t *pValue, uint8_t *pChannelList,
1364 uint8_t *pNumChannels)
1365{
1366 const uint8_t *inPtr = pValue;
1367 int tempInt;
1368 int j = 0;
1369 int v = 0;
1370 char buf[32];
1371
1372 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
1373 /* no argument after the command */
1374 if (NULL == inPtr) {
1375 return -EINVAL;
1376 }
1377
1378 /* no space after the command */
1379 else if (SPACE_ASCII_VALUE != *inPtr) {
1380 return -EINVAL;
1381 }
1382
1383 /* remove empty spaces */
1384 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
1385 inPtr++;
1386
1387 /* no argument followed by spaces */
1388 if ('\0' == *inPtr) {
1389 return -EINVAL;
1390 }
1391
1392 /* get the first argument ie the number of channels */
1393 v = sscanf(inPtr, "%31s ", buf);
1394 if (1 != v)
1395 return -EINVAL;
1396
1397 v = kstrtos32(buf, 10, &tempInt);
1398 if ((v < 0) ||
1399 (tempInt <= 0) || (tempInt > WNI_CFG_VALID_CHANNEL_LIST_LEN)) {
1400 return -EINVAL;
1401 }
1402
1403 *pNumChannels = tempInt;
1404
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001405 hdd_info("Number of channels are: %d", *pNumChannels);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001406
1407 for (j = 0; j < (*pNumChannels); j++) {
1408 /*
1409 * inPtr pointing to the beginning of first space after number
1410 * of channels
1411 */
1412 inPtr = strpbrk(inPtr, " ");
1413 /* no channel list after the number of channels argument */
1414 if (NULL == inPtr) {
1415 if (0 != j) {
1416 *pNumChannels = j;
1417 return 0;
1418 } else {
1419 return -EINVAL;
1420 }
1421 }
1422
1423 /* remove empty space */
1424 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
1425 inPtr++;
1426
1427 /*
1428 * no channel list after the number of channels
1429 * argument and spaces
1430 */
1431 if ('\0' == *inPtr) {
1432 if (0 != j) {
1433 *pNumChannels = j;
1434 return 0;
1435 } else {
1436 return -EINVAL;
1437 }
1438 }
1439
1440 v = sscanf(inPtr, "%31s ", buf);
1441 if (1 != v)
1442 return -EINVAL;
1443
1444 v = kstrtos32(buf, 10, &tempInt);
1445 if ((v < 0) ||
1446 (tempInt <= 0) ||
1447 (tempInt > WNI_CFG_CURRENT_CHANNEL_STAMAX)) {
1448 return -EINVAL;
1449 }
1450 pChannelList[j] = tempInt;
1451
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001452 hdd_info("Channel %d added to preferred channel list",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001453 pChannelList[j]);
1454 }
1455
1456 return 0;
1457}
1458
1459/**
1460 * hdd_parse_set_roam_scan_channels_v1() - parse version 1 of the
1461 * SETROAMSCANCHANNELS command
1462 * @adapter: Adapter upon which the command was received
1463 * @command: ASCII text command that was received
1464 *
1465 * This function parses the v1 SETROAMSCANCHANNELS command with the format
1466 *
1467 * SETROAMSCANCHANNELS N C1 C2 ... Cn
1468 *
1469 * Where "N" is the ASCII representation of the number of channels and
1470 * C1 thru Cn is the ASCII representation of the channels. For example
1471 *
1472 * SETROAMSCANCHANNELS 4 36 40 44 48
1473 *
1474 * Return: 0 for success non-zero for failure
1475 */
1476static int
1477hdd_parse_set_roam_scan_channels_v1(hdd_adapter_t *adapter,
1478 const char *command)
1479{
1480 uint8_t channel_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
1481 uint8_t num_chan = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301482 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001483 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1484 int ret;
1485
1486 ret = hdd_parse_channellist(command, channel_list, &num_chan);
1487 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001488 hdd_err("Failed to parse channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001489 goto exit;
1490 }
1491
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301492 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001493 TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL,
1494 adapter->sessionId, num_chan));
1495
1496 if (num_chan > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001497 hdd_err("number of channels (%d) supported exceeded max (%d)",
1498 num_chan, WNI_CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001499 ret = -EINVAL;
1500 goto exit;
1501 }
1502
1503 status =
1504 sme_change_roam_scan_channel_list(hdd_ctx->hHal,
1505 adapter->sessionId,
1506 channel_list, num_chan);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301507 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001508 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001509 ret = -EINVAL;
1510 goto exit;
1511 }
1512exit:
1513 return ret;
1514}
1515
1516/**
1517 * hdd_parse_set_roam_scan_channels_v2() - parse version 2 of the
1518 * SETROAMSCANCHANNELS command
1519 * @adapter: Adapter upon which the command was received
1520 * @command: Command that was received, ASCII command
1521 * followed by binary data
1522 *
1523 * This function parses the v2 SETROAMSCANCHANNELS command with the format
1524 *
1525 * SETROAMSCANCHANNELS [N][C1][C2][Cn]
1526 *
1527 * The command begins with SETROAMSCANCHANNELS followed by a space, but
1528 * what follows the space is an array of u08 parameters. For example
1529 *
1530 * SETROAMSCANCHANNELS [0x04 0x24 0x28 0x2c 0x30]
1531 *
1532 * Return: 0 for success non-zero for failure
1533 */
1534static int
1535hdd_parse_set_roam_scan_channels_v2(hdd_adapter_t *adapter,
1536 const char *command)
1537{
1538 const uint8_t *value;
1539 uint8_t channel_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
1540 uint8_t channel;
1541 uint8_t num_chan;
1542 int i;
1543 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301544 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001545 int ret = 0;
1546
1547 /* array of values begins after "SETROAMSCANCHANNELS " */
1548 value = command + 20;
1549
1550 num_chan = *value++;
1551 if (num_chan > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001552 hdd_err("number of channels (%d) supported exceeded max (%d)",
1553 num_chan, WNI_CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001554 ret = -EINVAL;
1555 goto exit;
1556 }
1557
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301558 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001559 TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL,
1560 adapter->sessionId, num_chan));
1561
1562 for (i = 0; i < num_chan; i++) {
1563 channel = *value++;
1564 if (channel > WNI_CFG_CURRENT_CHANNEL_STAMAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001565 hdd_err("index %d invalid channel %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001566 i, channel);
1567 ret = -EINVAL;
1568 goto exit;
1569 }
1570 channel_list[i] = channel;
1571 }
1572 status =
1573 sme_change_roam_scan_channel_list(hdd_ctx->hHal,
1574 adapter->sessionId,
1575 channel_list, num_chan);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301576 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001577 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001578 ret = -EINVAL;
1579 goto exit;
1580 }
1581exit:
1582 return ret;
1583}
1584
1585/**
1586 * hdd_parse_set_roam_scan_channels() - parse the
1587 * SETROAMSCANCHANNELS command
1588 * @adapter: Adapter upon which the command was received
1589 * @command: Command that was received
1590 *
1591 * There are two different versions of the SETROAMSCANCHANNELS command.
1592 * Version 1 of the command contains a parameter list that is ASCII
1593 * characters whereas version 2 contains a binary payload. Determine
1594 * if a version 1 or a version 2 command is being parsed by examining
1595 * the parameters, and then dispatch the parser that is appropriate for
1596 * the command.
1597 *
1598 * Return: 0 for success non-zero for failure
1599 */
1600static int
1601hdd_parse_set_roam_scan_channels(hdd_adapter_t *adapter, const char *command)
1602{
1603 const char *cursor;
1604 char ch;
1605 bool v1;
1606 int ret;
1607
1608 /* start after "SETROAMSCANCHANNELS " */
1609 cursor = command + 20;
1610
1611 /* assume we have a version 1 command until proven otherwise */
1612 v1 = true;
1613
1614 /* v1 params will only contain ASCII digits and space */
1615 while ((ch = *cursor++) && v1) {
1616 if (!(isdigit(ch) || isspace(ch))) {
1617 v1 = false;
1618 }
1619 }
1620 if (v1) {
1621 ret = hdd_parse_set_roam_scan_channels_v1(adapter, command);
1622 } else {
1623 ret = hdd_parse_set_roam_scan_channels_v2(adapter, command);
1624 }
1625
1626 return ret;
1627}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001628
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08001629#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001630/**
1631 * hdd_parse_plm_cmd() - HDD Parse Plm command
1632 * @pValue: Pointer to input data
1633 * @pPlmRequest:Pointer to output struct tpSirPlmReq
1634 *
1635 * This function parses the plm command passed in the format
1636 * CCXPLMREQ<space><enable><space><dialog_token><space>
1637 * <meas_token><space><num_of_bursts><space><burst_int><space>
1638 * <measu duration><space><burst_len><space><desired_tx_pwr>
1639 * <space><multcast_addr><space><number_of_channels>
1640 * <space><channel_numbers>
1641 *
1642 * Return: 0 for success non-zero for failure
1643 */
Jeff Johnsonf731b302016-10-05 16:00:55 -07001644static QDF_STATUS hdd_parse_plm_cmd(uint8_t *pValue, tSirPlmReq *pPlmRequest)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001645{
1646 uint8_t *cmdPtr = NULL;
1647 int count, content = 0, ret = 0;
1648 char buf[32];
1649
1650 /* move to argument list */
1651 cmdPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
1652 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301653 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001654
1655 /* no space after the command */
1656 if (SPACE_ASCII_VALUE != *cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301657 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001658
1659 /* remove empty spaces */
1660 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1661 cmdPtr++;
1662
1663 /* START/STOP PLM req */
1664 ret = sscanf(cmdPtr, "%31s ", buf);
1665 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301666 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001667
1668 ret = kstrtos32(buf, 10, &content);
1669 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301670 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001671
1672 pPlmRequest->enable = content;
1673 cmdPtr = strpbrk(cmdPtr, " ");
1674
1675 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301676 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001677
1678 /* remove empty spaces */
1679 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1680 cmdPtr++;
1681
1682 /* Dialog token of radio meas req containing meas reqIE */
1683 ret = sscanf(cmdPtr, "%31s ", buf);
1684 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301685 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001686
1687 ret = kstrtos32(buf, 10, &content);
1688 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301689 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001690
1691 pPlmRequest->diag_token = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001692 hdd_debug("diag token %d", pPlmRequest->diag_token);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001693 cmdPtr = strpbrk(cmdPtr, " ");
1694
1695 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301696 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001697
1698 /* remove empty spaces */
1699 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1700 cmdPtr++;
1701
1702 /* measurement token of meas req IE */
1703 ret = sscanf(cmdPtr, "%31s ", buf);
1704 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301705 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001706
1707 ret = kstrtos32(buf, 10, &content);
1708 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301709 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001710
1711 pPlmRequest->meas_token = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001712 hdd_debug("meas token %d", pPlmRequest->meas_token);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001713
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001714 hdd_err("PLM req %s", pPlmRequest->enable ? "START" : "STOP");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001715 if (pPlmRequest->enable) {
1716
1717 cmdPtr = strpbrk(cmdPtr, " ");
1718
1719 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301720 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001721
1722 /* remove empty spaces */
1723 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1724 cmdPtr++;
1725
1726 /* total number of bursts after which STA stops sending */
1727 ret = sscanf(cmdPtr, "%31s ", buf);
1728 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301729 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001730
1731 ret = kstrtos32(buf, 10, &content);
1732 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301733 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001734
1735 if (content < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301736 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001737
1738 pPlmRequest->numBursts = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001739 hdd_debug("num burst %d", pPlmRequest->numBursts);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001740 cmdPtr = strpbrk(cmdPtr, " ");
1741
1742 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301743 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001744
1745 /* remove empty spaces */
1746 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1747 cmdPtr++;
1748
1749 /* burst interval in seconds */
1750 ret = sscanf(cmdPtr, "%31s ", buf);
1751 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301752 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001753
1754 ret = kstrtos32(buf, 10, &content);
1755 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301756 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001757
1758 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301759 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001760
1761 pPlmRequest->burstInt = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001762 hdd_debug("burst Int %d", pPlmRequest->burstInt);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001763 cmdPtr = strpbrk(cmdPtr, " ");
1764
1765 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301766 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001767
1768 /* remove empty spaces */
1769 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1770 cmdPtr++;
1771
1772 /* Meas dur in TU's,STA goes off-ch and transmit PLM bursts */
1773 ret = sscanf(cmdPtr, "%31s ", buf);
1774 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301775 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001776
1777 ret = kstrtos32(buf, 10, &content);
1778 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301779 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001780
1781 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301782 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001783
1784 pPlmRequest->measDuration = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001785 hdd_debug("measDur %d", pPlmRequest->measDuration);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001786 cmdPtr = strpbrk(cmdPtr, " ");
1787
1788 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301789 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001790
1791 /* remove empty spaces */
1792 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1793 cmdPtr++;
1794
1795 /* burst length of PLM bursts */
1796 ret = sscanf(cmdPtr, "%31s ", buf);
1797 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301798 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001799
1800 ret = kstrtos32(buf, 10, &content);
1801 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301802 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001803
1804 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301805 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001806
1807 pPlmRequest->burstLen = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001808 hdd_debug("burstLen %d", pPlmRequest->burstLen);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001809 cmdPtr = strpbrk(cmdPtr, " ");
1810
1811 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301812 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001813
1814 /* remove empty spaces */
1815 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1816 cmdPtr++;
1817
1818 /* desired tx power for transmission of PLM bursts */
1819 ret = sscanf(cmdPtr, "%31s ", buf);
1820 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301821 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001822
1823 ret = kstrtos32(buf, 10, &content);
1824 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301825 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001826
1827 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301828 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001829
1830 pPlmRequest->desiredTxPwr = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001831 hdd_debug("desiredTxPwr %d",
1832 pPlmRequest->desiredTxPwr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001833
Anurag Chouhan6d760662016-02-20 16:05:43 +05301834 for (count = 0; count < QDF_MAC_ADDR_SIZE; count++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001835 cmdPtr = strpbrk(cmdPtr, " ");
1836
1837 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301838 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001839
1840 /* remove empty spaces */
1841 while ((SPACE_ASCII_VALUE == *cmdPtr)
1842 && ('\0' != *cmdPtr))
1843 cmdPtr++;
1844
1845 ret = sscanf(cmdPtr, "%31s ", buf);
1846 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301847 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001848
1849 ret = kstrtos32(buf, 16, &content);
1850 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301851 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001852
Srinivas Girigowda5146dee2015-11-18 21:46:48 -08001853 pPlmRequest->mac_addr.bytes[count] = content;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001854 }
1855
Srinivas Girigowda5146dee2015-11-18 21:46:48 -08001856 hdd_debug("MC addr " MAC_ADDRESS_STR,
1857 MAC_ADDR_ARRAY(pPlmRequest->mac_addr.bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001858
1859 cmdPtr = strpbrk(cmdPtr, " ");
1860
1861 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301862 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001863
1864 /* remove empty spaces */
1865 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1866 cmdPtr++;
1867
1868 /* number of channels */
1869 ret = sscanf(cmdPtr, "%31s ", buf);
1870 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301871 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001872
1873 ret = kstrtos32(buf, 10, &content);
1874 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301875 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001876
1877 if (content < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301878 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001879
Srinivas Girigowda0fb6cc42016-08-26 14:53:59 -07001880 content = QDF_MIN(content, WNI_CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001881 pPlmRequest->plmNumCh = content;
Srinivas Girigowda0fb6cc42016-08-26 14:53:59 -07001882 hdd_debug("numch: %d", pPlmRequest->plmNumCh);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001883
1884 /* Channel numbers */
1885 for (count = 0; count < pPlmRequest->plmNumCh; count++) {
1886 cmdPtr = strpbrk(cmdPtr, " ");
1887
1888 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301889 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001890
1891 /* remove empty spaces */
1892 while ((SPACE_ASCII_VALUE == *cmdPtr)
1893 && ('\0' != *cmdPtr))
1894 cmdPtr++;
1895
1896 ret = sscanf(cmdPtr, "%31s ", buf);
1897 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301898 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001899
1900 ret = kstrtos32(buf, 10, &content);
Srinivas Girigowda0fb6cc42016-08-26 14:53:59 -07001901 if (ret < 0 || content <= 0 ||
1902 content > WNI_CFG_CURRENT_CHANNEL_STAMAX)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301903 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001904
1905 pPlmRequest->plmChList[count] = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001906 hdd_debug(" ch- %d", pPlmRequest->plmChList[count]);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001907 }
1908 }
1909 /* If PLM START */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301910 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001911}
1912#endif
1913
1914#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
1915static void wlan_hdd_ready_to_extwow(void *callbackContext, bool is_success)
1916{
1917 hdd_context_t *hdd_ctx = (hdd_context_t *) callbackContext;
1918 int rc;
1919
1920 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301921 if (rc)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001922 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001923 hdd_ctx->ext_wow_should_suspend = is_success;
1924 complete(&hdd_ctx->ready_to_extwow);
1925}
1926
1927static int hdd_enable_ext_wow(hdd_adapter_t *adapter,
1928 tpSirExtWoWParams arg_params)
1929{
1930 tSirExtWoWParams params;
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301931 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001932 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1933 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
1934 int rc;
1935
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301936 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001937
1938 INIT_COMPLETION(hdd_ctx->ready_to_extwow);
1939
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301940 qdf_ret_status = sme_configure_ext_wow(hHal, &params,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001941 &wlan_hdd_ready_to_extwow,
1942 hdd_ctx);
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301943 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001944 hdd_err("sme_configure_ext_wow returned failure %d",
1945 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001946 return -EPERM;
1947 }
1948
1949 rc = wait_for_completion_timeout(&hdd_ctx->ready_to_extwow,
1950 msecs_to_jiffies(WLAN_WAIT_TIME_READY_TO_EXTWOW));
1951 if (!rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001952 hdd_err("Failed to get ready to extwow");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001953 return -EPERM;
1954 }
1955
1956 if (hdd_ctx->ext_wow_should_suspend) {
1957 if (hdd_ctx->config->extWowGotoSuspend) {
1958 pm_message_t state;
1959
1960 state.event = PM_EVENT_SUSPEND;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001961 hdd_info("Received ready to ExtWoW. Going to suspend");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001962
1963 rc = wlan_hdd_cfg80211_suspend_wlan(hdd_ctx->wiphy, NULL);
1964 if (rc < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001965 hdd_err("wlan_hdd_cfg80211_suspend_wlan failed, error = %d",
1966 rc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001967 return rc;
1968 }
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301969 qdf_ret_status = wlan_hdd_bus_suspend(state);
1970 if (qdf_ret_status != QDF_STATUS_SUCCESS) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001971 hdd_err("wlan_hdd_suspend failed, status = %d",
1972 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001973 wlan_hdd_cfg80211_resume_wlan(hdd_ctx->wiphy);
1974 return -EPERM;
1975 }
1976 }
1977 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001978 hdd_err("Received ready to ExtWoW failure");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001979 return -EPERM;
1980 }
1981
1982 return 0;
1983}
1984
1985static int hdd_enable_ext_wow_parser(hdd_adapter_t *adapter, int vdev_id,
1986 int value)
1987{
1988 tSirExtWoWParams params;
1989 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1990 int rc;
1991
1992 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301993 if (rc)
1994 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001995
1996 if (value < EXT_WOW_TYPE_APP_TYPE1 ||
1997 value > EXT_WOW_TYPE_APP_TYPE1_2) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001998 hdd_err("Invalid type");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001999 return -EINVAL;
2000 }
2001
2002 if (value == EXT_WOW_TYPE_APP_TYPE1 &&
2003 hdd_ctx->is_extwow_app_type1_param_set)
2004 params.type = value;
2005 else if (value == EXT_WOW_TYPE_APP_TYPE2 &&
2006 hdd_ctx->is_extwow_app_type2_param_set)
2007 params.type = value;
2008 else if (value == EXT_WOW_TYPE_APP_TYPE1_2 &&
2009 hdd_ctx->is_extwow_app_type1_param_set &&
2010 hdd_ctx->is_extwow_app_type2_param_set)
2011 params.type = value;
2012 else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002013 hdd_err("Set app params before enable it value %d",
2014 value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002015 return -EINVAL;
2016 }
2017
2018 params.vdev_id = vdev_id;
2019 params.wakeup_pin_num = hdd_ctx->config->extWowApp1WakeupPinNumber |
2020 (hdd_ctx->config->extWowApp2WakeupPinNumber
2021 << 8);
2022
2023 return hdd_enable_ext_wow(adapter, &params);
2024}
2025
2026static int hdd_set_app_type1_params(tHalHandle hHal,
2027 tpSirAppType1Params arg_params)
2028{
2029 tSirAppType1Params params;
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05302030 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002031
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302032 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002033
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05302034 qdf_ret_status = sme_configure_app_type1_params(hHal, &params);
2035 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002036 hdd_err("sme_configure_app_type1_params returned failure %d",
2037 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002038 return -EPERM;
2039 }
2040
2041 return 0;
2042}
2043
2044static int hdd_set_app_type1_parser(hdd_adapter_t *adapter,
2045 char *arg, int len)
2046{
2047 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2048 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
2049 char id[20], password[20];
2050 tSirAppType1Params params;
Srinivas Girigowda04209912015-11-24 12:11:13 -08002051 int rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002052
2053 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302054 if (rc)
2055 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002056
2057 if (2 != sscanf(arg, "%8s %16s", id, password)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002058 hdd_err("Invalid Number of arguments");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002059 return -EINVAL;
2060 }
2061
2062 memset(&params, 0, sizeof(tSirAppType1Params));
2063 params.vdev_id = adapter->sessionId;
Anurag Chouhanc5548422016-02-24 18:33:27 +05302064 qdf_copy_macaddr(&params.wakee_mac_addr, &adapter->macAddressCurrent);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002065
2066 params.id_length = strlen(id);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302067 qdf_mem_copy(params.identification_id, id, params.id_length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002068 params.pass_length = strlen(password);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302069 qdf_mem_copy(params.password, password, params.pass_length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002070
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002071 hdd_info("%d %pM %.8s %u %.16s %u",
2072 params.vdev_id, params.wakee_mac_addr.bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002073 params.identification_id, params.id_length,
2074 params.password, params.pass_length);
2075
2076 return hdd_set_app_type1_params(hHal, &params);
2077}
2078
2079static int hdd_set_app_type2_params(tHalHandle hHal,
2080 tpSirAppType2Params arg_params)
2081{
2082 tSirAppType2Params params;
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05302083 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002084
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302085 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002086
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05302087 qdf_ret_status = sme_configure_app_type2_params(hHal, &params);
2088 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002089 hdd_err("sme_configure_app_type2_params returned failure %d",
2090 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002091 return -EPERM;
2092 }
2093
2094 return 0;
2095}
2096
2097static int hdd_set_app_type2_parser(hdd_adapter_t *adapter,
2098 char *arg, int len)
2099{
2100 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2101 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
2102 char mac_addr[20], rc4_key[20];
Anurag Chouhan6d760662016-02-20 16:05:43 +05302103 unsigned int gateway_mac[QDF_MAC_ADDR_SIZE];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002104 tSirAppType2Params params;
2105 int ret;
2106
2107 ret = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302108 if (ret)
2109 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002110
2111 memset(&params, 0, sizeof(tSirAppType2Params));
2112
Bhargav Shahf4fd97d2015-07-08 10:21:37 +05302113 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 -08002114 mac_addr, rc4_key, (unsigned int *)&params.ip_id,
2115 (unsigned int *)&params.ip_device_ip,
2116 (unsigned int *)&params.ip_server_ip,
2117 (unsigned int *)&params.tcp_seq,
2118 (unsigned int *)&params.tcp_ack_seq,
Bhargav Shahf4fd97d2015-07-08 10:21:37 +05302119 (uint16_t *)&params.tcp_src_port,
2120 (uint16_t *)&params.tcp_dst_port,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002121 (unsigned int *)&params.keepalive_init,
2122 (unsigned int *)&params.keepalive_min,
2123 (unsigned int *)&params.keepalive_max,
2124 (unsigned int *)&params.keepalive_inc,
2125 (unsigned int *)&params.tcp_tx_timeout_val,
2126 (unsigned int *)&params.tcp_rx_timeout_val);
2127
2128 if (ret != 15 && ret != 7) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002129 hdd_err("Invalid Number of arguments");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002130 return -EINVAL;
2131 }
2132
2133 if (6 !=
2134 sscanf(mac_addr, "%02x:%02x:%02x:%02x:%02x:%02x", &gateway_mac[0],
2135 &gateway_mac[1], &gateway_mac[2], &gateway_mac[3],
2136 &gateway_mac[4], &gateway_mac[5])) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002137 hdd_err("Invalid MacAddress Input %s", mac_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002138 return -EINVAL;
2139 }
2140
2141 if (params.tcp_src_port > WLAN_HDD_MAX_TCP_PORT ||
2142 params.tcp_dst_port > WLAN_HDD_MAX_TCP_PORT) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002143 hdd_err("Invalid TCP Port Number");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002144 return -EINVAL;
2145 }
2146
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302147 qdf_mem_copy(&params.gateway_mac.bytes, (uint8_t *) &gateway_mac,
Anurag Chouhan6d760662016-02-20 16:05:43 +05302148 QDF_MAC_ADDR_SIZE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002149
2150 params.rc4_key_len = strlen(rc4_key);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302151 qdf_mem_copy(params.rc4_key, rc4_key, params.rc4_key_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002152
2153 params.vdev_id = adapter->sessionId;
2154 params.tcp_src_port = (params.tcp_src_port != 0) ?
2155 params.tcp_src_port : hdd_ctx->config->extWowApp2TcpSrcPort;
2156 params.tcp_dst_port = (params.tcp_dst_port != 0) ?
2157 params.tcp_dst_port : hdd_ctx->config->extWowApp2TcpDstPort;
2158 params.keepalive_init = (params.keepalive_init != 0) ?
2159 params.keepalive_init : hdd_ctx->config->
2160 extWowApp2KAInitPingInterval;
2161 params.keepalive_min =
2162 (params.keepalive_min != 0) ?
2163 params.keepalive_min :
2164 hdd_ctx->config->extWowApp2KAMinPingInterval;
2165 params.keepalive_max =
2166 (params.keepalive_max != 0) ?
2167 params.keepalive_max :
2168 hdd_ctx->config->extWowApp2KAMaxPingInterval;
2169 params.keepalive_inc =
2170 (params.keepalive_inc != 0) ?
2171 params.keepalive_inc :
2172 hdd_ctx->config->extWowApp2KAIncPingInterval;
2173 params.tcp_tx_timeout_val =
2174 (params.tcp_tx_timeout_val != 0) ?
2175 params.tcp_tx_timeout_val :
2176 hdd_ctx->config->extWowApp2TcpTxTimeout;
2177 params.tcp_rx_timeout_val =
2178 (params.tcp_rx_timeout_val != 0) ?
2179 params.tcp_rx_timeout_val :
2180 hdd_ctx->config->extWowApp2TcpRxTimeout;
2181
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002182 hdd_info("%pM %.16s %u %u %u %u %u %u %u %u %u %u %u %u %u",
2183 gateway_mac, rc4_key, params.ip_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002184 params.ip_device_ip, params.ip_server_ip, params.tcp_seq,
2185 params.tcp_ack_seq, params.tcp_src_port, params.tcp_dst_port,
2186 params.keepalive_init, params.keepalive_min,
2187 params.keepalive_max, params.keepalive_inc,
2188 params.tcp_tx_timeout_val, params.tcp_rx_timeout_val);
2189
2190 return hdd_set_app_type2_params(hHal, &params);
2191}
2192#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
2193
2194/**
2195 * hdd_parse_setmaxtxpower_command() - HDD Parse MAXTXPOWER command
2196 * @pValue: Pointer to MAXTXPOWER command
2197 * @pDbm: Pointer to tx power
2198 *
2199 * This function parses the MAXTXPOWER command passed in the format
2200 * MAXTXPOWER<space>X(Tx power in dbm)
2201 *
2202 * For example input commands:
2203 * 1) MAXTXPOWER -8 -> This is translated into set max TX power to -8 dbm
2204 * 2) MAXTXPOWER -23 -> This is translated into set max TX power to -23 dbm
2205 *
2206 * Return: 0 for success non-zero for failure
2207 */
2208static int hdd_parse_setmaxtxpower_command(uint8_t *pValue, int *pTxPower)
2209{
2210 uint8_t *inPtr = pValue;
2211 int tempInt;
2212 int v = 0;
2213 *pTxPower = 0;
2214
2215 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2216 /* no argument after the command */
2217 if (NULL == inPtr) {
2218 return -EINVAL;
2219 }
2220
2221 /* no space after the command */
2222 else if (SPACE_ASCII_VALUE != *inPtr) {
2223 return -EINVAL;
2224 }
2225
2226 /* remove empty spaces */
2227 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2228 inPtr++;
2229
2230 /* no argument followed by spaces */
2231 if ('\0' == *inPtr) {
2232 return 0;
2233 }
2234
2235 v = kstrtos32(inPtr, 10, &tempInt);
2236
2237 /* Range checking for passed parameter */
2238 if ((tempInt < HDD_MIN_TX_POWER) || (tempInt > HDD_MAX_TX_POWER)) {
2239 return -EINVAL;
2240 }
2241
2242 *pTxPower = tempInt;
2243
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002244 hdd_info("SETMAXTXPOWER: %d", *pTxPower);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002245
2246 return 0;
2247} /* End of hdd_parse_setmaxtxpower_command */
2248
2249static int hdd_get_dwell_time(struct hdd_config *pCfg, uint8_t *command,
2250 char *extra, uint8_t n, uint8_t *len)
2251{
2252 int ret = 0;
2253
2254 if (!pCfg || !command || !extra || !len) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002255 hdd_err("argument passed for GETDWELLTIME is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002256 ret = -EINVAL;
2257 return ret;
2258 }
2259
2260 if (strncmp(command, "GETDWELLTIME ACTIVE MAX", 23) == 0) {
2261 *len = scnprintf(extra, n, "GETDWELLTIME ACTIVE MAX %u\n",
2262 (int)pCfg->nActiveMaxChnTime);
2263 return ret;
2264 } else if (strncmp(command, "GETDWELLTIME ACTIVE MIN", 23) == 0) {
2265 *len = scnprintf(extra, n, "GETDWELLTIME ACTIVE MIN %u\n",
2266 (int)pCfg->nActiveMinChnTime);
2267 return ret;
2268 } else if (strncmp(command, "GETDWELLTIME PASSIVE MAX", 24) == 0) {
2269 *len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MAX %u\n",
2270 (int)pCfg->nPassiveMaxChnTime);
2271 return ret;
2272 } else if (strncmp(command, "GETDWELLTIME PASSIVE MIN", 24) == 0) {
2273 *len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MIN %u\n",
2274 (int)pCfg->nPassiveMinChnTime);
2275 return ret;
2276 } else if (strncmp(command, "GETDWELLTIME", 12) == 0) {
2277 *len = scnprintf(extra, n, "GETDWELLTIME %u \n",
2278 (int)pCfg->nActiveMaxChnTime);
2279 return ret;
2280 } else {
2281 ret = -EINVAL;
2282 }
2283
2284 return ret;
2285}
2286
2287static int hdd_set_dwell_time(hdd_adapter_t *adapter, uint8_t *command)
2288{
2289 tHalHandle hHal;
2290 struct hdd_config *pCfg;
2291 uint8_t *value = command;
2292 tSmeConfigParams smeConfig;
2293 int val = 0, temp = 0;
2294
2295 pCfg = (WLAN_HDD_GET_CTX(adapter))->config;
2296 hHal = WLAN_HDD_GET_HAL_CTX(adapter);
2297 if (!pCfg || !hHal) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002298 hdd_err("argument passed for SETDWELLTIME is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002299 return -EINVAL;
2300 }
2301
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302302 qdf_mem_zero(&smeConfig, sizeof(smeConfig));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002303 sme_get_config_param(hHal, &smeConfig);
2304
2305 if (strncmp(command, "SETDWELLTIME ACTIVE MAX", 23) == 0) {
2306 value = value + 24;
2307 temp = kstrtou32(value, 10, &val);
2308 if (temp != 0 || val < CFG_ACTIVE_MAX_CHANNEL_TIME_MIN ||
2309 val > CFG_ACTIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002310 hdd_err("argument passed for SETDWELLTIME ACTIVE MAX is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002311 return -EFAULT;
2312 }
2313 pCfg->nActiveMaxChnTime = val;
2314 smeConfig.csrConfig.nActiveMaxChnTime = val;
2315 sme_update_config(hHal, &smeConfig);
2316 } else if (strncmp(command, "SETDWELLTIME ACTIVE MIN", 23) == 0) {
2317 value = value + 24;
2318 temp = kstrtou32(value, 10, &val);
2319 if (temp != 0 || val < CFG_ACTIVE_MIN_CHANNEL_TIME_MIN ||
2320 val > CFG_ACTIVE_MIN_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002321 hdd_err("argument passed for SETDWELLTIME ACTIVE MIN is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002322 return -EFAULT;
2323 }
2324 pCfg->nActiveMinChnTime = val;
2325 smeConfig.csrConfig.nActiveMinChnTime = val;
2326 sme_update_config(hHal, &smeConfig);
2327 } else if (strncmp(command, "SETDWELLTIME PASSIVE MAX", 24) == 0) {
2328 value = value + 25;
2329 temp = kstrtou32(value, 10, &val);
2330 if (temp != 0 || val < CFG_PASSIVE_MAX_CHANNEL_TIME_MIN ||
2331 val > CFG_PASSIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002332 hdd_err("argument passed for SETDWELLTIME PASSIVE MAX is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002333 return -EFAULT;
2334 }
2335 pCfg->nPassiveMaxChnTime = val;
2336 smeConfig.csrConfig.nPassiveMaxChnTime = val;
2337 sme_update_config(hHal, &smeConfig);
2338 } else if (strncmp(command, "SETDWELLTIME PASSIVE MIN", 24) == 0) {
2339 value = value + 25;
2340 temp = kstrtou32(value, 10, &val);
2341 if (temp != 0 || val < CFG_PASSIVE_MIN_CHANNEL_TIME_MIN ||
2342 val > CFG_PASSIVE_MIN_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002343 hdd_err("argument passed for SETDWELLTIME PASSIVE MIN is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002344 return -EFAULT;
2345 }
2346 pCfg->nPassiveMinChnTime = val;
2347 smeConfig.csrConfig.nPassiveMinChnTime = val;
2348 sme_update_config(hHal, &smeConfig);
2349 } else if (strncmp(command, "SETDWELLTIME", 12) == 0) {
2350 value = value + 13;
2351 temp = kstrtou32(value, 10, &val);
2352 if (temp != 0 || val < CFG_ACTIVE_MAX_CHANNEL_TIME_MIN ||
2353 val > CFG_ACTIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002354 hdd_err("argument passed for SETDWELLTIME is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002355 return -EFAULT;
2356 }
2357 pCfg->nActiveMaxChnTime = val;
2358 smeConfig.csrConfig.nActiveMaxChnTime = val;
2359 sme_update_config(hHal, &smeConfig);
2360 } else {
2361 return -EINVAL;
2362 }
2363
2364 return 0;
2365}
2366
2367static void hdd_get_link_status_cb(uint8_t status, void *context)
2368{
2369 struct statsContext *pLinkContext;
2370 hdd_adapter_t *adapter;
2371
2372 if (NULL == context) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002373 hdd_err("Bad context [%p]", context);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002374 return;
2375 }
2376
2377 pLinkContext = context;
2378 adapter = pLinkContext->pAdapter;
2379
2380 spin_lock(&hdd_context_lock);
2381
2382 if ((NULL == adapter) ||
2383 (LINK_STATUS_MAGIC != pLinkContext->magic)) {
2384 /*
2385 * the caller presumably timed out so there is
2386 * nothing we can do
2387 */
2388 spin_unlock(&hdd_context_lock);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002389 hdd_warn("Invalid context, adapter [%p] magic [%08x]",
2390 adapter, pLinkContext->magic);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002391 return;
2392 }
2393
2394 /* context is valid so caller is still waiting */
2395
2396 /* paranoia: invalidate the magic */
2397 pLinkContext->magic = 0;
2398
2399 /* copy over the status */
2400 adapter->linkStatus = status;
2401
2402 /* notify the caller */
2403 complete(&pLinkContext->completion);
2404
2405 /* serialization is complete */
2406 spin_unlock(&hdd_context_lock);
2407}
2408
2409/**
2410 * wlan_hdd_get_link_status() - get link status
2411 * @pAdapter: pointer to the adapter
2412 *
2413 * This function sends a request to query the link status and waits
2414 * on a timer to invoke the callback. if the callback is invoked then
2415 * latest link status shall be returned or otherwise cached value
2416 * will be returned.
2417 *
2418 * Return: On success, link status shall be returned.
2419 * On error or not associated, link status 0 will be returned.
2420 */
2421static int wlan_hdd_get_link_status(hdd_adapter_t *adapter)
2422{
2423
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002424 hdd_station_ctx_t *pHddStaCtx =
2425 WLAN_HDD_GET_STATION_CTX_PTR(adapter);
2426 struct statsContext context;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302427 QDF_STATUS hstatus;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002428 unsigned long rc;
2429
Prashanth Bhatta9e143052015-12-04 11:56:47 -08002430 if (cds_is_driver_recovering()) {
2431 hdd_warn("Recovery in Progress. State: 0x%x Ignore!!!",
2432 cds_get_driver_state());
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002433 return 0;
2434 }
2435
Krunal Sonibe766b02016-03-10 13:00:44 -08002436 if ((QDF_STA_MODE != adapter->device_mode) &&
2437 (QDF_P2P_CLIENT_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002438 hdd_warn("Unsupported in mode %s(%d)",
2439 hdd_device_mode_to_string(adapter->device_mode),
2440 adapter->device_mode);
2441 return 0;
2442 }
2443
2444 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
2445 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
2446 /* If not associated, then expected link status return
2447 * value is 0
2448 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002449 hdd_info("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002450 return 0;
2451 }
2452
2453 init_completion(&context.completion);
2454 context.pAdapter = adapter;
2455 context.magic = LINK_STATUS_MAGIC;
2456 hstatus = sme_get_link_status(WLAN_HDD_GET_HAL_CTX(adapter),
2457 hdd_get_link_status_cb,
2458 &context, adapter->sessionId);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302459 if (QDF_STATUS_SUCCESS != hstatus) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002460 hdd_err("Unable to retrieve link status");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002461 /* return a cached value */
2462 } else {
2463 /* request is sent -- wait for the response */
2464 rc = wait_for_completion_timeout(&context.completion,
2465 msecs_to_jiffies(WLAN_WAIT_TIME_LINK_STATUS));
2466 if (!rc)
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002467 hdd_err("SME timed out while retrieving link status");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002468 }
2469
2470 spin_lock(&hdd_context_lock);
2471 context.magic = 0;
2472 spin_unlock(&hdd_context_lock);
2473
2474 /* either callback updated adapter stats or it has cached data */
2475 return adapter->linkStatus;
2476}
2477
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002478static void hdd_tx_fail_ind_callback(uint8_t *MacAddr, uint8_t seqNo)
2479{
2480 int payload_len;
2481 struct sk_buff *skb;
2482 struct nlmsghdr *nlh;
2483 uint8_t *data;
2484
2485 payload_len = ETH_ALEN;
2486
Ryan Hsu5e2e2052016-04-28 10:19:38 -07002487 if (0 == cesium_pid || cesium_nl_srv_sock == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002488 hdd_err("cesium process not registered");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002489 return;
2490 }
2491
2492 skb = nlmsg_new(payload_len, GFP_ATOMIC);
2493 if (skb == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002494 hdd_err("nlmsg_new() failed for msg size[%d]",
2495 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002496 return;
2497 }
2498
2499 nlh = nlmsg_put(skb, cesium_pid, seqNo, 0, payload_len, NLM_F_REQUEST);
2500
2501 if (NULL == nlh) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002502 hdd_err("nlmsg_put() failed for msg size[%d]",
2503 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002504
2505 kfree_skb(skb);
2506 return;
2507 }
2508
2509 data = nlmsg_data(nlh);
2510 memcpy(data, MacAddr, ETH_ALEN);
2511
2512 if (nlmsg_unicast(cesium_nl_srv_sock, skb, cesium_pid) < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002513 hdd_err("nlmsg_unicast() failed for msg size[%d]",
2514 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002515 }
2516
2517 return;
2518}
2519
2520
2521/**
2522 * hdd_ParseuserParams - return a pointer to the next argument
2523 * @pValue: Input argument string
2524 * @ppArg: Output pointer to the next argument
2525 *
2526 * This function parses argument stream and finds the pointer
2527 * to the next argument
2528 *
2529 * Return: 0 if the next argument found; -EINVAL otherwise
2530 */
2531static int hdd_parse_user_params(uint8_t *pValue, uint8_t **ppArg)
2532{
2533 uint8_t *pVal;
2534
2535 pVal = strnchr(pValue, strlen(pValue), ' ');
2536
2537 if (NULL == pVal) {
2538 /* no argument remains */
2539 return -EINVAL;
2540 } else if (SPACE_ASCII_VALUE != *pVal) {
2541 /* no space after the current argument */
2542 return -EINVAL;
2543 }
2544
2545 pVal++;
2546
2547 /* remove empty spaces */
2548 while ((SPACE_ASCII_VALUE == *pVal) && ('\0' != *pVal)) {
2549 pVal++;
2550 }
2551
2552 /* no argument followed by spaces */
2553 if ('\0' == *pVal) {
2554 return -EINVAL;
2555 }
2556
2557 *ppArg = pVal;
2558
2559 return 0;
2560}
2561
2562/**
2563 * hdd_parse_ibsstx_fail_event_params - Parse params
2564 * for SETIBSSTXFAILEVENT
2565 * @pValue: Input ibss tx fail event argument
2566 * @tx_fail_count: (Output parameter) Tx fail counter
2567 * @pid: (Output parameter) PID
2568 *
2569 * Return: 0 if the parsing succeeds; -EINVAL otherwise
2570 */
2571static int hdd_parse_ibsstx_fail_event_params(uint8_t *pValue,
2572 uint8_t *tx_fail_count,
2573 uint16_t *pid)
2574{
2575 uint8_t *param = NULL;
2576 int ret;
2577
2578 ret = hdd_parse_user_params(pValue, &param);
2579
2580 if (0 == ret && NULL != param) {
2581 if (1 != sscanf(param, "%hhu", tx_fail_count)) {
2582 ret = -EINVAL;
2583 goto done;
2584 }
2585 } else {
2586 goto done;
2587 }
2588
2589 if (0 == *tx_fail_count) {
2590 *pid = 0;
2591 goto done;
2592 }
2593
2594 pValue = param;
2595 pValue++;
2596
2597 ret = hdd_parse_user_params(pValue, &param);
2598
2599 if (0 == ret) {
2600 if (1 != sscanf(param, "%hu", pid)) {
2601 ret = -EINVAL;
2602 goto done;
2603 }
2604 } else {
2605 goto done;
2606 }
2607
2608done:
2609 return ret;
2610}
2611
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08002612#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002613/**
2614 * hdd_parse_ese_beacon_req() - Parse ese beacon request
2615 * @pValue: Pointer to data
2616 * @pEseBcnReq: Output pointer to store parsed ie information
2617 *
2618 * This function parses the ese beacon request passed in the format
2619 * CCXBEACONREQ<space><Number of fields><space><Measurement token>
2620 * <space>Channel 1<space>Scan Mode <space>Meas Duration<space>Channel N
2621 * <space>Scan Mode N<space>Meas Duration N
2622 *
2623 * If the Number of bcn req fields (N) does not match with the
2624 * actual number of fields passed then take N.
2625 * <Meas Token><Channel><Scan Mode> and <Meas Duration> are treated
2626 * as one pair. For example, CCXBEACONREQ 2 1 1 1 30 2 44 0 40.
2627 * This function does not take care of removing duplicate channels from the
2628 * list
2629 *
2630 * Return: 0 for success non-zero for failure
2631 */
2632static int hdd_parse_ese_beacon_req(uint8_t *pValue,
2633 tCsrEseBeaconReq *pEseBcnReq)
2634{
2635 uint8_t *inPtr = pValue;
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002636 uint8_t input = 0;
2637 uint32_t tempInt = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002638 int j = 0, i = 0, v = 0;
2639 char buf[32];
2640
2641 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2642 /* no argument after the command */
2643 if (NULL == inPtr) {
2644 return -EINVAL;
2645 }
2646 /* no space after the command */
2647 else if (SPACE_ASCII_VALUE != *inPtr) {
2648 return -EINVAL;
2649 }
2650
2651 /* remove empty spaces */
2652 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2653 inPtr++;
2654
2655 /* no argument followed by spaces */
2656 if ('\0' == *inPtr)
2657 return -EINVAL;
2658
Srinivas Girigowda476deeb2016-07-19 16:21:29 -07002659 /* Getting the first argument ie Number of IE fields */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002660 v = sscanf(inPtr, "%31s ", buf);
2661 if (1 != v)
2662 return -EINVAL;
2663
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002664 v = kstrtou8(buf, 10, &input);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002665 if (v < 0)
2666 return -EINVAL;
2667
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002668 input = QDF_MIN(input, SIR_ESE_MAX_MEAS_IE_REQS);
2669 pEseBcnReq->numBcnReqIe = input;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002670
Srinivas Girigowda476deeb2016-07-19 16:21:29 -07002671 hdd_info("Number of Bcn Req Ie fields: %d", pEseBcnReq->numBcnReqIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002672
2673 for (j = 0; j < (pEseBcnReq->numBcnReqIe); j++) {
2674 for (i = 0; i < 4; i++) {
2675 /*
2676 * inPtr pointing to the beginning of 1st space
2677 * after number of ie fields
2678 */
2679 inPtr = strpbrk(inPtr, " ");
2680 /* no ie data after the number of ie fields argument */
2681 if (NULL == inPtr)
2682 return -EINVAL;
2683
2684 /* remove empty space */
2685 while ((SPACE_ASCII_VALUE == *inPtr)
2686 && ('\0' != *inPtr))
2687 inPtr++;
2688
2689 /*
2690 * no ie data after the number of ie fields
2691 * argument and spaces
2692 */
2693 if ('\0' == *inPtr)
2694 return -EINVAL;
2695
2696 v = sscanf(inPtr, "%31s ", buf);
2697 if (1 != v)
2698 return -EINVAL;
2699
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002700 v = kstrtou32(buf, 10, &tempInt);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002701 if (v < 0)
2702 return -EINVAL;
2703
2704 switch (i) {
2705 case 0: /* Measurement token */
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002706 if (!tempInt) {
2707 hdd_err("Invalid Measurement Token: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002708 tempInt);
2709 return -EINVAL;
2710 }
2711 pEseBcnReq->bcnReq[j].measurementToken =
2712 tempInt;
2713 break;
2714
2715 case 1: /* Channel number */
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002716 if (!tempInt ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002717 (tempInt >
2718 WNI_CFG_CURRENT_CHANNEL_STAMAX)) {
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002719 hdd_err("Invalid Channel Number: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002720 tempInt);
2721 return -EINVAL;
2722 }
2723 pEseBcnReq->bcnReq[j].channel = tempInt;
2724 break;
2725
2726 case 2: /* Scan mode */
2727 if ((tempInt < eSIR_PASSIVE_SCAN)
2728 || (tempInt > eSIR_BEACON_TABLE)) {
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002729 hdd_err("Invalid Scan Mode: %u Expected{0|1|2}",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002730 tempInt);
2731 return -EINVAL;
2732 }
2733 pEseBcnReq->bcnReq[j].scanMode = tempInt;
2734 break;
2735
2736 case 3: /* Measurement duration */
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002737 if ((!tempInt
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002738 && (pEseBcnReq->bcnReq[j].scanMode !=
2739 eSIR_BEACON_TABLE)) ||
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002740 (pEseBcnReq->bcnReq[j].scanMode ==
2741 eSIR_BEACON_TABLE)) {
2742 hdd_err("Invalid Measurement Duration: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002743 tempInt);
2744 return -EINVAL;
2745 }
2746 pEseBcnReq->bcnReq[j].measurementDuration =
2747 tempInt;
2748 break;
2749 }
2750 }
2751 }
2752
2753 for (j = 0; j < pEseBcnReq->numBcnReqIe; j++) {
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002754 hdd_info("Index: %d Measurement Token: %u Channel: %u Scan Mode: %u Measurement Duration: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002755 j,
2756 pEseBcnReq->bcnReq[j].measurementToken,
2757 pEseBcnReq->bcnReq[j].channel,
2758 pEseBcnReq->bcnReq[j].scanMode,
2759 pEseBcnReq->bcnReq[j].measurementDuration);
2760 }
2761
2762 return 0;
2763}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002764
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002765/**
2766 * hdd_parse_get_cckm_ie() - HDD Parse and fetch the CCKM IE
2767 * @pValue: Pointer to input data
2768 * @pCckmIe: Pointer to output cckm Ie
2769 * @pCckmIeLen: Pointer to output cckm ie length
2770 *
2771 * This function parses the SETCCKM IE command
2772 * SETCCKMIE<space><ie data>
2773 *
2774 * Return: 0 for success non-zero for failure
2775 */
2776static int hdd_parse_get_cckm_ie(uint8_t *pValue, uint8_t **pCckmIe,
2777 uint8_t *pCckmIeLen)
2778{
2779 uint8_t *inPtr = pValue;
2780 uint8_t *dataEnd;
2781 int j = 0;
2782 int i = 0;
2783 uint8_t tempByte = 0;
2784 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2785 /* no argument after the command */
2786 if (NULL == inPtr) {
2787 return -EINVAL;
2788 }
2789 /* no space after the command */
2790 else if (SPACE_ASCII_VALUE != *inPtr) {
2791 return -EINVAL;
2792 }
2793 /* remove empty spaces */
2794 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2795 inPtr++;
2796 /* no argument followed by spaces */
2797 if ('\0' == *inPtr) {
2798 return -EINVAL;
2799 }
2800 /* find the length of data */
2801 dataEnd = inPtr;
2802 while (('\0' != *dataEnd)) {
2803 dataEnd++;
2804 ++(*pCckmIeLen);
2805 }
2806 if (*pCckmIeLen <= 0)
2807 return -EINVAL;
2808 /*
2809 * Allocate the number of bytes based on the number of input characters
2810 * whether it is even or odd.
2811 * if the number of input characters are even, then we need N / 2 byte.
2812 * if the number of input characters are odd, then we need do
2813 * (N + 1) / 2 to compensate rounding off.
2814 * For example, if N = 18, then (18 + 1) / 2 = 9 bytes are enough.
2815 * If N = 19, then we need 10 bytes, hence (19 + 1) / 2 = 10 bytes
2816 */
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302817 *pCckmIe = qdf_mem_malloc((*pCckmIeLen + 1) / 2);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002818 if (NULL == *pCckmIe) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002819 hdd_err("qdf_mem_malloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002820 return -ENOMEM;
2821 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302822 qdf_mem_zero(*pCckmIe, (*pCckmIeLen + 1) / 2);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002823 /*
2824 * the buffer received from the upper layer is character buffer,
2825 * we need to prepare the buffer taking 2 characters in to a U8 hex
2826 * decimal number for example 7f0000f0...form a buffer to contain
2827 * 7f in 0th location, 00 in 1st and f0 in 3rd location
2828 */
2829 for (i = 0, j = 0; j < *pCckmIeLen; j += 2) {
2830 tempByte = (hex_to_bin(inPtr[j]) << 4) |
2831 (hex_to_bin(inPtr[j + 1]));
2832 (*pCckmIe)[i++] = tempByte;
2833 }
2834 *pCckmIeLen = i;
2835 return 0;
2836}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08002837#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002838
2839int wlan_hdd_set_mc_rate(hdd_adapter_t *pAdapter, int targetRate)
2840{
2841 tSirRateUpdateInd rateUpdate = {0};
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302842 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002843 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
2844 struct hdd_config *pConfig = NULL;
2845
2846 if (pHddCtx == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002847 hdd_err("HDD context is null");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002848 return -EINVAL;
2849 }
Krunal Sonibe766b02016-03-10 13:00:44 -08002850 if ((QDF_IBSS_MODE != pAdapter->device_mode) &&
2851 (QDF_SAP_MODE != pAdapter->device_mode) &&
2852 (QDF_STA_MODE != pAdapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002853 hdd_err("Received SETMCRATE cmd in invalid mode %s(%d)",
2854 hdd_device_mode_to_string(pAdapter->device_mode),
2855 pAdapter->device_mode);
2856 hdd_err("SETMCRATE cmd is allowed only in STA, IBSS or SOFTAP mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002857 return -EINVAL;
2858 }
2859 pConfig = pHddCtx->config;
2860 rateUpdate.nss = (pConfig->enable2x2 == 0) ? 0 : 1;
2861 rateUpdate.dev_mode = pAdapter->device_mode;
2862 rateUpdate.mcastDataRate24GHz = targetRate;
2863 rateUpdate.mcastDataRate24GHzTxFlag = 1;
2864 rateUpdate.mcastDataRate5GHz = targetRate;
2865 rateUpdate.bcastDataRate = -1;
Anurag Chouhanc5548422016-02-24 18:33:27 +05302866 qdf_copy_macaddr(&rateUpdate.bssid, &pAdapter->macAddressCurrent);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002867 hdd_info("MC Target rate %d, mac = %pM, dev_mode %s(%d)",
2868 rateUpdate.mcastDataRate24GHz, rateUpdate.bssid.bytes,
2869 hdd_device_mode_to_string(pAdapter->device_mode),
2870 pAdapter->device_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002871 status = sme_send_rate_update_ind(pHddCtx->hHal, &rateUpdate);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302872 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002873 hdd_err("SETMCRATE failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002874 return -EFAULT;
2875 }
2876 return 0;
2877}
2878
2879static int drv_cmd_p2p_dev_addr(hdd_adapter_t *adapter,
2880 hdd_context_t *hdd_ctx,
2881 uint8_t *command,
2882 uint8_t command_len,
2883 hdd_priv_data_t *priv_data)
2884{
2885 int ret = 0;
2886
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302887 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002888 TRACE_CODE_HDD_P2P_DEV_ADDR_IOCTL,
2889 adapter->sessionId,
2890 (unsigned)(*(hdd_ctx->p2pDeviceAddress.bytes + 2)
2891 << 24 | *(hdd_ctx->p2pDeviceAddress.bytes
2892 + 3) << 16 | *(hdd_ctx->
2893 p2pDeviceAddress.bytes + 4) << 8 |
2894 *(hdd_ctx->p2pDeviceAddress.bytes +
2895 5))));
2896
2897 if (copy_to_user(priv_data->buf, hdd_ctx->p2pDeviceAddress.bytes,
2898 sizeof(tSirMacAddr))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002899 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002900 ret = -EFAULT;
2901 }
2902
2903 return ret;
2904}
2905
2906/**
2907 * drv_cmd_p2p_set_noa() - Handler for P2P_SET_NOA driver command
2908 * @adapter: Adapter on which the command was received
2909 * @hdd_ctx: HDD global context
2910 * @command: Entire driver command received from userspace
2911 * @command_len: Length of @command
2912 * @priv_data: Pointer to ioctl private data structure
2913 *
2914 * This is a trivial command hander function which simply forwards the
2915 * command to the actual command processor within the P2P module.
2916 *
2917 * Return: 0 on success, non-zero on failure
2918 */
2919static int drv_cmd_p2p_set_noa(hdd_adapter_t *adapter,
2920 hdd_context_t *hdd_ctx,
2921 uint8_t *command,
2922 uint8_t command_len,
2923 hdd_priv_data_t *priv_data)
2924{
2925 return hdd_set_p2p_noa(adapter->dev, command);
2926}
2927
2928/**
2929 * drv_cmd_p2p_set_ps() - Handler for P2P_SET_PS driver command
2930 * @adapter: Adapter on which the command was received
2931 * @hdd_ctx: HDD global context
2932 * @command: Entire driver command received from userspace
2933 * @command_len: Length of @command
2934 * @priv_data: Pointer to ioctl private data structure
2935 *
2936 * This is a trivial command hander function which simply forwards the
2937 * command to the actual command processor within the P2P module.
2938 *
2939 * Return: 0 on success, non-zero on failure
2940 */
2941static int drv_cmd_p2p_set_ps(hdd_adapter_t *adapter,
2942 hdd_context_t *hdd_ctx,
2943 uint8_t *command,
2944 uint8_t command_len,
2945 hdd_priv_data_t *priv_data)
2946{
2947 return hdd_set_p2p_opps(adapter->dev, command);
2948}
2949
2950static int drv_cmd_set_band(hdd_adapter_t *adapter,
2951 hdd_context_t *hdd_ctx,
2952 uint8_t *command,
2953 uint8_t command_len,
2954 hdd_priv_data_t *priv_data)
2955{
2956 int ret = 0;
2957
2958 uint8_t *ptr = command;
2959
2960 /* Change band request received */
2961
2962 /*
2963 * First 8 bytes will have "SETBAND " and
2964 * 9 byte will have band setting value
2965 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002966 hdd_info("SetBandCommand Info comm %s UL %d, TL %d",
2967 command, priv_data->used_len,
2968 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002969
2970 /* Change band request received */
2971 ret = hdd_set_band_helper(adapter->dev, ptr);
2972
2973 return ret;
2974}
2975
2976static int drv_cmd_set_wmmps(hdd_adapter_t *adapter,
2977 hdd_context_t *hdd_ctx,
2978 uint8_t *command,
2979 uint8_t command_len,
2980 hdd_priv_data_t *priv_data)
2981{
2982 return hdd_wmmps_helper(adapter, command);
2983}
2984
2985static int drv_cmd_country(hdd_adapter_t *adapter,
2986 hdd_context_t *hdd_ctx,
2987 uint8_t *command,
2988 uint8_t command_len,
2989 hdd_priv_data_t *priv_data)
2990{
2991 int ret = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302992 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002993 unsigned long rc;
2994 char *country_code;
2995
2996 country_code = command + 8;
2997
2998 INIT_COMPLETION(adapter->change_country_code);
2999
3000 status = sme_change_country_code(hdd_ctx->hHal,
3001 wlan_hdd_change_country_code_callback,
3002 country_code,
3003 adapter,
3004 hdd_ctx->pcds_context,
3005 eSIR_TRUE,
3006 eSIR_TRUE);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303007 if (status == QDF_STATUS_SUCCESS) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003008 rc = wait_for_completion_timeout(
3009 &adapter->change_country_code,
3010 msecs_to_jiffies(WLAN_WAIT_TIME_COUNTRY));
3011 if (!rc)
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003012 hdd_err("SME while setting country code timed out");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003013 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003014 hdd_err("SME Change Country code fail, status %d",
3015 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003016 ret = -EINVAL;
3017 }
3018
3019 return ret;
3020}
3021
3022static int drv_cmd_set_roam_trigger(hdd_adapter_t *adapter,
3023 hdd_context_t *hdd_ctx,
3024 uint8_t *command,
3025 uint8_t command_len,
3026 hdd_priv_data_t *priv_data)
3027{
3028 int ret = 0;
3029 uint8_t *value = command;
3030 int8_t rssi = 0;
3031 uint8_t lookUpThreshold = CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_DEFAULT;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303032 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003033
3034 /* Move pointer to ahead of SETROAMTRIGGER<delimiter> */
3035 value = value + command_len + 1;
3036
3037 /* Convert the value from ascii to integer */
3038 ret = kstrtos8(value, 10, &rssi);
3039 if (ret < 0) {
3040 /*
3041 * If the input value is greater than max value of datatype,
3042 * then also kstrtou8 fails
3043 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003044 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
3045 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN,
3046 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003047 ret = -EINVAL;
3048 goto exit;
3049 }
3050
3051 lookUpThreshold = abs(rssi);
3052
3053 if ((lookUpThreshold < CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN)
3054 || (lookUpThreshold > CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003055 hdd_err("Neighbor lookup threshold value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003056 lookUpThreshold,
3057 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN,
3058 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX);
3059 ret = -EINVAL;
3060 goto exit;
3061 }
3062
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303063 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003064 TRACE_CODE_HDD_SETROAMTRIGGER_IOCTL,
3065 adapter->sessionId, lookUpThreshold));
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003066 hdd_info("Received Command to Set Roam trigger (Neighbor lookup threshold) = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003067 lookUpThreshold);
3068
3069 hdd_ctx->config->nNeighborLookupRssiThreshold = lookUpThreshold;
3070 status = sme_set_neighbor_lookup_rssi_threshold(hdd_ctx->hHal,
3071 adapter->sessionId,
3072 lookUpThreshold);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303073 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003074 hdd_err("Failed to set roam trigger, try again");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003075 ret = -EPERM;
3076 goto exit;
3077 }
3078
3079exit:
3080 return ret;
3081}
3082
3083static int drv_cmd_get_roam_trigger(hdd_adapter_t *adapter,
3084 hdd_context_t *hdd_ctx,
3085 uint8_t *command,
3086 uint8_t command_len,
3087 hdd_priv_data_t *priv_data)
3088{
3089 int ret = 0;
3090 uint8_t lookUpThreshold =
3091 sme_get_neighbor_lookup_rssi_threshold(hdd_ctx->hHal);
3092 int rssi = (-1) * lookUpThreshold;
3093 char extra[32];
3094 uint8_t len = 0;
3095
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303096 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003097 TRACE_CODE_HDD_GETROAMTRIGGER_IOCTL,
3098 adapter->sessionId, lookUpThreshold));
3099
3100 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303101 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003102 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003103 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003104 ret = -EFAULT;
3105 }
3106
3107 return ret;
3108}
3109
3110static int drv_cmd_set_roam_scan_period(hdd_adapter_t *adapter,
3111 hdd_context_t *hdd_ctx,
3112 uint8_t *command,
3113 uint8_t command_len,
3114 hdd_priv_data_t *priv_data)
3115{
3116 int ret = 0;
3117 uint8_t *value = command;
3118 uint8_t roamScanPeriod = 0;
3119 uint16_t neighborEmptyScanRefreshPeriod =
3120 CFG_EMPTY_SCAN_REFRESH_PERIOD_DEFAULT;
3121
3122 /* input refresh period is in terms of seconds */
3123
3124 /* Move pointer to ahead of SETROAMSCANPERIOD<delimiter> */
3125 value = value + command_len + 1;
3126
3127 /* Convert the value from ascii to integer */
3128 ret = kstrtou8(value, 10, &roamScanPeriod);
3129 if (ret < 0) {
3130 /*
3131 * If the input value is greater than max value of datatype,
3132 * then also kstrtou8 fails
3133 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003134 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
3135 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000),
3136 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003137 ret = -EINVAL;
3138 goto exit;
3139 }
3140
3141 if ((roamScanPeriod < (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000))
3142 || (roamScanPeriod > (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003143 hdd_err("Roam scan period value %d is out of range (Min: %d Max: %d)",
3144 roamScanPeriod,
3145 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000),
3146 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003147 ret = -EINVAL;
3148 goto exit;
3149 }
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303150 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003151 TRACE_CODE_HDD_SETROAMSCANPERIOD_IOCTL,
3152 adapter->sessionId, roamScanPeriod));
3153 neighborEmptyScanRefreshPeriod = roamScanPeriod * 1000;
3154
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003155 hdd_info("Received Command to Set roam scan period (Empty Scan refresh period) = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003156 roamScanPeriod);
3157
3158 hdd_ctx->config->nEmptyScanRefreshPeriod =
3159 neighborEmptyScanRefreshPeriod;
3160 sme_update_empty_scan_refresh_period(hdd_ctx->hHal,
3161 adapter->sessionId,
3162 neighborEmptyScanRefreshPeriod);
3163
3164exit:
3165 return ret;
3166}
3167
3168static int drv_cmd_get_roam_scan_period(hdd_adapter_t *adapter,
3169 hdd_context_t *hdd_ctx,
3170 uint8_t *command,
3171 uint8_t command_len,
3172 hdd_priv_data_t *priv_data)
3173{
3174 int ret = 0;
3175 uint16_t nEmptyScanRefreshPeriod =
3176 sme_get_empty_scan_refresh_period(hdd_ctx->hHal);
3177 char extra[32];
3178 uint8_t len = 0;
3179
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303180 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003181 TRACE_CODE_HDD_GETROAMSCANPERIOD_IOCTL,
3182 adapter->sessionId,
3183 nEmptyScanRefreshPeriod));
3184 len = scnprintf(extra, sizeof(extra), "%s %d",
3185 "GETROAMSCANPERIOD",
3186 (nEmptyScanRefreshPeriod / 1000));
3187 /* Returned value is in units of seconds */
Anurag Chouhan6d760662016-02-20 16:05:43 +05303188 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003189 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003190 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003191 ret = -EFAULT;
3192 }
3193
3194 return ret;
3195}
3196
3197static int drv_cmd_set_roam_scan_refresh_period(hdd_adapter_t *adapter,
3198 hdd_context_t *hdd_ctx,
3199 uint8_t *command,
3200 uint8_t command_len,
3201 hdd_priv_data_t *priv_data)
3202{
3203 int ret = 0;
3204 uint8_t *value = command;
3205 uint8_t roamScanRefreshPeriod = 0;
3206 uint16_t neighborScanRefreshPeriod =
3207 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_DEFAULT;
3208
3209 /* input refresh period is in terms of seconds */
3210 /* Move pointer to ahead of SETROAMSCANREFRESHPERIOD<delimiter> */
3211 value = value + command_len + 1;
3212
3213 /* Convert the value from ascii to integer */
3214 ret = kstrtou8(value, 10, &roamScanRefreshPeriod);
3215 if (ret < 0) {
3216 /*
3217 * If the input value is greater than max value of datatype,
3218 * then also kstrtou8 fails
3219 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003220 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
3221 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN / 1000,
3222 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX / 1000);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003223 ret = -EINVAL;
3224 goto exit;
3225 }
3226
3227 if ((roamScanRefreshPeriod <
3228 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN / 1000))
3229 || (roamScanRefreshPeriod >
3230 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX / 1000))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003231 hdd_err("Neighbor scan results refresh period value %d is out of range (Min: %d Max: %d)",
3232 roamScanRefreshPeriod,
3233 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN
3234 / 1000),
3235 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX
3236 / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003237 ret = -EINVAL;
3238 goto exit;
3239 }
3240 neighborScanRefreshPeriod = roamScanRefreshPeriod * 1000;
3241
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003242 hdd_info("Received Command to Set roam scan refresh period (Scan refresh period) = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003243 roamScanRefreshPeriod);
3244
3245 hdd_ctx->config->nNeighborResultsRefreshPeriod =
3246 neighborScanRefreshPeriod;
3247 sme_set_neighbor_scan_refresh_period(hdd_ctx->hHal,
3248 adapter->sessionId,
3249 neighborScanRefreshPeriod);
3250
3251exit:
3252 return ret;
3253}
3254
3255static int drv_cmd_get_roam_scan_refresh_period(hdd_adapter_t *adapter,
3256 hdd_context_t *hdd_ctx,
3257 uint8_t *command,
3258 uint8_t command_len,
3259 hdd_priv_data_t *priv_data)
3260{
3261 int ret = 0;
3262 uint16_t value =
3263 sme_get_neighbor_scan_refresh_period(hdd_ctx->hHal);
3264 char extra[32];
3265 uint8_t len = 0;
3266
3267 len = scnprintf(extra, sizeof(extra), "%s %d",
3268 "GETROAMSCANREFRESHPERIOD",
3269 (value / 1000));
3270 /* Returned value is in units of seconds */
Anurag Chouhan6d760662016-02-20 16:05:43 +05303271 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003272 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003273 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003274 ret = -EFAULT;
3275 }
3276
3277 return ret;
3278}
3279
3280static int drv_cmd_set_roam_mode(hdd_adapter_t *adapter,
3281 hdd_context_t *hdd_ctx,
3282 uint8_t *command,
3283 uint8_t command_len,
3284 hdd_priv_data_t *priv_data)
3285{
3286 int ret = 0;
3287 uint8_t *value = command;
3288 uint8_t roamMode = CFG_LFR_FEATURE_ENABLED_DEFAULT;
3289
3290 /* Move pointer to ahead of SETROAMMODE<delimiter> */
3291 value = value + SIZE_OF_SETROAMMODE + 1;
3292
3293 /* Convert the value from ascii to integer */
3294 ret = kstrtou8(value, SIZE_OF_SETROAMMODE, &roamMode);
3295 if (ret < 0) {
3296 /*
3297 * If the input value is greater than max value of datatype,
3298 * then also kstrtou8 fails
3299 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003300 hdd_err("kstrtou8 failed range [%d - %d]",
3301 CFG_LFR_FEATURE_ENABLED_MIN,
3302 CFG_LFR_FEATURE_ENABLED_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003303 ret = -EINVAL;
3304 goto exit;
3305 }
3306 if ((roamMode < CFG_LFR_FEATURE_ENABLED_MIN) ||
3307 (roamMode > CFG_LFR_FEATURE_ENABLED_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003308 hdd_err("Roam Mode value %d is out of range (Min: %d Max: %d)",
3309 roamMode,
3310 CFG_LFR_FEATURE_ENABLED_MIN,
3311 CFG_LFR_FEATURE_ENABLED_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003312 ret = -EINVAL;
3313 goto exit;
3314 }
3315
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003316 hdd_debug("Received Command to Set Roam Mode = %d",
3317 roamMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003318 /*
3319 * Note that
3320 * SETROAMMODE 0 is to enable LFR while
3321 * SETROAMMODE 1 is to disable LFR, but
3322 * notify_is_fast_roam_ini_feature_enabled 0/1 is to
3323 * enable/disable. So, we have to invert the value
3324 * to call sme_update_is_fast_roam_ini_feature_enabled.
3325 */
3326 if (CFG_LFR_FEATURE_ENABLED_MIN == roamMode)
3327 roamMode = CFG_LFR_FEATURE_ENABLED_MAX; /* Roam enable */
3328 else
3329 roamMode = CFG_LFR_FEATURE_ENABLED_MIN; /* Roam disable */
3330
3331 hdd_ctx->config->isFastRoamIniFeatureEnabled = roamMode;
3332 if (roamMode) {
3333 hdd_ctx->config->isRoamOffloadScanEnabled = roamMode;
3334 sme_update_roam_scan_offload_enabled(
3335 (tHalHandle)(hdd_ctx->hHal),
3336 hdd_ctx->config->isRoamOffloadScanEnabled);
3337 sme_update_is_fast_roam_ini_feature_enabled(
3338 hdd_ctx->hHal,
3339 adapter->sessionId,
3340 roamMode);
3341 } else {
3342 sme_update_is_fast_roam_ini_feature_enabled(
3343 hdd_ctx->hHal,
3344 adapter->sessionId,
3345 roamMode);
3346 hdd_ctx->config->isRoamOffloadScanEnabled = roamMode;
3347 sme_update_roam_scan_offload_enabled(
3348 (tHalHandle)(hdd_ctx->hHal),
3349 hdd_ctx->config->isRoamOffloadScanEnabled);
3350 }
3351
3352
3353exit:
3354 return ret;
3355}
3356
3357static int drv_cmd_get_roam_mode(hdd_adapter_t *adapter,
3358 hdd_context_t *hdd_ctx,
3359 uint8_t *command,
3360 uint8_t command_len,
3361 hdd_priv_data_t *priv_data)
3362{
3363 int ret = 0;
3364 bool roamMode = sme_get_is_lfr_feature_enabled(hdd_ctx->hHal);
3365 char extra[32];
3366 uint8_t len = 0;
3367
3368 /*
3369 * roamMode value shall be inverted because the sementics is different.
3370 */
3371 if (CFG_LFR_FEATURE_ENABLED_MIN == roamMode)
3372 roamMode = CFG_LFR_FEATURE_ENABLED_MAX;
3373 else
3374 roamMode = CFG_LFR_FEATURE_ENABLED_MIN;
3375
3376 len = scnprintf(extra, sizeof(extra), "%s %d", command, roamMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303377 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003378 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003379 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003380 ret = -EFAULT;
3381 }
3382
3383 return ret;
3384}
3385
3386static int drv_cmd_set_roam_delta(hdd_adapter_t *adapter,
3387 hdd_context_t *hdd_ctx,
3388 uint8_t *command,
3389 uint8_t command_len,
3390 hdd_priv_data_t *priv_data)
3391{
3392 int ret = 0;
3393 uint8_t *value = command;
3394 uint8_t roamRssiDiff = CFG_ROAM_RSSI_DIFF_DEFAULT;
3395
3396 /* Move pointer to ahead of SETROAMDELTA<delimiter> */
3397 value = value + command_len + 1;
3398
3399 /* Convert the value from ascii to integer */
3400 ret = kstrtou8(value, 10, &roamRssiDiff);
3401 if (ret < 0) {
3402 /*
3403 * If the input value is greater than max value of datatype,
3404 * then also kstrtou8 fails
3405 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003406 hdd_err("kstrtou8 failed range [%d - %d]",
3407 CFG_ROAM_RSSI_DIFF_MIN,
3408 CFG_ROAM_RSSI_DIFF_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003409 ret = -EINVAL;
3410 goto exit;
3411 }
3412
3413 if ((roamRssiDiff < CFG_ROAM_RSSI_DIFF_MIN) ||
3414 (roamRssiDiff > CFG_ROAM_RSSI_DIFF_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003415 hdd_err("Roam rssi diff value %d is out of range (Min: %d Max: %d)",
3416 roamRssiDiff,
3417 CFG_ROAM_RSSI_DIFF_MIN,
3418 CFG_ROAM_RSSI_DIFF_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003419 ret = -EINVAL;
3420 goto exit;
3421 }
3422
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003423 hdd_info("Received Command to Set roam rssi diff = %d",
3424 roamRssiDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003425
3426 hdd_ctx->config->RoamRssiDiff = roamRssiDiff;
3427 sme_update_roam_rssi_diff(hdd_ctx->hHal,
3428 adapter->sessionId,
3429 roamRssiDiff);
3430
3431exit:
3432 return ret;
3433}
3434
3435static int drv_cmd_get_roam_delta(hdd_adapter_t *adapter,
3436 hdd_context_t *hdd_ctx,
3437 uint8_t *command,
3438 uint8_t command_len,
3439 hdd_priv_data_t *priv_data)
3440{
3441 int ret = 0;
3442 uint8_t roamRssiDiff =
3443 sme_get_roam_rssi_diff(hdd_ctx->hHal);
3444 char extra[32];
3445 uint8_t len = 0;
3446
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303447 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003448 TRACE_CODE_HDD_GETROAMDELTA_IOCTL,
3449 adapter->sessionId, roamRssiDiff));
3450
3451 len = scnprintf(extra, sizeof(extra), "%s %d",
3452 command, roamRssiDiff);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303453 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003454
3455 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003456 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003457 ret = -EFAULT;
3458 }
3459
3460 return ret;
3461}
3462
3463static int drv_cmd_get_band(hdd_adapter_t *adapter,
3464 hdd_context_t *hdd_ctx,
3465 uint8_t *command,
3466 uint8_t command_len,
3467 hdd_priv_data_t *priv_data)
3468{
3469 int ret = 0;
3470 int band = -1;
3471 char extra[32];
3472 uint8_t len = 0;
3473
3474 hdd_get_band_helper(hdd_ctx, &band);
3475
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303476 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003477 TRACE_CODE_HDD_GETBAND_IOCTL,
3478 adapter->sessionId, band));
3479
3480 len = scnprintf(extra, sizeof(extra), "%s %d", command, band);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303481 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003482
3483 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003484 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003485 ret = -EFAULT;
3486 }
3487
3488 return ret;
3489}
3490
3491static int drv_cmd_set_roam_scan_channels(hdd_adapter_t *adapter,
3492 hdd_context_t *hdd_ctx,
3493 uint8_t *command,
3494 uint8_t command_len,
3495 hdd_priv_data_t *priv_data)
3496{
3497 return hdd_parse_set_roam_scan_channels(adapter, command);
3498}
3499
3500static int drv_cmd_get_roam_scan_channels(hdd_adapter_t *adapter,
3501 hdd_context_t *hdd_ctx,
3502 uint8_t *command,
3503 uint8_t command_len,
3504 hdd_priv_data_t *priv_data)
3505{
3506 int ret = 0;
3507 uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
3508 uint8_t numChannels = 0;
3509 uint8_t j = 0;
3510 char extra[128] = { 0 };
3511 int len;
3512
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303513 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003514 sme_get_roam_scan_channel_list(hdd_ctx->hHal,
3515 ChannelList,
3516 &numChannels,
3517 adapter->sessionId)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003518 hdd_alert("failed to get roam scan channel list");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003519 ret = -EFAULT;
3520 goto exit;
3521 }
3522
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303523 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003524 TRACE_CODE_HDD_GETROAMSCANCHANNELS_IOCTL,
3525 adapter->sessionId, numChannels));
3526 /*
3527 * output channel list is of the format
3528 * [Number of roam scan channels][Channel1][Channel2]...
3529 * copy the number of channels in the 0th index
3530 */
3531 len = scnprintf(extra, sizeof(extra), "%s %d", command,
3532 numChannels);
3533 for (j = 0; (j < numChannels); j++)
3534 len += scnprintf(extra + len, sizeof(extra) - len,
3535 " %d", ChannelList[j]);
3536
Anurag Chouhan6d760662016-02-20 16:05:43 +05303537 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003538 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003539 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003540 ret = -EFAULT;
3541 goto exit;
3542 }
3543
3544exit:
3545 return ret;
3546}
3547
3548static int drv_cmd_get_ccx_mode(hdd_adapter_t *adapter,
3549 hdd_context_t *hdd_ctx,
3550 uint8_t *command,
3551 uint8_t command_len,
3552 hdd_priv_data_t *priv_data)
3553{
3554 int ret = 0;
3555 bool eseMode = sme_get_is_ese_feature_enabled(hdd_ctx->hHal);
3556 char extra[32];
3557 uint8_t len = 0;
3558
3559 /*
3560 * Check if the features OKC/ESE/11R are supported simultaneously,
3561 * then this operation is not permitted (return FAILURE)
3562 */
3563 if (eseMode &&
3564 hdd_is_okc_mode_enabled(hdd_ctx) &&
3565 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003566 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003567 ret = -EPERM;
3568 goto exit;
3569 }
3570
3571 len = scnprintf(extra, sizeof(extra), "%s %d",
3572 "GETCCXMODE", eseMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303573 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003574 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003575 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003576 ret = -EFAULT;
3577 goto exit;
3578 }
3579
3580exit:
3581 return ret;
3582}
3583
3584static int drv_cmd_get_okc_mode(hdd_adapter_t *adapter,
3585 hdd_context_t *hdd_ctx,
3586 uint8_t *command,
3587 uint8_t command_len,
3588 hdd_priv_data_t *priv_data)
3589{
3590 int ret = 0;
3591 bool okcMode = hdd_is_okc_mode_enabled(hdd_ctx);
3592 char extra[32];
3593 uint8_t len = 0;
3594
3595 /*
3596 * Check if the features OKC/ESE/11R are supported simultaneously,
3597 * then this operation is not permitted (return FAILURE)
3598 */
3599 if (okcMode &&
3600 sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
3601 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003602 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003603 ret = -EPERM;
3604 goto exit;
3605 }
3606
3607 len = scnprintf(extra, sizeof(extra), "%s %d",
3608 "GETOKCMODE", okcMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303609 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003610
3611 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003612 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003613 ret = -EFAULT;
3614 goto exit;
3615 }
3616
3617exit:
3618 return ret;
3619}
3620
3621static int drv_cmd_get_fast_roam(hdd_adapter_t *adapter,
3622 hdd_context_t *hdd_ctx,
3623 uint8_t *command,
3624 uint8_t command_len,
3625 hdd_priv_data_t *priv_data)
3626{
3627 int ret = 0;
3628 bool lfrMode = sme_get_is_lfr_feature_enabled(hdd_ctx->hHal);
3629 char extra[32];
3630 uint8_t len = 0;
3631
3632 len = scnprintf(extra, sizeof(extra), "%s %d",
3633 "GETFASTROAM", lfrMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303634 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003635
3636 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003637 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003638 ret = -EFAULT;
3639 }
3640
3641 return ret;
3642}
3643
3644static int drv_cmd_get_fast_transition(hdd_adapter_t *adapter,
3645 hdd_context_t *hdd_ctx,
3646 uint8_t *command,
3647 uint8_t command_len,
3648 hdd_priv_data_t *priv_data)
3649{
3650 int ret = 0;
3651 bool ft = sme_get_is_ft_feature_enabled(hdd_ctx->hHal);
3652 char extra[32];
3653 uint8_t len = 0;
3654
3655 len = scnprintf(extra, sizeof(extra), "%s %d",
3656 "GETFASTTRANSITION", ft);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303657 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003658
3659 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003660 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003661 ret = -EFAULT;
3662 }
3663
3664 return ret;
3665}
3666
3667static int drv_cmd_set_roam_scan_channel_min_time(hdd_adapter_t *adapter,
3668 hdd_context_t *hdd_ctx,
3669 uint8_t *command,
3670 uint8_t command_len,
3671 hdd_priv_data_t *priv_data)
3672{
3673 int ret = 0;
3674 uint8_t *value = command;
3675 uint8_t minTime = CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_DEFAULT;
3676
3677 /* Move pointer to ahead of SETROAMSCANCHANNELMINTIME<delimiter> */
3678 value = value + command_len + 1;
3679
3680 /* Convert the value from ascii to integer */
3681 ret = kstrtou8(value, 10, &minTime);
3682 if (ret < 0) {
3683 /*
3684 * If the input value is greater than max value of datatype,
3685 * then also kstrtou8 fails
3686 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003687 hdd_err("kstrtou8 failed range [%d - %d]",
3688 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN,
3689 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003690 ret = -EINVAL;
3691 goto exit;
3692 }
3693
3694 if ((minTime < CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN) ||
3695 (minTime > CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003696 hdd_err("scan min channel time value %d is out of range (Min: %d Max: %d)",
3697 minTime,
3698 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN,
3699 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003700 ret = -EINVAL;
3701 goto exit;
3702 }
3703
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303704 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003705 TRACE_CODE_HDD_SETROAMSCANCHANNELMINTIME_IOCTL,
3706 adapter->sessionId, minTime));
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003707 hdd_info("Received Command to change channel min time = %d",
3708 minTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003709
3710 hdd_ctx->config->nNeighborScanMinChanTime = minTime;
3711 sme_set_neighbor_scan_min_chan_time(hdd_ctx->hHal,
3712 minTime,
3713 adapter->sessionId);
3714
3715exit:
3716 return ret;
3717}
3718
3719static int drv_cmd_send_action_frame(hdd_adapter_t *adapter,
3720 hdd_context_t *hdd_ctx,
3721 uint8_t *command,
3722 uint8_t command_len,
3723 hdd_priv_data_t *priv_data)
3724{
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07003725 return hdd_parse_sendactionframe(adapter, command,
3726 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003727}
3728
3729static int drv_cmd_get_roam_scan_channel_min_time(hdd_adapter_t *adapter,
3730 hdd_context_t *hdd_ctx,
3731 uint8_t *command,
3732 uint8_t command_len,
3733 hdd_priv_data_t *priv_data)
3734{
3735 int ret = 0;
3736 uint16_t val = sme_get_neighbor_scan_min_chan_time(hdd_ctx->hHal,
3737 adapter->sessionId);
3738 char extra[32];
3739 uint8_t len = 0;
3740
3741 /* value is interms of msec */
3742 len = scnprintf(extra, sizeof(extra), "%s %d",
3743 "GETROAMSCANCHANNELMINTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303744 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003745
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303746 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003747 TRACE_CODE_HDD_GETROAMSCANCHANNELMINTIME_IOCTL,
3748 adapter->sessionId, val));
3749
3750 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003751 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003752 ret = -EFAULT;
3753 }
3754
3755 return ret;
3756}
3757
3758static int drv_cmd_set_scan_channel_time(hdd_adapter_t *adapter,
3759 hdd_context_t *hdd_ctx,
3760 uint8_t *command,
3761 uint8_t command_len,
3762 hdd_priv_data_t *priv_data)
3763{
3764 int ret = 0;
3765 uint8_t *value = command;
3766 uint16_t maxTime = CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_DEFAULT;
3767
3768 /* Move pointer to ahead of SETSCANCHANNELTIME<delimiter> */
3769 value = value + command_len + 1;
3770
3771 /* Convert the value from ascii to integer */
3772 ret = kstrtou16(value, 10, &maxTime);
3773 if (ret < 0) {
3774 /*
3775 * If the input value is greater than max value of datatype,
3776 * then also kstrtou8 fails
3777 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003778 hdd_err("kstrtou16 failed range [%d - %d]",
3779 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN,
3780 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003781 ret = -EINVAL;
3782 goto exit;
3783 }
3784
3785 if ((maxTime < CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN) ||
3786 (maxTime > CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003787 hdd_err("lfr mode value %d is out of range (Min: %d Max: %d)",
3788 maxTime,
3789 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN,
3790 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003791 ret = -EINVAL;
3792 goto exit;
3793 }
3794
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003795 hdd_info("Received Command to change channel max time = %d",
3796 maxTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003797
3798 hdd_ctx->config->nNeighborScanMaxChanTime = maxTime;
3799 sme_set_neighbor_scan_max_chan_time(hdd_ctx->hHal,
3800 adapter->sessionId,
3801 maxTime);
3802
3803exit:
3804 return ret;
3805}
3806
3807static int drv_cmd_get_scan_channel_time(hdd_adapter_t *adapter,
3808 hdd_context_t *hdd_ctx,
3809 uint8_t *command,
3810 uint8_t command_len,
3811 hdd_priv_data_t *priv_data)
3812{
3813 int ret = 0;
3814 uint16_t val = sme_get_neighbor_scan_max_chan_time(hdd_ctx->hHal,
3815 adapter->sessionId);
3816 char extra[32];
3817 uint8_t len = 0;
3818
3819 /* value is interms of msec */
3820 len = scnprintf(extra, sizeof(extra), "%s %d",
3821 "GETSCANCHANNELTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303822 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003823
3824 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003825 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003826 ret = -EFAULT;
3827 }
3828
3829 return ret;
3830}
3831
3832static int drv_cmd_set_scan_home_time(hdd_adapter_t *adapter,
3833 hdd_context_t *hdd_ctx,
3834 uint8_t *command,
3835 uint8_t command_len,
3836 hdd_priv_data_t *priv_data)
3837{
3838 int ret = 0;
3839 uint8_t *value = command;
3840 uint16_t val = CFG_NEIGHBOR_SCAN_TIMER_PERIOD_DEFAULT;
3841
3842 /* Move pointer to ahead of SETSCANHOMETIME<delimiter> */
3843 value = value + command_len + 1;
3844
3845 /* Convert the value from ascii to integer */
3846 ret = kstrtou16(value, 10, &val);
3847 if (ret < 0) {
3848 /*
3849 * If the input value is greater than max value of datatype,
3850 * then also kstrtou8 fails
3851 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003852 hdd_err("kstrtou16 failed range [%d - %d]",
3853 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN,
3854 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003855 ret = -EINVAL;
3856 goto exit;
3857 }
3858
3859 if ((val < CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN) ||
3860 (val > CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003861 hdd_err("scan home time value %d is out of range (Min: %d Max: %d)",
3862 val,
3863 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN,
3864 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003865 ret = -EINVAL;
3866 goto exit;
3867 }
3868
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003869 hdd_info("Received Command to change scan home time = %d",
3870 val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003871
3872 hdd_ctx->config->nNeighborScanPeriod = val;
3873 sme_set_neighbor_scan_period(hdd_ctx->hHal,
3874 adapter->sessionId, val);
3875
3876exit:
3877 return ret;
3878}
3879
3880static int drv_cmd_get_scan_home_time(hdd_adapter_t *adapter,
3881 hdd_context_t *hdd_ctx,
3882 uint8_t *command,
3883 uint8_t command_len,
3884 hdd_priv_data_t *priv_data)
3885{
3886 int ret = 0;
3887 uint16_t val = sme_get_neighbor_scan_period(hdd_ctx->hHal,
3888 adapter->
3889 sessionId);
3890 char extra[32];
3891 uint8_t len = 0;
3892
3893 /* value is interms of msec */
3894 len = scnprintf(extra, sizeof(extra), "%s %d",
3895 "GETSCANHOMETIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303896 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003897
3898 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003899 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003900 ret = -EFAULT;
3901 }
3902
3903 return ret;
3904}
3905
3906static int drv_cmd_set_roam_intra_band(hdd_adapter_t *adapter,
3907 hdd_context_t *hdd_ctx,
3908 uint8_t *command,
3909 uint8_t command_len,
3910 hdd_priv_data_t *priv_data)
3911{
3912 int ret = 0;
3913 uint8_t *value = command;
3914 uint8_t val = CFG_ROAM_INTRA_BAND_DEFAULT;
3915
3916 /* Move pointer to ahead of SETROAMINTRABAND<delimiter> */
3917 value = value + command_len + 1;
3918
3919 /* Convert the value from ascii to integer */
3920 ret = kstrtou8(value, 10, &val);
3921 if (ret < 0) {
3922 /*
3923 * If the input value is greater than max value of datatype,
3924 * then also kstrtou8 fails
3925 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003926 hdd_err("kstrtou8 failed range [%d - %d]",
3927 CFG_ROAM_INTRA_BAND_MIN,
3928 CFG_ROAM_INTRA_BAND_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003929 ret = -EINVAL;
3930 goto exit;
3931 }
3932
3933 if ((val < CFG_ROAM_INTRA_BAND_MIN) ||
3934 (val > CFG_ROAM_INTRA_BAND_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003935 hdd_err("intra band mode value %d is out of range (Min: %d Max: %d)",
3936 val,
3937 CFG_ROAM_INTRA_BAND_MIN,
3938 CFG_ROAM_INTRA_BAND_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003939 ret = -EINVAL;
3940 goto exit;
3941 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003942 hdd_info("Received Command to change intra band = %d",
3943 val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003944
3945 hdd_ctx->config->nRoamIntraBand = val;
3946 sme_set_roam_intra_band(hdd_ctx->hHal, val);
3947
3948exit:
3949 return ret;
3950}
3951
3952static int drv_cmd_get_roam_intra_band(hdd_adapter_t *adapter,
3953 hdd_context_t *hdd_ctx,
3954 uint8_t *command,
3955 uint8_t command_len,
3956 hdd_priv_data_t *priv_data)
3957{
3958 int ret = 0;
3959 uint16_t val = sme_get_roam_intra_band(hdd_ctx->hHal);
3960 char extra[32];
3961 uint8_t len = 0;
3962
3963 /* value is interms of msec */
3964 len = scnprintf(extra, sizeof(extra), "%s %d",
3965 "GETROAMINTRABAND", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303966 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003967 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003968 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003969 ret = -EFAULT;
3970 }
3971
3972 return ret;
3973}
3974
3975static int drv_cmd_set_scan_n_probes(hdd_adapter_t *adapter,
3976 hdd_context_t *hdd_ctx,
3977 uint8_t *command,
3978 uint8_t command_len,
3979 hdd_priv_data_t *priv_data)
3980{
3981 int ret = 0;
3982 uint8_t *value = command;
3983 uint8_t nProbes = CFG_ROAM_SCAN_N_PROBES_DEFAULT;
3984
3985 /* Move pointer to ahead of SETSCANNPROBES<delimiter> */
3986 value = value + command_len + 1;
3987
3988 /* Convert the value from ascii to integer */
3989 ret = kstrtou8(value, 10, &nProbes);
3990 if (ret < 0) {
3991 /*
3992 * If the input value is greater than max value of datatype,
3993 * then also kstrtou8 fails
3994 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003995 hdd_err("kstrtou8 failed range [%d - %d]",
3996 CFG_ROAM_SCAN_N_PROBES_MIN,
3997 CFG_ROAM_SCAN_N_PROBES_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003998 ret = -EINVAL;
3999 goto exit;
4000 }
4001
4002 if ((nProbes < CFG_ROAM_SCAN_N_PROBES_MIN) ||
4003 (nProbes > CFG_ROAM_SCAN_N_PROBES_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004004 hdd_err("NProbes value %d is out of range (Min: %d Max: %d)",
4005 nProbes,
4006 CFG_ROAM_SCAN_N_PROBES_MIN,
4007 CFG_ROAM_SCAN_N_PROBES_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004008 ret = -EINVAL;
4009 goto exit;
4010 }
4011
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004012 hdd_info("Received Command to Set nProbes = %d",
4013 nProbes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004014
4015 hdd_ctx->config->nProbes = nProbes;
4016 sme_update_roam_scan_n_probes(hdd_ctx->hHal,
4017 adapter->sessionId, nProbes);
4018
4019exit:
4020 return ret;
4021}
4022
4023static int drv_cmd_get_scan_n_probes(hdd_adapter_t *adapter,
4024 hdd_context_t *hdd_ctx,
4025 uint8_t *command,
4026 uint8_t command_len,
4027 hdd_priv_data_t *priv_data)
4028{
4029 int ret = 0;
4030 uint8_t val = sme_get_roam_scan_n_probes(hdd_ctx->hHal);
4031 char extra[32];
4032 uint8_t len = 0;
4033
4034 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304035 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004036 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004037 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004038 ret = -EFAULT;
4039 }
4040
4041 return ret;
4042}
4043
4044static int drv_cmd_set_scan_home_away_time(hdd_adapter_t *adapter,
4045 hdd_context_t *hdd_ctx,
4046 uint8_t *command,
4047 uint8_t command_len,
4048 hdd_priv_data_t *priv_data)
4049{
4050 int ret = 0;
4051 uint8_t *value = command;
4052 uint16_t homeAwayTime = CFG_ROAM_SCAN_HOME_AWAY_TIME_DEFAULT;
4053
4054 /* input value is in units of msec */
4055
4056 /* Move pointer to ahead of SETSCANHOMEAWAYTIME<delimiter> */
4057 value = value + command_len + 1;
4058
4059 /* Convert the value from ascii to integer */
4060 ret = kstrtou16(value, 10, &homeAwayTime);
4061 if (ret < 0) {
4062 /*
4063 * If the input value is greater than max value of datatype,
4064 * then also kstrtou8 fails
4065 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004066 hdd_err("kstrtou8 failed range [%d - %d]",
4067 CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN,
4068 CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004069 ret = -EINVAL;
4070 goto exit;
4071 }
4072
4073 if ((homeAwayTime < CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN) ||
4074 (homeAwayTime > CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004075 hdd_err("homeAwayTime value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004076 homeAwayTime,
4077 CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN,
4078 CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX);
4079 ret = -EINVAL;
4080 goto exit;
4081 }
4082
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004083 hdd_info("Received Command to Set scan away time = %d",
4084 homeAwayTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004085
4086 if (hdd_ctx->config->nRoamScanHomeAwayTime !=
4087 homeAwayTime) {
4088 hdd_ctx->config->nRoamScanHomeAwayTime = homeAwayTime;
4089 sme_update_roam_scan_home_away_time(hdd_ctx->hHal,
4090 adapter->sessionId,
4091 homeAwayTime,
4092 true);
4093 }
4094
4095exit:
4096 return ret;
4097}
4098
4099static int drv_cmd_get_scan_home_away_time(hdd_adapter_t *adapter,
4100 hdd_context_t *hdd_ctx,
4101 uint8_t *command,
4102 uint8_t command_len,
4103 hdd_priv_data_t *priv_data)
4104{
4105 int ret = 0;
4106 uint16_t val = sme_get_roam_scan_home_away_time(hdd_ctx->hHal);
4107 char extra[32];
4108 uint8_t len = 0;
4109
4110 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304111 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004112
4113 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004114 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004115 ret = -EFAULT;
4116 }
4117
4118 return ret;
4119}
4120
4121static int drv_cmd_reassoc(hdd_adapter_t *adapter,
4122 hdd_context_t *hdd_ctx,
4123 uint8_t *command,
4124 uint8_t command_len,
4125 hdd_priv_data_t *priv_data)
4126{
4127 return hdd_parse_reassoc(adapter, command);
4128}
4129
4130static int drv_cmd_set_wes_mode(hdd_adapter_t *adapter,
4131 hdd_context_t *hdd_ctx,
4132 uint8_t *command,
4133 uint8_t command_len,
4134 hdd_priv_data_t *priv_data)
4135{
4136 int ret = 0;
4137 uint8_t *value = command;
4138 uint8_t wesMode = CFG_ENABLE_WES_MODE_NAME_DEFAULT;
4139
4140 /* Move pointer to ahead of SETWESMODE<delimiter> */
4141 value = value + command_len + 1;
4142
4143 /* Convert the value from ascii to integer */
4144 ret = kstrtou8(value, 10, &wesMode);
4145 if (ret < 0) {
4146 /*
4147 * If the input value is greater than max value of datatype,
4148 * then also kstrtou8 fails
4149 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004150 hdd_err("kstrtou8 failed range [%d - %d]",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004151 CFG_ENABLE_WES_MODE_NAME_MIN,
4152 CFG_ENABLE_WES_MODE_NAME_MAX);
4153 ret = -EINVAL;
4154 goto exit;
4155 }
4156
4157 if ((wesMode < CFG_ENABLE_WES_MODE_NAME_MIN) ||
4158 (wesMode > CFG_ENABLE_WES_MODE_NAME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004159 hdd_err("WES Mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004160 wesMode,
4161 CFG_ENABLE_WES_MODE_NAME_MIN,
4162 CFG_ENABLE_WES_MODE_NAME_MAX);
4163 ret = -EINVAL;
4164 goto exit;
4165 }
4166
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004167 hdd_info("Received Command to Set WES Mode rssi diff = %d",
4168 wesMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004169
4170 hdd_ctx->config->isWESModeEnabled = wesMode;
4171 sme_update_wes_mode(hdd_ctx->hHal, wesMode, adapter->sessionId);
4172
4173exit:
4174 return ret;
4175}
4176
4177static int drv_cmd_get_wes_mode(hdd_adapter_t *adapter,
4178 hdd_context_t *hdd_ctx,
4179 uint8_t *command,
4180 uint8_t command_len,
4181 hdd_priv_data_t *priv_data)
4182{
4183 int ret = 0;
4184 bool wesMode = sme_get_wes_mode(hdd_ctx->hHal);
4185 char extra[32];
4186 uint8_t len = 0;
4187
4188 len = scnprintf(extra, sizeof(extra), "%s %d", command, wesMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304189 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004190 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004191 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004192 ret = -EFAULT;
4193 }
4194
4195 return ret;
4196}
4197
4198static int drv_cmd_set_opportunistic_rssi_diff(hdd_adapter_t *adapter,
4199 hdd_context_t *hdd_ctx,
4200 uint8_t *command,
4201 uint8_t command_len,
4202 hdd_priv_data_t *priv_data)
4203{
4204 int ret = 0;
4205 uint8_t *value = command;
4206 uint8_t nOpportunisticThresholdDiff =
4207 CFG_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF_DEFAULT;
4208
4209 /* Move pointer to ahead of SETOPPORTUNISTICRSSIDIFF<delimiter> */
4210 value = value + command_len + 1;
4211
4212 /* Convert the value from ascii to integer */
4213 ret = kstrtou8(value, 10, &nOpportunisticThresholdDiff);
4214 if (ret < 0) {
4215 /*
4216 * If the input value is greater than max value of datatype,
4217 * then also kstrtou8 fails
4218 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004219 hdd_err("kstrtou8 failed.");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004220 ret = -EINVAL;
4221 goto exit;
4222 }
4223
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004224 hdd_info("Received Command to Set Opportunistic Threshold diff = %d",
4225 nOpportunisticThresholdDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004226
4227 sme_set_roam_opportunistic_scan_threshold_diff(hdd_ctx->hHal,
4228 adapter->sessionId,
4229 nOpportunisticThresholdDiff);
4230
4231exit:
4232 return ret;
4233}
4234
4235static int drv_cmd_get_opportunistic_rssi_diff(hdd_adapter_t *adapter,
4236 hdd_context_t *hdd_ctx,
4237 uint8_t *command,
4238 uint8_t command_len,
4239 hdd_priv_data_t *priv_data)
4240{
4241 int ret = 0;
4242 int8_t val = sme_get_roam_opportunistic_scan_threshold_diff(
4243 hdd_ctx->hHal);
4244 char extra[32];
4245 uint8_t len = 0;
4246
4247 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304248 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004249 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004250 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004251 ret = -EFAULT;
4252 }
4253
4254 return ret;
4255}
4256
4257static int drv_cmd_set_roam_rescan_rssi_diff(hdd_adapter_t *adapter,
4258 hdd_context_t *hdd_ctx,
4259 uint8_t *command,
4260 uint8_t command_len,
4261 hdd_priv_data_t *priv_data)
4262{
4263 int ret = 0;
4264 uint8_t *value = command;
4265 uint8_t nRoamRescanRssiDiff = CFG_ROAM_RESCAN_RSSI_DIFF_DEFAULT;
4266
4267 /* Move pointer to ahead of SETROAMRESCANRSSIDIFF<delimiter> */
4268 value = value + command_len + 1;
4269
4270 /* Convert the value from ascii to integer */
4271 ret = kstrtou8(value, 10, &nRoamRescanRssiDiff);
4272 if (ret < 0) {
4273 /*
4274 * If the input value is greater than max value of datatype,
4275 * then also kstrtou8 fails
4276 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004277 hdd_err("kstrtou8 failed.");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004278 ret = -EINVAL;
4279 goto exit;
4280 }
4281
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004282 hdd_info("Received Command to Set Roam Rescan RSSI Diff = %d",
4283 nRoamRescanRssiDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004284
4285 sme_set_roam_rescan_rssi_diff(hdd_ctx->hHal,
4286 adapter->sessionId,
4287 nRoamRescanRssiDiff);
4288
4289exit:
4290 return ret;
4291}
4292
4293static int drv_cmd_get_roam_rescan_rssi_diff(hdd_adapter_t *adapter,
4294 hdd_context_t *hdd_ctx,
4295 uint8_t *command,
4296 uint8_t command_len,
4297 hdd_priv_data_t *priv_data)
4298{
4299 int ret = 0;
4300 uint8_t val = sme_get_roam_rescan_rssi_diff(hdd_ctx->hHal);
4301 char extra[32];
4302 uint8_t len = 0;
4303
4304 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304305 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004306 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004307 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004308 ret = -EFAULT;
4309 }
4310
4311 return ret;
4312}
4313
4314static int drv_cmd_set_fast_roam(hdd_adapter_t *adapter,
4315 hdd_context_t *hdd_ctx,
4316 uint8_t *command,
4317 uint8_t command_len,
4318 hdd_priv_data_t *priv_data)
4319{
4320 int ret = 0;
4321 uint8_t *value = command;
4322 uint8_t lfrMode = CFG_LFR_FEATURE_ENABLED_DEFAULT;
4323
4324 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4325 value = value + command_len + 1;
4326
4327 /* Convert the value from ascii to integer */
4328 ret = kstrtou8(value, 10, &lfrMode);
4329 if (ret < 0) {
4330 /*
4331 * If the input value is greater than max value of datatype,
4332 * then also kstrtou8 fails
4333 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004334 hdd_err("kstrtou8 failed range [%d - %d]",
4335 CFG_LFR_FEATURE_ENABLED_MIN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004336 CFG_LFR_FEATURE_ENABLED_MAX);
4337 ret = -EINVAL;
4338 goto exit;
4339 }
4340
4341 if ((lfrMode < CFG_LFR_FEATURE_ENABLED_MIN) ||
4342 (lfrMode > CFG_LFR_FEATURE_ENABLED_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004343 hdd_err("lfr mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004344 lfrMode,
4345 CFG_LFR_FEATURE_ENABLED_MIN,
4346 CFG_LFR_FEATURE_ENABLED_MAX);
4347 ret = -EINVAL;
4348 goto exit;
4349 }
4350
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004351 hdd_info("Received Command to change lfr mode = %d",
4352 lfrMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004353
4354 hdd_ctx->config->isFastRoamIniFeatureEnabled = lfrMode;
4355 sme_update_is_fast_roam_ini_feature_enabled(hdd_ctx->hHal,
4356 adapter->
4357 sessionId,
4358 lfrMode);
4359
4360exit:
4361 return ret;
4362}
4363
4364static int drv_cmd_set_fast_transition(hdd_adapter_t *adapter,
4365 hdd_context_t *hdd_ctx,
4366 uint8_t *command,
4367 uint8_t command_len,
4368 hdd_priv_data_t *priv_data)
4369{
4370 int ret = 0;
4371 uint8_t *value = command;
4372 uint8_t ft = CFG_FAST_TRANSITION_ENABLED_NAME_DEFAULT;
4373
4374 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4375 value = value + command_len + 1;
4376
4377 /* Convert the value from ascii to integer */
4378 ret = kstrtou8(value, 10, &ft);
4379 if (ret < 0) {
4380 /*
4381 * If the input value is greater than max value of datatype,
4382 * then also kstrtou8 fails
4383 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004384 hdd_err("kstrtou8 failed range [%d - %d]",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004385 CFG_FAST_TRANSITION_ENABLED_NAME_MIN,
4386 CFG_FAST_TRANSITION_ENABLED_NAME_MAX);
4387 ret = -EINVAL;
4388 goto exit;
4389 }
4390
4391 if ((ft < CFG_FAST_TRANSITION_ENABLED_NAME_MIN) ||
4392 (ft > CFG_FAST_TRANSITION_ENABLED_NAME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004393 hdd_err("ft mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004394 ft,
4395 CFG_FAST_TRANSITION_ENABLED_NAME_MIN,
4396 CFG_FAST_TRANSITION_ENABLED_NAME_MAX);
4397 ret = -EINVAL;
4398 goto exit;
4399 }
4400
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004401 hdd_info("Received Command to change ft mode = %d", ft);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004402
4403 hdd_ctx->config->isFastTransitionEnabled = ft;
4404 sme_update_fast_transition_enabled(hdd_ctx->hHal, ft);
4405
4406exit:
4407 return ret;
4408}
4409
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004410static int drv_cmd_fast_reassoc(hdd_adapter_t *adapter,
4411 hdd_context_t *hdd_ctx,
4412 uint8_t *command,
4413 uint8_t command_len,
4414 hdd_priv_data_t *priv_data)
4415{
4416 int ret = 0;
4417 uint8_t *value = command;
4418 uint8_t channel = 0;
4419 tSirMacAddr targetApBssid;
4420 uint32_t roamId = 0;
4421 tCsrRoamModifyProfileFields modProfileFields;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004422 tCsrHandoffRequest handoffInfo;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004423 hdd_station_ctx_t *pHddStaCtx;
4424
Krunal Sonibe766b02016-03-10 13:00:44 -08004425 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004426 hdd_warn("Unsupported in mode %s(%d)",
4427 hdd_device_mode_to_string(adapter->device_mode),
4428 adapter->device_mode);
4429 return -EINVAL;
4430 }
4431
4432 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
4433
4434 /* if not associated, no need to proceed with reassoc */
4435 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004436 hdd_info("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004437 ret = -EINVAL;
4438 goto exit;
4439 }
4440
4441 ret = hdd_parse_reassoc_command_v1_data(value, targetApBssid,
4442 &channel);
4443 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004444 hdd_err("Failed to parse reassoc command data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004445 goto exit;
4446 }
4447
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304448 /* Check channel number is a valid channel number */
4449 if (QDF_STATUS_SUCCESS !=
4450 wlan_hdd_validate_operation_channel(adapter, channel)) {
4451 hdd_err("Invalid Channel [%d]", channel);
4452 return -EINVAL;
4453 }
4454
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004455 /*
4456 * if the target bssid is same as currently associated AP,
4457 * issue reassoc to same AP
4458 */
Ankit Guptaa5076012016-09-14 11:32:19 -07004459 if (!qdf_mem_cmp(targetApBssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004460 pHddStaCtx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05304461 QDF_MAC_ADDR_SIZE)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004462 hdd_info("Reassoc BSSID is same as currently associated AP bssid");
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304463 if (roaming_offload_enabled(hdd_ctx)) {
4464 hdd_wma_send_fastreassoc_cmd((int)adapter->sessionId,
4465 targetApBssid, (int)channel);
4466 } else {
4467 sme_get_modify_profile_fields(hdd_ctx->hHal,
4468 adapter->sessionId,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004469 &modProfileFields);
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304470 sme_roam_reassoc(hdd_ctx->hHal, adapter->sessionId,
4471 NULL, modProfileFields, &roamId, 1);
4472 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004473 return 0;
4474 }
4475
Varun Reddy Yeturud351a6c2016-03-16 14:01:00 -07004476 if (roaming_offload_enabled(hdd_ctx)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004477 hdd_wma_send_fastreassoc_cmd((int)adapter->sessionId,
4478 targetApBssid, (int)channel);
4479 goto exit;
4480 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004481 /* Proceed with reassoc */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004482 handoffInfo.channel = channel;
4483 handoffInfo.src = FASTREASSOC;
Varun Reddy Yeturua66f9c52016-02-17 09:58:40 -08004484 qdf_mem_copy(handoffInfo.bssid.bytes, targetApBssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004485 sizeof(tSirMacAddr));
4486 sme_handoff_request(hdd_ctx->hHal, adapter->sessionId,
4487 &handoffInfo);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004488exit:
4489 return ret;
4490}
4491
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004492static int drv_cmd_set_roam_scan_control(hdd_adapter_t *adapter,
4493 hdd_context_t *hdd_ctx,
4494 uint8_t *command,
4495 uint8_t command_len,
4496 hdd_priv_data_t *priv_data)
4497{
4498 int ret = 0;
4499 uint8_t *value = command;
4500 uint8_t roamScanControl = 0;
4501
4502 /* Move pointer to ahead of SETROAMSCANCONTROL<delimiter> */
4503 value = value + command_len + 1;
4504
4505 /* Convert the value from ascii to integer */
4506 ret = kstrtou8(value, 10, &roamScanControl);
4507 if (ret < 0) {
4508 /*
4509 * If the input value is greater than max value of datatype,
4510 * then also kstrtou8 fails
4511 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004512 hdd_err("kstrtou8 failed ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004513 ret = -EINVAL;
4514 goto exit;
4515 }
4516
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004517 hdd_info("Received Command to Set roam scan control = %d",
4518 roamScanControl);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004519
4520 if (0 != roamScanControl) {
4521 ret = 0; /* return success but ignore param value "true" */
4522 goto exit;
4523 }
4524
4525 sme_set_roam_scan_control(hdd_ctx->hHal,
4526 adapter->sessionId,
4527 roamScanControl);
4528
4529exit:
4530 return ret;
4531}
4532
4533static int drv_cmd_set_okc_mode(hdd_adapter_t *adapter,
4534 hdd_context_t *hdd_ctx,
4535 uint8_t *command,
4536 uint8_t command_len,
4537 hdd_priv_data_t *priv_data)
4538{
4539 int ret = 0;
4540 uint8_t *value = command;
4541 uint8_t okcMode = CFG_OKC_FEATURE_ENABLED_DEFAULT;
4542
4543 /*
4544 * Check if the features OKC/ESE/11R are supported simultaneously,
4545 * then this operation is not permitted (return FAILURE)
4546 */
4547 if (sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
4548 hdd_is_okc_mode_enabled(hdd_ctx) &&
4549 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004550 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004551 ret = -EPERM;
4552 goto exit;
4553 }
4554
4555 /* Move pointer to ahead of SETOKCMODE<delimiter> */
4556 value = value + command_len + 1;
4557
4558 /* Convert the value from ascii to integer */
4559 ret = kstrtou8(value, 10, &okcMode);
4560 if (ret < 0) {
4561 /*
4562 * If the input value is greater than max value of datatype,
4563 * then also kstrtou8 fails
4564 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004565 hdd_err("kstrtou8 failed range [%d - %d]",
4566 CFG_OKC_FEATURE_ENABLED_MIN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004567 CFG_OKC_FEATURE_ENABLED_MAX);
4568 ret = -EINVAL;
4569 goto exit;
4570 }
4571
4572 if ((okcMode < CFG_OKC_FEATURE_ENABLED_MIN) ||
4573 (okcMode > CFG_OKC_FEATURE_ENABLED_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004574 hdd_err("Okc mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004575 okcMode,
4576 CFG_OKC_FEATURE_ENABLED_MIN,
4577 CFG_OKC_FEATURE_ENABLED_MAX);
4578 ret = -EINVAL;
4579 goto exit;
4580 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004581 hdd_info("Received Command to change okc mode = %d",
4582 okcMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004583
4584 hdd_ctx->config->isOkcIniFeatureEnabled = okcMode;
4585
4586exit:
4587 return ret;
4588}
4589
4590static int drv_cmd_get_roam_scan_control(hdd_adapter_t *adapter,
4591 hdd_context_t *hdd_ctx,
4592 uint8_t *command,
4593 uint8_t command_len,
4594 hdd_priv_data_t *priv_data)
4595{
4596 int ret = 0;
4597 bool roamScanControl = sme_get_roam_scan_control(hdd_ctx->hHal);
4598 char extra[32];
4599 uint8_t len = 0;
4600
4601 len = scnprintf(extra, sizeof(extra), "%s %d",
4602 command, roamScanControl);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304603 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004604 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004605 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004606 ret = -EFAULT;
4607 }
4608
4609 return ret;
4610}
4611
4612static int drv_cmd_bt_coex_mode(hdd_adapter_t *adapter,
4613 hdd_context_t *hdd_ctx,
4614 uint8_t *command,
4615 uint8_t command_len,
4616 hdd_priv_data_t *priv_data)
4617{
4618 int ret = 0;
4619 char *bcMode;
4620
4621 bcMode = command + 11;
4622 if ('1' == *bcMode) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004623 hdd_debug("BTCOEXMODE %d", *bcMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004624 hdd_ctx->btCoexModeSet = true;
4625 ret = wlan_hdd_scan_abort(adapter);
4626 if (ret < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004627 hdd_err("Failed to abort existing scan status: %d",
4628 ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004629 }
4630 } else if ('2' == *bcMode) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004631 hdd_debug("BTCOEXMODE %d", *bcMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004632 hdd_ctx->btCoexModeSet = false;
4633 }
4634
4635 return ret;
4636}
4637
4638static int drv_cmd_scan_active(hdd_adapter_t *adapter,
4639 hdd_context_t *hdd_ctx,
4640 uint8_t *command,
4641 uint8_t command_len,
4642 hdd_priv_data_t *priv_data)
4643{
4644 hdd_ctx->ioctl_scan_mode = eSIR_ACTIVE_SCAN;
4645 return 0;
4646}
4647
4648static int drv_cmd_scan_passive(hdd_adapter_t *adapter,
4649 hdd_context_t *hdd_ctx,
4650 uint8_t *command,
4651 uint8_t command_len,
4652 hdd_priv_data_t *priv_data)
4653{
4654 hdd_ctx->ioctl_scan_mode = eSIR_PASSIVE_SCAN;
4655 return 0;
4656}
4657
4658static int drv_cmd_get_dwell_time(hdd_adapter_t *adapter,
4659 hdd_context_t *hdd_ctx,
4660 uint8_t *command,
4661 uint8_t command_len,
4662 hdd_priv_data_t *priv_data)
4663{
4664 int ret = 0;
4665 struct hdd_config *pCfg =
4666 (WLAN_HDD_GET_CTX(adapter))->config;
4667 char extra[32];
4668 uint8_t len = 0;
4669
4670 memset(extra, 0, sizeof(extra));
4671 ret = hdd_get_dwell_time(pCfg, command, extra, sizeof(extra), &len);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304672 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004673 if (ret != 0 || copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004674 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004675 ret = -EFAULT;
4676 goto exit;
4677 }
4678 ret = len;
4679exit:
4680 return ret;
4681}
4682
4683static int drv_cmd_set_dwell_time(hdd_adapter_t *adapter,
4684 hdd_context_t *hdd_ctx,
4685 uint8_t *command,
4686 uint8_t command_len,
4687 hdd_priv_data_t *priv_data)
4688{
4689 return hdd_set_dwell_time(adapter, command);
4690}
4691
4692static int drv_cmd_miracast(hdd_adapter_t *adapter,
4693 hdd_context_t *hdd_ctx,
4694 uint8_t *command,
4695 uint8_t command_len,
4696 hdd_priv_data_t *priv_data)
4697{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304698 QDF_STATUS ret_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004699 int ret = 0;
4700 tHalHandle hHal;
4701 uint8_t filterType = 0;
4702 hdd_context_t *pHddCtx = NULL;
4703 uint8_t *value;
4704
4705 pHddCtx = WLAN_HDD_GET_CTX(adapter);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05304706 if (wlan_hdd_validate_context(pHddCtx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004707 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004708
4709 hHal = pHddCtx->hHal;
4710 value = command + 9;
4711
4712 /* Convert the value from ascii to integer */
4713 ret = kstrtou8(value, 10, &filterType);
4714 if (ret < 0) {
4715 /*
4716 * If the input value is greater than max value of datatype,
4717 * then also kstrtou8 fails
4718 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004719 hdd_err("kstrtou8 failed range ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004720 ret = -EINVAL;
4721 goto exit;
4722 }
4723 if ((filterType < WLAN_HDD_DRIVER_MIRACAST_CFG_MIN_VAL)
4724 || (filterType >
4725 WLAN_HDD_DRIVER_MIRACAST_CFG_MAX_VAL)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004726 hdd_err("Accepted Values are 0 to 2. 0-Disabled, 1-Source, 2-Sink ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004727 ret = -EINVAL;
4728 goto exit;
4729 }
4730 /* Filtertype value should be either 0-Disabled, 1-Source, 2-sink */
4731 pHddCtx->miracast_value = filterType;
4732
4733 ret_status = sme_set_miracast(hHal, filterType);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304734 if (QDF_STATUS_SUCCESS != ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004735 hdd_err("Failed to set miracast");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004736 return -EBUSY;
4737 }
4738
Tushnim Bhattacharyyaca50b322015-12-28 17:14:36 -08004739 if (cds_is_mcc_in_24G())
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004740 return cds_set_mas(adapter, filterType);
4741
4742exit:
4743 return ret;
4744}
4745
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004746/* Function header is left blank intentionally */
4747static int hdd_parse_set_ibss_oui_data_command(uint8_t *command, uint8_t *ie,
4748 int32_t *oui_length, int32_t limit)
4749{
4750 uint8_t len;
4751 uint8_t data;
4752
4753 while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) {
4754 command++;
4755 limit--;
4756 }
4757
4758 len = 2;
4759
4760 while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) &&
4761 (limit > 1)) {
4762 sscanf(command, "%02x", (unsigned int *)&data);
4763 ie[len++] = data;
4764 command += 2;
4765 limit -= 2;
4766 }
4767
4768 *oui_length = len - 2;
4769
4770 while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) {
4771 command++;
4772 limit--;
4773 }
4774
4775 while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) &&
4776 (limit > 1)) {
4777 sscanf(command, "%02x", (unsigned int *)&data);
4778 ie[len++] = data;
4779 command += 2;
4780 limit -= 2;
4781 }
4782
4783 ie[0] = IE_EID_VENDOR;
4784 ie[1] = len - 2;
4785
4786 return len;
4787}
4788
4789/**
4790 * drv_cmd_set_ibss_beacon_oui_data() - set ibss oui data command
4791 * @adapter: Pointer to adapter
4792 * @hdd_ctx: Pointer to HDD context
4793 * @command: Pointer to command string
4794 * @command_len : Command length
4795 * @priv_data : Pointer to priv data
4796 *
4797 * Return:
4798 * int status code
4799 */
4800static int drv_cmd_set_ibss_beacon_oui_data(hdd_adapter_t *adapter,
4801 hdd_context_t *hdd_ctx,
4802 uint8_t *command,
4803 uint8_t command_len,
4804 hdd_priv_data_t *priv_data)
4805{
4806 int i = 0;
4807 int status;
4808 int ret = 0;
4809 uint8_t *ibss_ie;
4810 int32_t oui_length = 0;
4811 uint32_t ibss_ie_length;
4812 uint8_t *value = command;
4813 tSirModifyIE ibssModifyIE;
4814 tCsrRoamProfile *pRoamProfile;
4815 hdd_wext_state_t *pWextState;
4816
4817
Krunal Sonibe766b02016-03-10 13:00:44 -08004818 if (QDF_IBSS_MODE != adapter->device_mode) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004819 hdd_info("Device_mode %s(%d) not IBSS",
4820 hdd_device_mode_to_string(adapter->device_mode),
4821 adapter->device_mode);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004822 return ret;
4823 }
4824
4825 pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(adapter);
4826
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004827 hdd_info("received command %s", ((char *)value));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004828
4829
4830 /* validate argument of command */
4831 if (strlen(value) <= command_len) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004832 hdd_err("No arguments in command length %zu",
4833 strlen(value));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004834 ret = -EFAULT;
4835 goto exit;
4836 }
4837
4838 /* moving to arguments of commands */
4839 value = value + command_len;
4840 command_len = strlen(value);
4841
4842 /* oui_data can't be less than 3 bytes */
4843 if (command_len < (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004844 hdd_err("Invalid SETIBSSBEACONOUIDATA command length %d",
4845 command_len);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004846 ret = -EFAULT;
4847 goto exit;
4848 }
4849
4850 ibss_ie = qdf_mem_malloc(command_len);
4851 if (!ibss_ie) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004852 hdd_err("Could not allocate memory for command length %d",
4853 command_len);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004854 ret = -ENOMEM;
4855 goto exit;
4856 }
4857 qdf_mem_zero(ibss_ie, command_len);
4858
4859 ibss_ie_length = hdd_parse_set_ibss_oui_data_command(value, ibss_ie,
4860 &oui_length,
4861 command_len);
4862 if (ibss_ie_length <= (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004863 hdd_err("Could not parse command %s return length %d",
4864 value, ibss_ie_length);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004865 ret = -EFAULT;
4866 qdf_mem_free(ibss_ie);
4867 goto exit;
4868 }
4869
4870 pRoamProfile = &pWextState->roamProfile;
4871
4872 qdf_copy_macaddr(&ibssModifyIE.bssid,
4873 pRoamProfile->BSSIDs.bssid);
4874
4875 ibssModifyIE.smeSessionId = adapter->sessionId;
4876 ibssModifyIE.notify = true;
4877 ibssModifyIE.ieID = IE_EID_VENDOR;
4878 ibssModifyIE.ieIDLen = ibss_ie_length;
4879 ibssModifyIE.ieBufferlength = ibss_ie_length;
4880 ibssModifyIE.pIEBuffer = ibss_ie;
4881 ibssModifyIE.oui_length = oui_length;
4882
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004883 hdd_warn("ibss_ie length %d oui_length %d ibss_ie:",
4884 ibss_ie_length, oui_length);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004885 while (i < ibssModifyIE.ieBufferlength)
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004886 hdd_warn("0x%x", ibss_ie[i++]);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004887
4888 /* Probe Bcn modification */
4889 sme_modify_add_ie(WLAN_HDD_GET_HAL_CTX(adapter),
4890 &ibssModifyIE, eUPDATE_IE_PROBE_BCN);
4891
4892 /* Populating probe resp frame */
4893 sme_modify_add_ie(WLAN_HDD_GET_HAL_CTX(adapter),
4894 &ibssModifyIE, eUPDATE_IE_PROBE_RESP);
4895
4896 qdf_mem_free(ibss_ie);
4897
4898 status = sme_send_cesium_enable_ind((tHalHandle)(hdd_ctx->hHal),
4899 adapter->sessionId);
4900 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004901 hdd_err("Could not send cesium enable indication %d",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004902 status);
4903 ret = -EINVAL;
4904 goto exit;
4905 }
4906
4907exit:
4908 return ret;
4909}
4910
4911static int drv_cmd_set_rmc_enable(hdd_adapter_t *adapter,
4912 hdd_context_t *hdd_ctx,
4913 uint8_t *command,
4914 uint8_t command_len,
4915 hdd_priv_data_t *priv_data)
4916{
4917 int ret = 0;
4918 uint8_t *value = command;
4919 uint8_t ucRmcEnable = 0;
4920 int status;
4921
Krunal Sonibe766b02016-03-10 13:00:44 -08004922 if ((QDF_IBSS_MODE != adapter->device_mode) &&
4923 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004924 hdd_err("Received SETRMCENABLE cmd in invalid mode %s(%d)",
4925 hdd_device_mode_to_string(adapter->device_mode),
4926 adapter->device_mode);
4927 hdd_err("SETRMCENABLE cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004928 ret = -EINVAL;
4929 goto exit;
4930 }
4931
4932 status = hdd_parse_setrmcenable_command(value, &ucRmcEnable);
4933 if (status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004934 hdd_err("Invalid SETRMCENABLE command ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004935 ret = -EINVAL;
4936 goto exit;
4937 }
4938
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004939 hdd_info("ucRmcEnable %d ", ucRmcEnable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004940
4941 if (true == ucRmcEnable) {
4942 status = sme_enable_rmc((tHalHandle)
4943 (hdd_ctx->hHal),
4944 adapter->sessionId);
4945 } else if (false == ucRmcEnable) {
4946 status = sme_disable_rmc((tHalHandle)
4947 (hdd_ctx->hHal),
4948 adapter->sessionId);
4949 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004950 hdd_err("Invalid SETRMCENABLE command %d",
4951 ucRmcEnable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004952 ret = -EINVAL;
4953 goto exit;
4954 }
4955
4956 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004957 hdd_err("SETRMC %d failed status %d",
4958 ucRmcEnable, status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004959 ret = -EINVAL;
4960 goto exit;
4961 }
4962
4963exit:
4964 return ret;
4965}
4966
4967static int drv_cmd_set_rmc_action_period(hdd_adapter_t *adapter,
4968 hdd_context_t *hdd_ctx,
4969 uint8_t *command,
4970 uint8_t command_len,
4971 hdd_priv_data_t *priv_data)
4972{
4973 int ret = 0;
4974 uint8_t *value = command;
4975 uint32_t uActionPeriod = 0;
4976 int status;
4977
Krunal Sonibe766b02016-03-10 13:00:44 -08004978 if ((QDF_IBSS_MODE != adapter->device_mode) &&
4979 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004980 hdd_err("Received SETRMC cmd in invalid mode %s(%d)",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004981 hdd_device_mode_to_string(adapter->device_mode),
4982 adapter->device_mode);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004983 hdd_err("SETRMC cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004984 ret = -EINVAL;
4985 goto exit;
4986 }
4987
4988 status = hdd_parse_setrmcactionperiod_command(value, &uActionPeriod);
4989 if (status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004990 hdd_err("Invalid SETRMCACTIONPERIOD command ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004991 ret = -EINVAL;
4992 goto exit;
4993 }
4994
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004995 hdd_info("uActionPeriod %d ",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004996 uActionPeriod);
4997
4998 if (sme_cfg_set_int(hdd_ctx->hHal,
4999 WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY,
5000 uActionPeriod)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005001 hdd_err("Could not set SETRMCACTIONPERIOD %d",
5002 uActionPeriod);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005003 ret = -EINVAL;
5004 goto exit;
5005 }
5006
5007 status = sme_send_rmc_action_period((tHalHandle)(hdd_ctx->hHal),
5008 adapter->sessionId);
5009 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005010 hdd_err("Could not send cesium enable indication %d",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005011 status);
5012 ret = -EINVAL;
5013 goto exit;
5014 }
5015
5016exit:
5017 return ret;
5018}
5019
5020static int drv_cmd_get_ibss_peer_info_all(hdd_adapter_t *adapter,
5021 hdd_context_t *hdd_ctx,
5022 uint8_t *command,
5023 uint8_t command_len,
5024 hdd_priv_data_t *priv_data)
5025{
5026 int ret = 0;
5027 int status = QDF_STATUS_SUCCESS;
5028 hdd_station_ctx_t *pHddStaCtx = NULL;
5029 char *extra = NULL;
5030 int idx = 0;
5031 int length = 0;
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005032 uint8_t mac_addr[QDF_MAC_ADDR_SIZE];
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005033 uint32_t numOfBytestoPrint = 0;
5034
Krunal Sonibe766b02016-03-10 13:00:44 -08005035 if (QDF_IBSS_MODE != adapter->device_mode) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005036 hdd_warn("Unsupported in mode %s(%d)",
5037 hdd_device_mode_to_string(adapter->device_mode),
5038 adapter->device_mode);
5039 return -EINVAL;
5040 }
5041
5042 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005043 hdd_info("Received GETIBSSPEERINFOALL Command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005044
5045 /* Handle the command */
5046 status = hdd_cfg80211_get_ibss_peer_info_all(adapter);
5047 if (QDF_STATUS_SUCCESS == status) {
5048 /*
5049 * The variable extra needed to be allocated on the heap since
5050 * amount of memory required to copy the data for 32 devices
5051 * exceeds the size of 1024 bytes of default stack size. On
5052 * 64 bit devices, the default max stack size of 2048 bytes
5053 */
5054 extra = kmalloc(WLAN_MAX_BUF_SIZE, GFP_KERNEL);
5055
5056 if (NULL == extra) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005057 hdd_err("kmalloc failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005058 ret = -EINVAL;
5059 goto exit;
5060 }
5061
5062 /* Copy number of stations */
5063 length = scnprintf(extra, WLAN_MAX_BUF_SIZE, "%d ",
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005064 pHddStaCtx->ibss_peer_info.numPeers);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005065 numOfBytestoPrint = length;
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005066 for (idx = 0; idx < pHddStaCtx->ibss_peer_info.numPeers;
5067 idx++) {
5068 int8_t rssi;
5069 uint32_t tx_rate;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005070
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005071 qdf_mem_copy(mac_addr,
5072 pHddStaCtx->ibss_peer_info.peerInfoParams[idx].
5073 mac_addr, sizeof(mac_addr));
5074
5075 tx_rate =
5076 pHddStaCtx->ibss_peer_info.peerInfoParams[idx].
5077 txRate;
Sriram Madhvapathi85df7c72016-09-30 11:35:28 +05305078 /*
5079 * Only lower 3 bytes are rate info. Mask of the MSByte
5080 */
5081 tx_rate &= 0x00FFFFFF;
5082
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005083 rssi = pHddStaCtx->ibss_peer_info.peerInfoParams[idx].
5084 rssi;
5085
5086 length += scnprintf((extra + length),
5087 WLAN_MAX_BUF_SIZE - length,
5088 "%02x:%02x:%02x:%02x:%02x:%02x %d %d ",
5089 mac_addr[0], mac_addr[1], mac_addr[2],
5090 mac_addr[3], mac_addr[4], mac_addr[5],
5091 tx_rate, rssi);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005092 /*
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005093 * cdf_trace_msg has limitation of 512 bytes for the
5094 * print buffer. Hence printing the data in two chunks.
5095 * The first chunk will have the data for 16 devices
5096 * and the second chunk will have the rest.
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005097 */
5098 if (idx < NUM_OF_STA_DATA_TO_PRINT)
5099 numOfBytestoPrint = length;
5100 }
5101
5102 /*
5103 * Copy the data back into buffer, if the data to copy is
5104 * more than 512 bytes than we will split the data and do
5105 * it in two shots
5106 */
5107 if (copy_to_user(priv_data->buf, extra, numOfBytestoPrint)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005108 hdd_err("Copy into user data buffer failed ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005109 ret = -EFAULT;
5110 goto exit;
5111 }
5112
5113 priv_data->buf[numOfBytestoPrint] = '\0';
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005114 hdd_debug("%s", priv_data->buf);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005115
5116 if (length > numOfBytestoPrint) {
5117 if (copy_to_user
5118 (priv_data->buf + numOfBytestoPrint,
5119 extra + numOfBytestoPrint,
5120 length - numOfBytestoPrint + 1)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005121 hdd_err("Copy into user data buffer failed ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005122 ret = -EFAULT;
5123 goto exit;
5124 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005125 hdd_debug("%s", &priv_data->buf[numOfBytestoPrint]);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005126 }
5127
5128 /* Free temporary buffer */
5129 kfree(extra);
5130 } else {
5131 /* Command failed, log error */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005132 hdd_err("GETIBSSPEERINFOALL command failed with status code %d",
5133 status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005134 ret = -EINVAL;
5135 goto exit;
5136 }
5137 ret = 0;
5138
5139exit:
5140 return ret;
5141}
5142
5143/* Peer Info <Peer Addr> command */
5144static int drv_cmd_get_ibss_peer_info(hdd_adapter_t *adapter,
5145 hdd_context_t *hdd_ctx,
5146 uint8_t *command,
5147 uint8_t command_len,
5148 hdd_priv_data_t *priv_data)
5149{
5150 int ret = 0;
5151 uint8_t *value = command;
5152 QDF_STATUS status;
5153 hdd_station_ctx_t *pHddStaCtx = NULL;
5154 char extra[128] = { 0 };
5155 uint32_t length = 0;
5156 uint8_t staIdx = 0;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005157 struct qdf_mac_addr peerMacAddr;
5158
Krunal Sonibe766b02016-03-10 13:00:44 -08005159 if (QDF_IBSS_MODE != adapter->device_mode) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005160 hdd_warn("Unsupported in mode %s(%d)",
5161 hdd_device_mode_to_string(adapter->device_mode),
5162 adapter->device_mode);
5163 return -EINVAL;
5164 }
5165
5166 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5167
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005168 hdd_info("Received GETIBSSPEERINFO Command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005169
5170 /* if there are no peers, no need to continue with the command */
5171 if (eConnectionState_IbssConnected !=
5172 pHddStaCtx->conn_info.connState) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005173 hdd_info("No IBSS Peers coalesced");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005174 ret = -EINVAL;
5175 goto exit;
5176 }
5177
5178 /* Parse the incoming command buffer */
5179 status = hdd_parse_get_ibss_peer_info(value, &peerMacAddr);
5180 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005181 hdd_err("Invalid GETIBSSPEERINFO command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005182 ret = -EINVAL;
5183 goto exit;
5184 }
5185
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005186 /* Get station index for the peer mac address and sanitize it */
Deepak Dhamdhere5872c8c2016-06-02 15:51:47 -07005187 hdd_get_peer_sta_id(pHddStaCtx, &peerMacAddr, &staIdx);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005188
Naveen Rawatc45d1622016-07-05 12:20:09 -07005189 if (staIdx > MAX_PEERS) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005190 hdd_err("Invalid StaIdx %d returned", staIdx);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005191 ret = -EINVAL;
5192 goto exit;
5193 }
5194
5195 /* Handle the command */
5196 status = hdd_cfg80211_get_ibss_peer_info(adapter, staIdx);
5197 if (QDF_STATUS_SUCCESS == status) {
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005198 uint32_t txRate =
5199 pHddStaCtx->ibss_peer_info.peerInfoParams[0].txRate;
Sriram Madhvapathi85df7c72016-09-30 11:35:28 +05305200 /* Only lower 3 bytes are rate info. Mask of the MSByte */
5201 txRate &= 0x00FFFFFF;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005202
5203 length = scnprintf(extra, sizeof(extra), "%d %d",
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005204 (int)txRate,
5205 (int)pHddStaCtx->ibss_peer_info.
5206 peerInfoParams[0].rssi);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005207
5208 /* Copy the data back into buffer */
5209 if (copy_to_user(priv_data->buf, &extra, length + 1)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005210 hdd_err("copy data to user buffer failed GETIBSSPEERINFO command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005211 ret = -EFAULT;
5212 goto exit;
5213 }
5214 } else {
5215 /* Command failed, log error */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005216 hdd_err("GETIBSSPEERINFO command failed with status code %d",
5217 status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005218 ret = -EINVAL;
5219 goto exit;
5220 }
5221
5222 /* Success ! */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005223 hdd_debug("%s", priv_data->buf);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005224 ret = 0;
5225
5226exit:
5227 return ret;
5228}
5229
5230static int drv_cmd_set_rmc_tx_rate(hdd_adapter_t *adapter,
5231 hdd_context_t *hdd_ctx,
5232 uint8_t *command,
5233 uint8_t command_len,
5234 hdd_priv_data_t *priv_data)
5235{
5236 int ret = 0;
5237 uint8_t *value = command;
5238 uint32_t uRate = 0;
5239 tTxrateinfoflags txFlags = 0;
5240 tSirRateUpdateInd rateUpdateParams = {0};
5241 int status;
5242 struct hdd_config *pConfig = hdd_ctx->config;
5243
Krunal Sonibe766b02016-03-10 13:00:44 -08005244 if ((QDF_IBSS_MODE != adapter->device_mode) &&
5245 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005246 hdd_err("Received SETRMCTXRATE cmd in invalid mode %s(%d)",
5247 hdd_device_mode_to_string(adapter->device_mode),
5248 adapter->device_mode);
5249 hdd_err("SETRMCTXRATE cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005250 ret = -EINVAL;
5251 goto exit;
5252 }
5253
5254 status = hdd_parse_setrmcrate_command(value, &uRate, &txFlags);
5255 if (status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005256 hdd_err("Invalid SETRMCTXRATE command ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005257 ret = -EINVAL;
5258 goto exit;
5259 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005260 hdd_info("uRate %d ", uRate);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005261 /* -1 implies ignore this param */
5262 rateUpdateParams.ucastDataRate = -1;
5263
5264 /*
5265 * Fill the user specifieed RMC rate param
5266 * and the derived tx flags.
5267 */
5268 rateUpdateParams.nss = (pConfig->enable2x2 == 0) ? 0 : 1;
5269 rateUpdateParams.reliableMcastDataRate = uRate;
5270 rateUpdateParams.reliableMcastDataRateTxFlag = txFlags;
5271 rateUpdateParams.dev_mode = adapter->device_mode;
5272 rateUpdateParams.bcastDataRate = -1;
5273 memcpy(rateUpdateParams.bssid.bytes,
5274 adapter->macAddressCurrent.bytes,
5275 sizeof(rateUpdateParams.bssid));
5276 status = sme_send_rate_update_ind((tHalHandle) (hdd_ctx->hHal),
5277 &rateUpdateParams);
5278
5279exit:
5280 return ret;
5281}
5282
5283static int drv_cmd_set_ibss_tx_fail_event(hdd_adapter_t *adapter,
5284 hdd_context_t *hdd_ctx,
5285 uint8_t *command,
5286 uint8_t command_len,
5287 hdd_priv_data_t *priv_data)
5288{
5289 int ret = 0;
5290 char *value;
5291 uint8_t tx_fail_count = 0;
5292 uint16_t pid = 0;
5293
5294 value = command;
5295
5296 ret = hdd_parse_ibsstx_fail_event_params(value, &tx_fail_count, &pid);
5297
5298 if (0 != ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005299 hdd_info("Failed to parse SETIBSSTXFAILEVENT arguments");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005300 goto exit;
5301 }
5302
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005303 hdd_info("tx_fail_cnt=%hhu, pid=%hu", tx_fail_count, pid);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005304
5305 if (0 == tx_fail_count) {
5306 /* Disable TX Fail Indication */
5307 if (QDF_STATUS_SUCCESS ==
5308 sme_tx_fail_monitor_start_stop_ind(hdd_ctx->hHal,
5309 tx_fail_count,
5310 NULL)) {
5311 cesium_pid = 0;
5312 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005313 hdd_err("failed to disable TX Fail Event ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005314 ret = -EINVAL;
5315 }
5316 } else {
5317 if (QDF_STATUS_SUCCESS ==
5318 sme_tx_fail_monitor_start_stop_ind(hdd_ctx->hHal,
5319 tx_fail_count,
5320 (void *)hdd_tx_fail_ind_callback)) {
5321 cesium_pid = pid;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005322 hdd_info("Registered Cesium pid %u",
5323 cesium_pid);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005324 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005325 hdd_err("Failed to enable TX Fail Monitoring");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005326 ret = -EINVAL;
5327 }
5328 }
5329
5330exit:
5331 return ret;
5332}
5333
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08005334#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005335static int drv_cmd_set_ccx_roam_scan_channels(hdd_adapter_t *adapter,
5336 hdd_context_t *hdd_ctx,
5337 uint8_t *command,
5338 uint8_t command_len,
5339 hdd_priv_data_t *priv_data)
5340{
5341 int ret = 0;
5342 uint8_t *value = command;
5343 uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
5344 uint8_t numChannels = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305345 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005346
5347 ret = hdd_parse_channellist(value, ChannelList, &numChannels);
5348 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005349 hdd_err("Failed to parse channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005350 goto exit;
5351 }
5352 if (numChannels > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005353 hdd_err("number of channels (%d) supported exceeded max (%d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005354 numChannels,
5355 WNI_CFG_VALID_CHANNEL_LIST_LEN);
5356 ret = -EINVAL;
5357 goto exit;
5358 }
5359 status = sme_set_ese_roam_scan_channel_list(hdd_ctx->hHal,
5360 adapter->sessionId,
5361 ChannelList,
5362 numChannels);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305363 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005364 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005365 ret = -EINVAL;
5366 goto exit;
5367 }
5368
5369exit:
5370 return ret;
5371}
5372
5373static int drv_cmd_get_tsm_stats(hdd_adapter_t *adapter,
5374 hdd_context_t *hdd_ctx,
5375 uint8_t *command,
5376 uint8_t command_len,
5377 hdd_priv_data_t *priv_data)
5378{
5379 int ret = 0;
5380 uint8_t *value = command;
5381 char extra[128] = { 0 };
5382 int len = 0;
5383 uint8_t tid = 0;
5384 hdd_station_ctx_t *pHddStaCtx;
5385 tAniTrafStrmMetrics tsm_metrics;
5386
Krunal Sonibe766b02016-03-10 13:00:44 -08005387 if ((QDF_STA_MODE != adapter->device_mode) &&
5388 (QDF_P2P_CLIENT_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005389 hdd_warn("Unsupported in mode %s(%d)",
5390 hdd_device_mode_to_string(adapter->device_mode),
5391 adapter->device_mode);
5392 return -EINVAL;
5393 }
5394
5395 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5396
5397 /* if not associated, return error */
5398 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005399 hdd_err("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005400 ret = -EINVAL;
5401 goto exit;
5402 }
5403
5404 /* Move pointer to ahead of GETTSMSTATS<delimiter> */
5405 value = value + command_len + 1;
5406
5407 /* Convert the value from ascii to integer */
5408 ret = kstrtou8(value, 10, &tid);
5409 if (ret < 0) {
5410 /*
5411 * If the input value is greater than max value of datatype,
5412 * then also kstrtou8 fails
5413 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005414 hdd_err("kstrtou8 failed range [%d - %d]",
5415 TID_MIN_VALUE,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005416 TID_MAX_VALUE);
5417 ret = -EINVAL;
5418 goto exit;
5419 }
5420 if ((tid < TID_MIN_VALUE) || (tid > TID_MAX_VALUE)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005421 hdd_err("tid value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005422 tid, TID_MIN_VALUE, TID_MAX_VALUE);
5423 ret = -EINVAL;
5424 goto exit;
5425 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005426 hdd_info("Received Command to get tsm stats tid = %d",
5427 tid);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305428 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005429 hdd_get_tsm_stats(adapter, tid, &tsm_metrics)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005430 hdd_err("failed to get tsm stats");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005431 ret = -EFAULT;
5432 goto exit;
5433 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005434 hdd_info(
5435 "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 -08005436 tsm_metrics.UplinkPktQueueDly,
5437 tsm_metrics.UplinkPktQueueDlyHist[0],
5438 tsm_metrics.UplinkPktQueueDlyHist[1],
5439 tsm_metrics.UplinkPktQueueDlyHist[2],
5440 tsm_metrics.UplinkPktQueueDlyHist[3],
5441 tsm_metrics.UplinkPktTxDly,
5442 tsm_metrics.UplinkPktLoss,
5443 tsm_metrics.UplinkPktCount,
5444 tsm_metrics.RoamingCount,
5445 tsm_metrics.RoamingDly);
5446 /*
5447 * Output TSM stats is of the format
5448 * GETTSMSTATS [PktQueueDly]
5449 * [PktQueueDlyHist[0]]:[PktQueueDlyHist[1]] ...[RoamingDly]
5450 * eg., GETTSMSTATS 10 1:0:0:161 20 1 17 8 39800
5451 */
5452 len = scnprintf(extra,
5453 sizeof(extra),
5454 "%s %d %d:%d:%d:%d %u %d %d %d %d",
5455 command,
5456 tsm_metrics.UplinkPktQueueDly,
5457 tsm_metrics.UplinkPktQueueDlyHist[0],
5458 tsm_metrics.UplinkPktQueueDlyHist[1],
5459 tsm_metrics.UplinkPktQueueDlyHist[2],
5460 tsm_metrics.UplinkPktQueueDlyHist[3],
5461 tsm_metrics.UplinkPktTxDly,
5462 tsm_metrics.UplinkPktLoss,
5463 tsm_metrics.UplinkPktCount,
5464 tsm_metrics.RoamingCount,
5465 tsm_metrics.RoamingDly);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305466 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005467 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005468 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005469 ret = -EFAULT;
5470 goto exit;
5471 }
5472
5473exit:
5474 return ret;
5475}
5476
5477static int drv_cmd_set_cckm_ie(hdd_adapter_t *adapter,
5478 hdd_context_t *hdd_ctx,
5479 uint8_t *command,
5480 uint8_t command_len,
5481 hdd_priv_data_t *priv_data)
5482{
5483 int ret;
5484 uint8_t *value = command;
5485 uint8_t *cckmIe = NULL;
5486 uint8_t cckmIeLen = 0;
5487
5488 ret = hdd_parse_get_cckm_ie(value, &cckmIe, &cckmIeLen);
5489 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005490 hdd_err("Failed to parse cckm ie data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005491 goto exit;
5492 }
5493
5494 if (cckmIeLen > DOT11F_IE_RSN_MAX_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005495 hdd_err("CCKM Ie input length is more than max[%d]",
5496 DOT11F_IE_RSN_MAX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005497 if (NULL != cckmIe) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305498 qdf_mem_free(cckmIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005499 cckmIe = NULL;
5500 }
5501 ret = -EINVAL;
5502 goto exit;
5503 }
5504
5505 sme_set_cckm_ie(hdd_ctx->hHal, adapter->sessionId,
5506 cckmIe, cckmIeLen);
5507 if (NULL != cckmIe) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305508 qdf_mem_free(cckmIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005509 cckmIe = NULL;
5510 }
5511
5512exit:
5513 return ret;
5514}
5515
5516static int drv_cmd_ccx_beacon_req(hdd_adapter_t *adapter,
5517 hdd_context_t *hdd_ctx,
5518 uint8_t *command,
5519 uint8_t command_len,
5520 hdd_priv_data_t *priv_data)
5521{
5522 int ret;
5523 uint8_t *value = command;
5524 tCsrEseBeaconReq eseBcnReq;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305525 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005526
Krunal Sonibe766b02016-03-10 13:00:44 -08005527 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005528 hdd_warn("Unsupported in mode %s(%d)",
5529 hdd_device_mode_to_string(adapter->device_mode),
5530 adapter->device_mode);
5531 return -EINVAL;
5532 }
5533
5534 ret = hdd_parse_ese_beacon_req(value, &eseBcnReq);
5535 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005536 hdd_err("Failed to parse ese beacon req");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005537 goto exit;
5538 }
5539
5540 if (!hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005541 hdd_info("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005542 hdd_indicate_ese_bcn_report_no_results(adapter,
5543 eseBcnReq.bcnReq[0].measurementToken,
5544 0x02, /* BIT(1) set for measurement done */
5545 0); /* no BSS */
5546 goto exit;
5547 }
5548
5549 status = sme_set_ese_beacon_request(hdd_ctx->hHal,
5550 adapter->sessionId,
5551 &eseBcnReq);
5552
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305553 if (QDF_STATUS_E_RESOURCES == status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005554 hdd_info("sme_set_ese_beacon_request failed (%d), a request already in progress",
5555 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005556 ret = -EBUSY;
5557 goto exit;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305558 } else if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005559 hdd_err("sme_set_ese_beacon_request failed (%d)",
5560 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005561 ret = -EINVAL;
5562 goto exit;
5563 }
5564
5565exit:
5566 return ret;
5567}
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005568
5569/**
5570 * drv_cmd_ccx_plm_req() - Set ESE PLM request
5571 * @adapter: Pointer to the HDD adapter
5572 * @hdd_ctx: Pointer to the HDD context
5573 * @command: Driver command string
5574 * @command_len: Driver command string length
5575 * @priv_data: Private data coming with the driver command. Unused here
5576 *
5577 * This function handles driver command that sets the ESE PLM request
5578 *
5579 * Return: 0 on success; negative errno otherwise
5580 */
5581static int drv_cmd_ccx_plm_req(hdd_adapter_t *adapter,
5582 hdd_context_t *hdd_ctx,
5583 uint8_t *command,
5584 uint8_t command_len,
5585 hdd_priv_data_t *priv_data)
5586{
5587 int ret = 0;
5588 uint8_t *value = command;
5589 QDF_STATUS status = QDF_STATUS_SUCCESS;
5590 tpSirPlmReq pPlmRequest = NULL;
5591
5592 pPlmRequest = qdf_mem_malloc(sizeof(tSirPlmReq));
5593 if (NULL == pPlmRequest) {
5594 ret = -ENOMEM;
5595 goto exit;
5596 }
5597
5598 status = hdd_parse_plm_cmd(value, pPlmRequest);
5599 if (QDF_STATUS_SUCCESS != status) {
5600 qdf_mem_free(pPlmRequest);
5601 pPlmRequest = NULL;
5602 ret = -EINVAL;
5603 goto exit;
5604 }
5605 pPlmRequest->sessionId = adapter->sessionId;
5606
5607 status = sme_set_plm_request(hdd_ctx->hHal, pPlmRequest);
5608 if (QDF_STATUS_SUCCESS != status) {
5609 qdf_mem_free(pPlmRequest);
5610 pPlmRequest = NULL;
5611 ret = -EINVAL;
5612 goto exit;
5613 }
5614
5615exit:
5616 return ret;
5617}
5618
5619/**
5620 * drv_cmd_set_ccx_mode() - Set ESE mode
5621 * @adapter: Pointer to the HDD adapter
5622 * @hdd_ctx: Pointer to the HDD context
5623 * @command: Driver command string
5624 * @command_len: Driver command string length
5625 * @priv_data: Private data coming with the driver command. Unused here
5626 *
5627 * This function handles driver command that sets ESE mode
5628 *
5629 * Return: 0 on success; negative errno otherwise
5630 */
5631static int drv_cmd_set_ccx_mode(hdd_adapter_t *adapter,
5632 hdd_context_t *hdd_ctx,
5633 uint8_t *command,
5634 uint8_t command_len,
5635 hdd_priv_data_t *priv_data)
5636{
5637 int ret = 0;
5638 uint8_t *value = command;
5639 uint8_t eseMode = CFG_ESE_FEATURE_ENABLED_DEFAULT;
5640
5641 /*
5642 * Check if the features OKC/ESE/11R are supported simultaneously,
5643 * then this operation is not permitted (return FAILURE)
5644 */
5645 if (sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
5646 hdd_is_okc_mode_enabled(hdd_ctx) &&
5647 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
5648 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
5649 ret = -EPERM;
5650 goto exit;
5651 }
5652
5653 /* Move pointer to ahead of SETCCXMODE<delimiter> */
5654 value = value + command_len + 1;
5655
5656 /* Convert the value from ascii to integer */
5657 ret = kstrtou8(value, 10, &eseMode);
5658 if (ret < 0) {
5659 /*
5660 * If the input value is greater than max value of datatype,
5661 * then also kstrtou8 fails
5662 */
5663 hdd_err("kstrtou8 failed range [%d - %d]",
5664 CFG_ESE_FEATURE_ENABLED_MIN,
5665 CFG_ESE_FEATURE_ENABLED_MAX);
5666 ret = -EINVAL;
5667 goto exit;
5668 }
5669
5670 if ((eseMode < CFG_ESE_FEATURE_ENABLED_MIN) ||
5671 (eseMode > CFG_ESE_FEATURE_ENABLED_MAX)) {
5672 hdd_err("Ese mode value %d is out of range (Min: %d Max: %d)",
5673 eseMode,
5674 CFG_ESE_FEATURE_ENABLED_MIN,
5675 CFG_ESE_FEATURE_ENABLED_MAX);
5676 ret = -EINVAL;
5677 goto exit;
5678 }
5679 hdd_info("Received Command to change ese mode = %d", eseMode);
5680
5681 hdd_ctx->config->isEseIniFeatureEnabled = eseMode;
5682 sme_update_is_ese_feature_enabled(hdd_ctx->hHal,
5683 adapter->sessionId,
5684 eseMode);
5685
5686exit:
5687 return ret;
5688}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08005689#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005690
5691static int drv_cmd_set_mc_rate(hdd_adapter_t *adapter,
5692 hdd_context_t *hdd_ctx,
5693 uint8_t *command,
5694 uint8_t command_len,
5695 hdd_priv_data_t *priv_data)
5696{
5697 int ret = 0;
5698 uint8_t *value = command;
5699 int targetRate;
5700
5701 /* input value is in units of hundred kbps */
5702
5703 /* Move pointer to ahead of SETMCRATE<delimiter> */
5704 value = value + command_len + 1;
5705
5706 /* Convert the value from ascii to integer, decimal base */
5707 ret = kstrtouint(value, 10, &targetRate);
5708
5709 ret = wlan_hdd_set_mc_rate(adapter, targetRate);
5710 return ret;
5711}
5712
5713static int drv_cmd_max_tx_power(hdd_adapter_t *adapter,
5714 hdd_context_t *hdd_ctx,
5715 uint8_t *command,
5716 uint8_t command_len,
5717 hdd_priv_data_t *priv_data)
5718{
5719 int ret = 0;
5720 int status;
5721 int txPower;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305722 QDF_STATUS qdf_status;
5723 QDF_STATUS smeStatus;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005724 uint8_t *value = command;
Anurag Chouhan6d760662016-02-20 16:05:43 +05305725 struct qdf_mac_addr bssid = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
5726 struct qdf_mac_addr selfMac = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005727 hdd_adapter_list_node_t *pAdapterNode = NULL;
5728 hdd_adapter_list_node_t *pNext = NULL;
5729
5730 status = hdd_parse_setmaxtxpower_command(value, &txPower);
5731 if (status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005732 hdd_err("Invalid MAXTXPOWER command ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005733 ret = -EINVAL;
5734 goto exit;
5735 }
5736
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305737 qdf_status = hdd_get_front_adapter(hdd_ctx, &pAdapterNode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005738 while (NULL != pAdapterNode
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305739 && QDF_STATUS_SUCCESS == qdf_status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005740 adapter = pAdapterNode->pAdapter;
5741 /* Assign correct self MAC address */
Anurag Chouhanc5548422016-02-24 18:33:27 +05305742 qdf_copy_macaddr(&bssid,
Srinivas Girigowda97215232015-09-24 12:26:28 -07005743 &adapter->macAddressCurrent);
Anurag Chouhanc5548422016-02-24 18:33:27 +05305744 qdf_copy_macaddr(&selfMac,
Srinivas Girigowda97215232015-09-24 12:26:28 -07005745 &adapter->macAddressCurrent);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005746
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005747 hdd_info("Device mode %d max tx power %d selfMac: "
5748 MAC_ADDRESS_STR " bssId: " MAC_ADDRESS_STR " ",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005749 adapter->device_mode, txPower,
Srinivas Girigowda97215232015-09-24 12:26:28 -07005750 MAC_ADDR_ARRAY(selfMac.bytes),
5751 MAC_ADDR_ARRAY(bssid.bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005752
Srinivas Girigowda97215232015-09-24 12:26:28 -07005753 smeStatus = sme_set_max_tx_power(hdd_ctx->hHal,
5754 bssid, selfMac, txPower);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305755 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005756 hdd_err("Set max tx power failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005757 ret = -EINVAL;
5758 goto exit;
5759 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005760 hdd_info("Set max tx power success");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305761 qdf_status = hdd_get_next_adapter(hdd_ctx, pAdapterNode,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005762 &pNext);
5763 pAdapterNode = pNext;
5764 }
5765
5766exit:
5767 return ret;
5768}
5769
5770static int drv_cmd_set_dfs_scan_mode(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 = 0;
5777 uint8_t *value = command;
5778 uint8_t dfsScanMode = CFG_ROAMING_DFS_CHANNEL_DEFAULT;
5779
5780 /* Move pointer to ahead of SETDFSSCANMODE<delimiter> */
5781 value = value + command_len + 1;
5782
5783 /* Convert the value from ascii to integer */
5784 ret = kstrtou8(value, 10, &dfsScanMode);
5785 if (ret < 0) {
5786 /*
5787 * If the input value is greater than max value of datatype,
5788 * then also kstrtou8 fails
5789 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005790 hdd_err("kstrtou8 failed range [%d - %d]",
5791 CFG_ROAMING_DFS_CHANNEL_MIN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005792 CFG_ROAMING_DFS_CHANNEL_MAX);
5793 ret = -EINVAL;
5794 goto exit;
5795 }
5796
5797 if ((dfsScanMode < CFG_ROAMING_DFS_CHANNEL_MIN) ||
5798 (dfsScanMode > CFG_ROAMING_DFS_CHANNEL_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005799 hdd_err("dfsScanMode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005800 dfsScanMode,
5801 CFG_ROAMING_DFS_CHANNEL_MIN,
5802 CFG_ROAMING_DFS_CHANNEL_MAX);
5803 ret = -EINVAL;
5804 goto exit;
5805 }
5806
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005807 hdd_info("Received Command to Set DFS Scan Mode = %d",
5808 dfsScanMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005809
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005810 /* When DFS scanning is disabled, the DFS channels need to be
5811 * removed from the operation of device.
5812 */
5813 ret = wlan_hdd_disable_dfs_chan_scan(hdd_ctx, adapter,
5814 (dfsScanMode == CFG_ROAMING_DFS_CHANNEL_DISABLED));
5815 if (ret < 0) {
5816 /* Some conditions prevented it from disabling DFS channels */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005817 hdd_err("disable/enable DFS channel request was denied");
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005818 goto exit;
5819 }
5820
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005821 hdd_ctx->config->allowDFSChannelRoam = dfsScanMode;
5822 sme_update_dfs_scan_mode(hdd_ctx->hHal, adapter->sessionId,
5823 dfsScanMode);
5824
5825exit:
5826 return ret;
5827}
5828
5829static int drv_cmd_get_dfs_scan_mode(hdd_adapter_t *adapter,
5830 hdd_context_t *hdd_ctx,
5831 uint8_t *command,
5832 uint8_t command_len,
5833 hdd_priv_data_t *priv_data)
5834{
5835 int ret = 0;
5836 uint8_t dfsScanMode = sme_get_dfs_scan_mode(hdd_ctx->hHal);
5837 char extra[32];
5838 uint8_t len = 0;
5839
5840 len = scnprintf(extra, sizeof(extra), "%s %d", command, dfsScanMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305841 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005842 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005843 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005844 ret = -EFAULT;
5845 }
5846
5847 return ret;
5848}
5849
5850static int drv_cmd_get_link_status(hdd_adapter_t *adapter,
5851 hdd_context_t *hdd_ctx,
5852 uint8_t *command,
5853 uint8_t command_len,
5854 hdd_priv_data_t *priv_data)
5855{
5856 int ret = 0;
5857 int value = wlan_hdd_get_link_status(adapter);
5858 char extra[32];
5859 uint8_t len;
5860
5861 len = scnprintf(extra, sizeof(extra), "%s %d", command, value);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305862 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005863 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005864 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005865 ret = -EFAULT;
5866 }
5867
5868 return ret;
5869}
5870
5871#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
5872static int drv_cmd_enable_ext_wow(hdd_adapter_t *adapter,
5873 hdd_context_t *hdd_ctx,
5874 uint8_t *command,
5875 uint8_t command_len,
5876 hdd_priv_data_t *priv_data)
5877{
5878 uint8_t *value = command;
5879 int set_value;
5880
5881 /* Move pointer to ahead of ENABLEEXTWOW */
5882 value = value + command_len;
5883
Anurag Chouhan43e0c752016-09-03 16:17:02 +05305884 if (!(sscanf(value, "%d", &set_value))) {
5885 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
5886 ("No input identified"));
5887 return -EINVAL;
5888 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005889
5890 return hdd_enable_ext_wow_parser(adapter,
5891 adapter->sessionId,
5892 set_value);
5893}
5894
5895static int drv_cmd_set_app1_params(hdd_adapter_t *adapter,
5896 hdd_context_t *hdd_ctx,
5897 uint8_t *command,
5898 uint8_t command_len,
5899 hdd_priv_data_t *priv_data)
5900{
5901 int ret;
5902 uint8_t *value = command;
5903
5904 /* Move pointer to ahead of SETAPP1PARAMS */
5905 value = value + command_len;
5906
5907 ret = hdd_set_app_type1_parser(adapter,
5908 value, strlen(value));
5909 if (ret >= 0)
5910 hdd_ctx->is_extwow_app_type1_param_set = true;
5911
5912 return ret;
5913}
5914
5915static int drv_cmd_set_app2_params(hdd_adapter_t *adapter,
5916 hdd_context_t *hdd_ctx,
5917 uint8_t *command,
5918 uint8_t command_len,
5919 hdd_priv_data_t *priv_data)
5920{
5921 int ret;
5922 uint8_t *value = command;
5923
5924 /* Move pointer to ahead of SETAPP2PARAMS */
5925 value = value + command_len;
5926
5927 ret = hdd_set_app_type2_parser(adapter, value, strlen(value));
5928 if (ret >= 0)
5929 hdd_ctx->is_extwow_app_type2_param_set = true;
5930
5931 return ret;
5932}
5933#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
5934
5935#ifdef FEATURE_WLAN_TDLS
5936/**
5937 * drv_cmd_tdls_secondary_channel_offset() - secondary tdls off channel offset
5938 * @adapter: Pointer to the HDD adapter
5939 * @hdd_ctx: Pointer to the HDD context
5940 * @command: Driver command string
5941 * @command_len: Driver command string length
5942 * @priv_data: Private data coming with the driver command. Unused here
5943 *
5944 * This function handles driver command that sets the secondary tdls off channel
5945 * offset
5946 *
5947 * Return: 0 on success; negative errno otherwise
5948 */
5949static int drv_cmd_tdls_secondary_channel_offset(hdd_adapter_t *adapter,
5950 hdd_context_t *hdd_ctx,
5951 uint8_t *command,
5952 uint8_t command_len,
5953 hdd_priv_data_t *priv_data)
5954{
5955 int ret;
5956 uint8_t *value = command;
5957 int set_value;
5958
5959 /* Move pointer to point the string */
5960 value += command_len;
5961
5962 ret = sscanf(value, "%d", &set_value);
5963 if (ret != 1)
5964 return -EINVAL;
5965
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005966 hdd_info("Tdls offchannel offset:%d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005967
5968 ret = hdd_set_tdls_secoffchanneloffset(hdd_ctx, set_value);
5969
5970 return ret;
5971}
5972
5973/**
5974 * drv_cmd_tdls_off_channel_mode() - set tdls off channel mode
5975 * @adapter: Pointer to the HDD adapter
5976 * @hdd_ctx: Pointer to the HDD context
5977 * @command: Driver command string
5978 * @command_len: Driver command string length
5979 * @priv_data: Private data coming with the driver command. Unused here
5980 *
5981 * This function handles driver command that sets tdls off channel mode
5982 *
5983 * Return: 0 on success; negative errno otherwise
5984 */
5985static int drv_cmd_tdls_off_channel_mode(hdd_adapter_t *adapter,
5986 hdd_context_t *hdd_ctx,
5987 uint8_t *command,
5988 uint8_t command_len,
5989 hdd_priv_data_t *priv_data)
5990{
5991 int ret;
5992 uint8_t *value = command;
5993 int set_value;
5994
5995 /* Move pointer to point the string */
5996 value += command_len;
5997
5998 ret = sscanf(value, "%d", &set_value);
5999 if (ret != 1)
6000 return -EINVAL;
6001
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006002 hdd_info("Tdls offchannel mode:%d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006003
6004 ret = hdd_set_tdls_offchannelmode(adapter, set_value);
6005
6006 return ret;
6007}
6008
6009/**
6010 * drv_cmd_tdls_off_channel() - set tdls off channel number
6011 * @adapter: Pointer to the HDD adapter
6012 * @hdd_ctx: Pointer to the HDD context
6013 * @command: Driver command string
6014 * @command_len: Driver command string length
6015 * @priv_data: Private data coming with the driver command. Unused here
6016 *
6017 * This function handles driver command that sets tdls off channel number
6018 *
6019 * Return: 0 on success; negative errno otherwise
6020 */
6021static int drv_cmd_tdls_off_channel(hdd_adapter_t *adapter,
6022 hdd_context_t *hdd_ctx,
6023 uint8_t *command,
6024 uint8_t command_len,
6025 hdd_priv_data_t *priv_data)
6026{
6027 int ret;
6028 uint8_t *value = command;
6029 int set_value;
6030
6031 /* Move pointer to point the string */
6032 value += command_len;
6033
6034 ret = sscanf(value, "%d", &set_value);
6035 if (ret != 1)
6036 return -EINVAL;
6037
Krishna Kumaar Natarajan4d090352015-10-26 18:30:53 -07006038 if (CDS_IS_DFS_CH(set_value)) {
6039 hdd_err("DFS channel %d is passed for hdd_set_tdls_offchannel",
6040 set_value);
6041 return -EINVAL;
6042 }
6043
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006044 hdd_info("Tdls offchannel num: %d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006045
6046 ret = hdd_set_tdls_offchannel(hdd_ctx, set_value);
6047
6048 return ret;
6049}
6050
6051/**
6052 * drv_cmd_tdls_scan() - set tdls scan type
6053 * @adapter: Pointer to the HDD adapter
6054 * @hdd_ctx: Pointer to the HDD context
6055 * @command: Driver command string
6056 * @command_len: Driver command string length
6057 * @priv_data: Private data coming with the driver command. Unused here
6058 *
6059 * This function handles driver command that sets tdls scan type
6060 *
6061 * Return: 0 on success; negative errno otherwise
6062 */
6063static int drv_cmd_tdls_scan(hdd_adapter_t *adapter,
6064 hdd_context_t *hdd_ctx,
6065 uint8_t *command,
6066 uint8_t command_len,
6067 hdd_priv_data_t *priv_data)
6068{
6069 int ret;
6070 uint8_t *value = command;
6071 int set_value;
6072
6073 /* Move pointer to point the string */
6074 value += command_len;
6075
6076 ret = sscanf(value, "%d", &set_value);
6077 if (ret != 1)
6078 return -EINVAL;
6079
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006080 hdd_info("Tdls scan type val: %d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006081
6082 ret = hdd_set_tdls_scan_type(hdd_ctx, set_value);
6083
6084 return ret;
6085}
6086#endif
6087
6088static int drv_cmd_get_rssi(hdd_adapter_t *adapter,
6089 hdd_context_t *hdd_ctx,
6090 uint8_t *command,
6091 uint8_t command_len,
6092 hdd_priv_data_t *priv_data)
6093{
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006094 int ret = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006095 int8_t rssi = 0;
6096 char extra[32];
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006097
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006098 uint8_t len = 0;
6099
6100 wlan_hdd_get_rssi(adapter, &rssi);
6101
6102 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
Anurag Chouhan6d760662016-02-20 16:05:43 +05306103 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006104
6105 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006106 hdd_err("Failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006107 ret = -EFAULT;
6108 }
6109
6110 return ret;
6111}
6112
6113static int drv_cmd_get_linkspeed(hdd_adapter_t *adapter,
6114 hdd_context_t *hdd_ctx,
6115 uint8_t *command,
6116 uint8_t command_len,
6117 hdd_priv_data_t *priv_data)
6118{
6119 int ret;
6120 uint32_t link_speed = 0;
6121 char extra[32];
6122 uint8_t len = 0;
6123
6124 ret = wlan_hdd_get_link_speed(adapter, &link_speed);
6125 if (0 != ret)
6126 return ret;
6127
6128 len = scnprintf(extra, sizeof(extra), "%s %d", command, link_speed);
Anurag Chouhan6d760662016-02-20 16:05:43 +05306129 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006130 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006131 hdd_err("Failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006132 ret = -EFAULT;
6133 }
6134
6135 return ret;
6136}
6137
6138#ifdef FEATURE_NAPI
6139/**
6140 * hdd_parse_napi() - helper functions to drv_cmd_napi
6141 * @str : source string to parse
6142 * @cmd : pointer to cmd part after parsing
6143 * @sub : pointer to subcmd part after parsing
6144 * @aux : pointer to optional aux part after parsing
6145 *
6146 * Example:
6147 * NAPI SCALE <n> +-- IN str
6148 * | | +------ OUT aux
6149 * | +------------ OUT subcmd
6150 * +----------------- OUT cmd
6151 *
6152 * Return: ==0: success; !=0: failure
6153 */
6154static int hdd_parse_napi(char **str, char **cmd, char **sub, char **aux)
6155{
6156 int rc;
6157 char *token, *lcmd = NULL, *lsub = NULL, *laux = NULL;
6158
6159 NAPI_DEBUG("-->\n");
6160
6161 token = strsep(str, " \t");
6162 if (NULL == token) {
6163 hdd_err("cannot parse cmd");
6164 goto parse_end;
6165 }
6166 lcmd = token;
6167
6168 token = strsep(str, " \t");
6169 if (NULL == token) {
6170 hdd_err("cannot parse subcmd");
6171 goto parse_end;
6172 }
6173 lsub = token;
6174
6175 token = strsep(str, " \t");
6176 if (NULL == token)
6177 hdd_warn("cannot parse aux\n");
6178 else
6179 laux = token;
6180
6181parse_end:
6182 if ((NULL == lcmd) || (NULL == lsub))
6183 rc = -EINVAL;
6184 else {
6185 rc = 0;
6186 *cmd = lcmd;
6187 *sub = lsub;
6188 if (NULL != aux)
6189 *aux = laux;
6190 }
6191 NAPI_DEBUG("<--[rc=%d]\n", rc);
6192 return rc;
6193}
6194
6195
6196/**
6197 * hdd_parse_stats() - print NAPI stats into a buffer
6198 * @buf : buffer to write stats into
6199 * @max : "size of buffer"
6200 * @idp : NULL: all stats, otherwise, ptr to the NAPI instance
6201 * @napid: binary structure to retrieve the stats from
6202 *
6203 * Return: number of bytes written into the buffer
6204 */
6205int hdd_napi_stats(char *buf,
6206 int max,
6207 char *indp,
6208 struct qca_napi_data *napid)
6209{
6210 int n = 0;
6211 int i, j, k; /* NAPI, CPU, bucket indices */
6212 int from, to;
6213 struct qca_napi_info *napii;
6214 struct qca_napi_stat *napis;
6215
6216 NAPI_DEBUG("-->\n");
6217
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006218 if (NULL == napid)
6219 return n;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006220 if (NULL == indp) {
6221 from = 0;
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006222 to = CE_COUNT_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006223 } else {
6224 if (0 > kstrtoint(indp, 10, &to)) {
6225 from = 0;
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006226 to = CE_COUNT_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006227 } else
6228 from = to;
6229 }
6230
6231 for (i = from; i < to; i++)
6232 if (napid->ce_map & (0x01 << i)) {
6233 napii = &(napid->napis[i]);
6234 for (j = 0; j < NR_CPUS; j++) {
6235 napis = &(napii->stats[j]);
6236 n += scnprintf(buf + n, max - n,
6237 "STATS: NAPI[%d] CPU: %d scheds: %d polls: %d completes: %d done: %d ",
6238 i, j,
6239 napis->napi_schedules,
6240 napis->napi_polls,
6241 napis->napi_completes,
6242 napis->napi_workdone);
6243
6244 for (k = 0; k < QCA_NAPI_NUM_BUCKETS; k++) {
6245 n += scnprintf(
6246 buf + n, max - n,
6247 " %d",
6248 napis->napi_budget_uses[k]);
6249 }
6250 n += scnprintf(buf+n, max - n, "\n");
6251 }
6252 }
6253
6254 NAPI_DEBUG("<--[n=%d]\n", n);
6255 return n;
6256}
6257
6258/**
6259 * napi_set_scale() - sets the scale attribute in all NAPI entries
6260 * @sc : scale to set
6261 *
6262 * Return: void
6263 */
6264static void napi_set_scale(uint8_t sc)
6265{
6266 uint32_t i;
6267 struct qca_napi_data *napi_data;
6268
6269 napi_data = hdd_napi_get_all();
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006270 if (likely(NULL != napi_data))
6271 for (i = 0; i < CE_COUNT_MAX; i++)
6272 if (napi_data->ce_map & (0x01 << i))
6273 napi_data->napis[i].scale = sc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006274
6275 return;
6276}
6277/**
6278 * drv_cmd_napi() - processes NAPI commands
6279 * @adapter : net_device
6280 * @hdd_ctx : HDD context
6281 * @command : command string from user command (including "NAPI")
6282 * @command_len: length of command
6283 * @priv_data : ifr_data
6284 *
6285 * Commands supported:
6286 * NAPI ENABLE : enables NAPI administratively. Note that this may not
6287 * enable NAPI functionally, as some other conditions
6288 * may not have been satisfied yet
6289 * NAPI DISABLE : reverse operation of "enable"
6290 * NAPI STATUS : get global status of NAPI instances
6291 * NAPI STATS [<n>] : get the stats for a given NAPI instance
6292 * NAPI SCALE <n> : set the scale factor
6293 *
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006294 * Return: 0: success; !0: failure
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006295 */
6296static int drv_cmd_napi(hdd_adapter_t *adapter,
6297 hdd_context_t *hdd_ctx,
6298 uint8_t *command,
6299 uint8_t command_len,
6300 hdd_priv_data_t *priv_data)
6301{
6302 int rc = 0;
6303 int n, l;
6304 char *cmd = NULL, *subcmd = NULL, *aux = NULL;
6305 char *synopsis = "NAPI ENABLE\n"
6306 "NAPI DISABLE\n"
6307 "NAPI STATUS\n"
6308 "NAPI STATS [<n>] -- if no <n> then all\n"
6309 "NAPI SCALE <n> -- set the scale\n";
6310 char *reply = NULL;
6311
6312 /* make a local copy, as strsep modifies the str in place */
6313 char *str = NULL;
6314
6315 NAPI_DEBUG("-->\n");
6316
6317 /**
6318 * NOTE TO MAINTAINER: from this point to the end of the function,
6319 * please do not return anywhere in the code except the very end
6320 * to avoid memory leakage (goto end_drv_napi instead)
6321 * or make sure that reply+str is freed
6322 */
6323 reply = kmalloc(MAX_USER_COMMAND_SIZE, GFP_KERNEL);
6324 if (NULL == reply) {
6325 hdd_err("could not allocate reply buffer");
6326 rc = -ENOMEM;
6327 goto end_drv_napi;
6328 }
6329
6330 str = kmalloc(strlen(command) + 1, GFP_KERNEL);
6331 if (NULL == str) {
6332 hdd_err("could not allocate copy of input buffer");
6333 rc = -ENOMEM;
6334 goto end_drv_napi;
6335 }
6336
6337 strlcpy(str, command, strlen(command) + 1);
6338 hdd_debug("parsing command into cmd=0x%p sub=0x%p aux=0x%p\n",
6339 cmd, subcmd, aux);
6340
6341
6342 rc = hdd_parse_napi(&str, &cmd, &subcmd, &aux);
6343
6344 if (0 != rc) {
6345 const char *msg = "unknown or badly formatted cmd\n%s";
Anurag Chouhan6d760662016-02-20 16:05:43 +05306346 l = QDF_MIN(MAX_USER_COMMAND_SIZE,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006347 strlen(msg)+strlen(synopsis));
6348 n = scnprintf(reply, l, msg, synopsis);
6349
6350 if (copy_to_user(priv_data->buf, reply,
Anurag Chouhan6d760662016-02-20 16:05:43 +05306351 QDF_MIN(priv_data->total_len, l)))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006352 hdd_err("failed to copy data to user buffer");
6353 hdd_debug("reply: %s", reply);
6354
6355 rc = -EINVAL;
6356 } else {
6357 hdd_debug("cmd=(%s) subcmd=(%s) aux=(%s)\n",
6358 cmd, subcmd, aux);
6359 if (!strcmp(subcmd, "ENABLE"))
6360 hdd_napi_event(NAPI_EVT_CMD_STATE, (void *)1);
6361 else if (!strcmp(subcmd, "DISABLE"))
6362 hdd_napi_event(NAPI_EVT_CMD_STATE, (void *)0);
6363 else if (!strcmp(subcmd, "STATUS")) {
6364 int n = 0;
6365 uint32_t i;
6366 struct qca_napi_data *napi_data;
6367
6368 napi_data = hdd_napi_get_all();
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006369 if (unlikely(NULL == napi_data))
6370 goto status_end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006371 n += scnprintf(reply+n, MAX_USER_COMMAND_SIZE - n,
6372 "NAPI state: 0x%08x map: 0x%08x\n",
6373 napi_data->state,
6374 napi_data->ce_map);
6375
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006376 for (i = 0; i < CE_COUNT_MAX; i++)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006377 if (napi_data->ce_map & (0x01 << i)) {
6378 n += scnprintf(
6379 reply + n,
6380 MAX_USER_COMMAND_SIZE - n,
6381 "#%d: id: %d, scale=%d\n",
6382 i,
6383 napi_data->napis[i].id,
6384 napi_data->napis[i].scale);
6385 }
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006386 status_end:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006387 hdd_info("wlan: STATUS DATA:\n%s", reply);
6388 if (copy_to_user(priv_data->buf, reply,
Anurag Chouhan6d760662016-02-20 16:05:43 +05306389 QDF_MIN(n, priv_data->total_len)))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006390 rc = -EINVAL;
6391 } else if (!strcmp(subcmd, "STATS")) {
6392 int n = 0;
6393 struct qca_napi_data *napi_data;
6394
6395 napi_data = hdd_napi_get_all();
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006396 if (NULL != napi_data) {
6397 n = hdd_napi_stats(reply, MAX_USER_COMMAND_SIZE,
6398 aux, napi_data);
6399 NAPI_DEBUG("STATS: returns %d\n", n);
6400 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006401 if (n > 0) {
6402 if (copy_to_user(priv_data->buf, reply,
Anurag Chouhan6d760662016-02-20 16:05:43 +05306403 QDF_MIN(priv_data->total_len,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006404 n)))
6405 rc = -EINVAL;
6406 hdd_info("wlan: STATS_DATA\n%s\n", reply);
6407 } else
6408 rc = -EINVAL;
6409 } else if (!strcmp(subcmd, "SCALE")) {
6410 if (NULL == aux) {
6411 rc = -EINVAL;
6412 hdd_err("wlan: SCALE cmd requires <n>");
6413 } else {
6414 uint8_t sc;
6415 rc = kstrtou8(aux, 10, &sc);
6416 if (rc) {
6417 hdd_err("wlan: bad scale (%s)", aux);
6418 rc = -EINVAL;
6419 } else
6420 napi_set_scale(sc);
6421 }
6422 } /* SCALE */
6423 }
6424end_drv_napi:
6425 if (NULL != str)
6426 kfree(str);
6427 if (NULL != reply)
6428 kfree(reply);
6429
6430 NAPI_DEBUG("<--[rc=%d]\n", rc);
6431 return rc;
6432}
6433#endif /* FEATURE_NAPI */
6434
6435/**
6436 * hdd_set_rx_filter() - set RX filter
6437 * @adapter: Pointer to adapter
6438 * @action: Filter action
6439 * @pattern: Address pattern
6440 *
6441 * Address pattern is most significant byte of address for example
6442 * 0x01 for IPV4 multicast address
6443 * 0x33 for IPV6 multicast address
6444 * 0xFF for broadcast address
6445 *
6446 * Return: 0 for success, non-zero for failure
6447 */
6448static int hdd_set_rx_filter(hdd_adapter_t *adapter, bool action,
6449 uint8_t pattern)
6450{
6451 int ret;
Frank Liuf95e8132016-09-29 19:01:30 +08006452 uint8_t i, j;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006453 tHalHandle handle;
6454 tSirRcvFltMcAddrList *filter;
6455 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
6456
6457 ret = wlan_hdd_validate_context(hdd_ctx);
6458 if (0 != ret)
6459 return ret;
6460
6461 handle = hdd_ctx->hHal;
6462
6463 if (NULL == handle) {
6464 hdd_err("HAL Handle is NULL");
6465 return -EINVAL;
6466 }
6467
6468 /*
6469 * If action is false it means start dropping packets
6470 * Set addr_filter_pattern which will be used when sending
6471 * MC/BC address list to target
6472 */
6473 if (!action)
6474 adapter->addr_filter_pattern = pattern;
6475 else
6476 adapter->addr_filter_pattern = 0;
6477
Krunal Sonibe766b02016-03-10 13:00:44 -08006478 if (((adapter->device_mode == QDF_STA_MODE) ||
6479 (adapter->device_mode == QDF_P2P_CLIENT_MODE)) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006480 adapter->mc_addr_list.mc_cnt &&
6481 hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
6482
6483
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306484 filter = qdf_mem_malloc(sizeof(*filter));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006485 if (NULL == filter) {
6486 hdd_err("Could not allocate Memory");
6487 return -ENOMEM;
6488 }
6489 filter->action = action;
Frank Liuf95e8132016-09-29 19:01:30 +08006490 for (i = 0, j = 0; i < adapter->mc_addr_list.mc_cnt; i++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006491 if (!memcmp(adapter->mc_addr_list.addr[i],
6492 &pattern, 1)) {
Frank Liuf95e8132016-09-29 19:01:30 +08006493 memcpy(filter->multicastAddr[j].bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006494 adapter->mc_addr_list.addr[i],
6495 sizeof(adapter->mc_addr_list.addr[i]));
Frank Liuf95e8132016-09-29 19:01:30 +08006496
Srinivas Girigowdaf2599dd2015-11-16 18:20:46 -08006497 hdd_info("%s RX filter : addr ="
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006498 MAC_ADDRESS_STR,
6499 action ? "setting" : "clearing",
Frank Liuf95e8132016-09-29 19:01:30 +08006500 MAC_ADDR_ARRAY(filter->multicastAddr[j].bytes));
6501 j++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006502 }
6503 }
Frank Liuf95e8132016-09-29 19:01:30 +08006504 filter->ulMulticastAddrCnt = j;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006505 /* Set rx filter */
6506 sme_8023_multicast_list(handle, adapter->sessionId, filter);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306507 qdf_mem_free(filter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006508 } else {
Srinivas Girigowdaf2599dd2015-11-16 18:20:46 -08006509 hdd_info("mode %d mc_cnt %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006510 adapter->device_mode, adapter->mc_addr_list.mc_cnt);
6511 }
6512
6513 return 0;
6514}
6515
6516/**
6517 * hdd_driver_rxfilter_comand_handler() - RXFILTER driver command handler
6518 * @command: Pointer to input string driver command
6519 * @adapter: Pointer to adapter
6520 * @action: Action to enable/disable filtering
6521 *
6522 * If action == false
6523 * Start filtering out data packets based on type
6524 * RXFILTER-REMOVE 0 -> Start filtering out unicast data packets
6525 * RXFILTER-REMOVE 1 -> Start filtering out broadcast data packets
6526 * RXFILTER-REMOVE 2 -> Start filtering out IPV4 mcast data packets
6527 * RXFILTER-REMOVE 3 -> Start filtering out IPV6 mcast data packets
6528 *
6529 * if action == true
6530 * Stop filtering data packets based on type
6531 * RXFILTER-ADD 0 -> Stop filtering unicast data packets
6532 * RXFILTER-ADD 1 -> Stop filtering broadcast data packets
6533 * RXFILTER-ADD 2 -> Stop filtering IPV4 mcast data packets
6534 * RXFILTER-ADD 3 -> Stop filtering IPV6 mcast data packets
6535 *
6536 * Current implementation only supports IPV4 address filtering by
6537 * selectively allowing IPV4 multicast data packest based on
6538 * address list received in .ndo_set_rx_mode
6539 *
6540 * Return: 0 for success, non-zero for failure
6541 */
6542static int hdd_driver_rxfilter_comand_handler(uint8_t *command,
6543 hdd_adapter_t *adapter,
6544 bool action)
6545{
6546 int ret = 0;
6547 uint8_t *value;
6548 uint8_t type;
6549
6550 value = command;
6551 /* Skip space after RXFILTER-REMOVE OR RXFILTER-ADD based on action */
6552 if (!action)
6553 value = command + 16;
6554 else
6555 value = command + 13;
6556 ret = kstrtou8(value, 10, &type);
6557 if (ret < 0) {
6558 hdd_err("kstrtou8 failed invalid input value %d", type);
6559 return -EINVAL;
6560 }
6561
6562 switch (type) {
6563 case 2:
6564 /* Set rx filter for IPV4 multicast data packets */
6565 ret = hdd_set_rx_filter(adapter, action, 0x01);
6566 break;
6567 default:
6568 hdd_info("Unsupported RXFILTER type %d", type);
6569 break;
6570 }
6571
6572 return ret;
6573}
6574
6575/**
6576 * drv_cmd_rx_filter_remove() - RXFILTER REMOVE driver command handler
6577 * @adapter: Pointer to network adapter
6578 * @hdd_ctx: Pointer to hdd context
6579 * @command: Pointer to input command
6580 * @command_len: Command length
6581 * @priv_data: Pointer to private data in command
6582 */
6583static int drv_cmd_rx_filter_remove(hdd_adapter_t *adapter,
6584 hdd_context_t *hdd_ctx,
6585 uint8_t *command,
6586 uint8_t command_len,
6587 hdd_priv_data_t *priv_data)
6588{
6589 return hdd_driver_rxfilter_comand_handler(command, adapter, false);
6590}
6591
6592/**
6593 * drv_cmd_rx_filter_add() - RXFILTER ADD driver command handler
6594 * @adapter: Pointer to network adapter
6595 * @hdd_ctx: Pointer to hdd context
6596 * @command: Pointer to input command
6597 * @command_len: Command length
6598 * @priv_data: Pointer to private data in command
6599 */
6600static int drv_cmd_rx_filter_add(hdd_adapter_t *adapter,
6601 hdd_context_t *hdd_ctx,
6602 uint8_t *command,
6603 uint8_t command_len,
6604 hdd_priv_data_t *priv_data)
6605{
6606 return hdd_driver_rxfilter_comand_handler(command, adapter, true);
6607}
6608
Archana Ramachandran393f3792015-11-13 17:13:21 -08006609/**
6610 * hdd_parse_setantennamode_command() - HDD Parse SETANTENNAMODE
6611 * command
6612 * @value: Pointer to SETANTENNAMODE command
6613 * @mode: Pointer to antenna mode
6614 * @reason: Pointer to reason for set antenna mode
6615 *
6616 * This function parses the SETANTENNAMODE command passed in the format
6617 * SETANTENNAMODE<space>mode
6618 *
6619 * Return: 0 for success non-zero for failure
6620 */
6621static int hdd_parse_setantennamode_command(const uint8_t *value)
6622{
6623 const uint8_t *in_ptr = value;
6624 int tmp, v;
6625 char arg1[32];
6626
6627 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
6628
6629 /* no argument after the command */
6630 if (NULL == in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006631 hdd_err("No argument after the command");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006632 return -EINVAL;
6633 }
6634
6635 /* no space after the command */
6636 if (SPACE_ASCII_VALUE != *in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006637 hdd_err("No space after the command");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006638 return -EINVAL;
6639 }
6640
6641 /* remove empty spaces */
6642 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
6643 in_ptr++;
6644
6645 /* no argument followed by spaces */
6646 if ('\0' == *in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006647 hdd_err("No argument followed by spaces");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006648 return -EINVAL;
6649 }
6650
6651 /* get the argument i.e. antenna mode */
6652 v = sscanf(in_ptr, "%31s ", arg1);
6653 if (1 != v) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006654 hdd_err("argument retrieval from cmd string failed");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006655 return -EINVAL;
6656 }
6657
6658 v = kstrtos32(arg1, 10, &tmp);
6659 if (v < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006660 hdd_err("argument string to int conversion failed");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006661 return -EINVAL;
6662 }
6663
6664 return tmp;
6665}
6666
6667/**
6668 * hdd_is_supported_chain_mask_2x2() - Verify if supported chain
6669 * mask is 2x2 mode
6670 * @hdd_ctx: Pointer to hdd contex
6671 *
6672 * Return: true if supported chain mask 2x2 else false
6673 */
6674static bool hdd_is_supported_chain_mask_2x2(hdd_context_t *hdd_ctx)
6675{
6676 /*
6677 * Revisit and the update logic to determine the number
6678 * of TX/RX chains supported in the system when
6679 * antenna sharing per band chain mask support is
6680 * brought in
6681 */
6682 return (hdd_ctx->config->enable2x2 == 0x01) ? true : false;
6683}
6684
6685/**
6686 * hdd_is_supported_chain_mask_1x1() - Verify if the supported
6687 * chain mask is 1x1
6688 * @hdd_ctx: Pointer to hdd contex
6689 *
6690 * Return: true if supported chain mask 1x1 else false
6691 */
6692static bool hdd_is_supported_chain_mask_1x1(hdd_context_t *hdd_ctx)
6693{
6694 /*
6695 * Revisit and update the logic to determine the number
6696 * of TX/RX chains supported in the system when
6697 * antenna sharing per band chain mask support is
6698 * brought in
6699 */
6700 return (!hdd_ctx->config->enable2x2) ? true : false;
6701}
6702
6703/**
6704 * drv_cmd_set_antenna_mode() - SET ANTENNA MODE driver command
6705 * handler
6706 * @adapter: Pointer to network adapter
6707 * @hdd_ctx: Pointer to hdd context
6708 * @command: Pointer to input command
6709 * @command_len: Command length
6710 * @priv_data: Pointer to private data in command
6711 */
6712static int drv_cmd_set_antenna_mode(hdd_adapter_t *adapter,
6713 hdd_context_t *hdd_ctx,
6714 uint8_t *command,
6715 uint8_t command_len,
6716 hdd_priv_data_t *priv_data)
6717{
6718 struct sir_antenna_mode_param params;
6719 QDF_STATUS status;
6720 int ret = 0;
6721 int mode;
6722 uint8_t *value = command;
6723 uint8_t smps_mode;
6724 uint8_t smps_enable;
6725
6726 if (((1 << QDF_STA_MODE) != hdd_ctx->concurrency_mode) ||
6727 (hdd_ctx->no_of_active_sessions[QDF_STA_MODE] > 1)) {
6728 hdd_err("Operation invalid in non sta or concurrent mode");
6729 ret = -EPERM;
6730 goto exit;
6731 }
6732
6733 mode = hdd_parse_setantennamode_command(value);
6734 if (mode < 0) {
6735 hdd_err("Invalid SETANTENNA command");
6736 ret = mode;
6737 goto exit;
6738 }
6739
6740 hdd_info("Processing antenna mode switch to: %d", mode);
6741
6742 if (hdd_ctx->current_antenna_mode == mode) {
6743 hdd_err("System already in the requested mode");
6744 ret = 0;
6745 goto exit;
6746 }
6747
6748 if ((HDD_ANTENNA_MODE_2X2 == mode) &&
6749 (!hdd_is_supported_chain_mask_2x2(hdd_ctx))) {
6750 hdd_err("System does not support 2x2 mode");
6751 ret = -EPERM;
6752 goto exit;
6753 }
6754
6755 if ((HDD_ANTENNA_MODE_1X1 == mode) &&
6756 hdd_is_supported_chain_mask_1x1(hdd_ctx)) {
6757 hdd_err("System only supports 1x1 mode");
6758 ret = 0;
6759 goto exit;
6760 }
6761
6762 switch (mode) {
6763 case HDD_ANTENNA_MODE_1X1:
6764 params.num_rx_chains = 1;
6765 params.num_tx_chains = 1;
6766 break;
6767 case HDD_ANTENNA_MODE_2X2:
6768 params.num_rx_chains = 2;
6769 params.num_tx_chains = 2;
6770 break;
6771 default:
6772 hdd_err("unsupported antenna mode");
6773 ret = -EINVAL;
6774 goto exit;
6775 }
6776
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006777 /* Check TDLS status and update antenna mode */
6778 if ((QDF_STA_MODE == adapter->device_mode) &&
Kabilan Kannan32eb5022016-10-04 12:24:50 -07006779 cds_is_sta_active_connection_exists()) {
Archana Ramachandran2ad7de22016-04-22 16:53:25 -07006780 ret = wlan_hdd_tdls_antenna_switch(hdd_ctx, adapter,
6781 mode);
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006782 if (0 != ret)
6783 goto exit;
6784 }
6785
Archana Ramachandran393f3792015-11-13 17:13:21 -08006786 params.set_antenna_mode_resp =
6787 (void *)wlan_hdd_soc_set_antenna_mode_cb;
6788 hdd_info("Set antenna mode rx chains: %d tx chains: %d",
6789 params.num_rx_chains,
6790 params.num_tx_chains);
6791
6792
6793 INIT_COMPLETION(hdd_ctx->set_antenna_mode_cmpl);
6794 status = sme_soc_set_antenna_mode(hdd_ctx->hHal, &params);
6795 if (QDF_STATUS_SUCCESS != status) {
6796 hdd_err("set antenna mode failed status : %d", status);
6797 ret = -EFAULT;
6798 goto exit;
6799 }
6800
6801 ret = wait_for_completion_timeout(
6802 &hdd_ctx->set_antenna_mode_cmpl,
6803 msecs_to_jiffies(WLAN_WAIT_TIME_ANTENNA_MODE_REQ));
6804 if (!ret) {
6805 ret = -EFAULT;
6806 hdd_err("send set antenna mode timed out");
6807 goto exit;
6808 }
6809
6810 /* Update SME SMPS config */
6811 if (HDD_ANTENNA_MODE_1X1 == mode) {
6812 smps_enable = true;
6813 smps_mode = HDD_SMPS_MODE_STATIC;
6814 } else {
6815 smps_enable = false;
6816 smps_mode = HDD_SMPS_MODE_DISABLED;
6817 }
6818
6819 hdd_info("Update SME SMPS enable: %d mode: %d",
6820 smps_enable, smps_mode);
6821 status = sme_update_mimo_power_save(
6822 hdd_ctx->hHal, smps_enable, smps_mode, false);
6823 if (QDF_STATUS_SUCCESS != status) {
6824 hdd_err("Update SMPS config failed enable: %d mode: %d status: %d",
6825 smps_enable, smps_mode, status);
6826 ret = -EFAULT;
6827 goto exit;
6828 }
6829
Archana Ramachandran393f3792015-11-13 17:13:21 -08006830 hdd_ctx->current_antenna_mode = mode;
Archana Ramachandran5041b252016-04-25 14:29:25 -07006831 /* Update the user requested nss in the mac context.
6832 * This will be used in tdls protocol engine to form tdls
6833 * Management frames.
6834 */
6835 sme_update_user_configured_nss(
6836 hdd_ctx->hHal,
6837 hdd_ctx->current_antenna_mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006838
Archana Ramachandran5041b252016-04-25 14:29:25 -07006839 hdd_info("Successfully switched to mode: %d x %d",
6840 hdd_ctx->current_antenna_mode,
6841 hdd_ctx->current_antenna_mode);
6842 ret = 0;
Archana Ramachandran393f3792015-11-13 17:13:21 -08006843exit:
Kabilan Kannanff89f742016-08-15 18:14:10 -07006844#ifdef FEATURE_WLAN_TDLS
6845 /* Reset tdls NSS flags */
6846 if (hdd_ctx->tdls_nss_switch_in_progress &&
6847 hdd_ctx->tdls_nss_teardown_complete) {
6848 hdd_ctx->tdls_nss_switch_in_progress = false;
6849 hdd_ctx->tdls_nss_teardown_complete = false;
6850 }
6851 hdd_info("tdls_nss_switch_in_progress: %d tdls_nss_teardown_complete: %d",
6852 hdd_ctx->tdls_nss_switch_in_progress,
6853 hdd_ctx->tdls_nss_teardown_complete);
6854#endif
Archana Ramachandran393f3792015-11-13 17:13:21 -08006855 hdd_info("Set antenna status: %d current mode: %d",
6856 ret, hdd_ctx->current_antenna_mode);
6857 return ret;
6858
6859}
6860
6861/**
6862 * drv_cmd_get_antenna_mode() - GET ANTENNA MODE driver command
6863 * handler
6864 * @adapter: Pointer to hdd adapter
6865 * @hdd_ctx: Pointer to hdd context
6866 * @command: Pointer to input command
6867 * @command_len: length of the command
6868 * @priv_data: private data coming with the driver command
6869 *
6870 * Return: 0 for success non-zero for failure
6871 */
6872static inline int drv_cmd_get_antenna_mode(hdd_adapter_t *adapter,
6873 hdd_context_t *hdd_ctx,
6874 uint8_t *command,
6875 uint8_t command_len,
6876 hdd_priv_data_t *priv_data)
6877{
6878 uint32_t antenna_mode = 0;
6879 char extra[32];
6880 uint8_t len = 0;
6881
6882 antenna_mode = hdd_ctx->current_antenna_mode;
6883 len = scnprintf(extra, sizeof(extra), "%s %d", command,
6884 antenna_mode);
6885 len = QDF_MIN(priv_data->total_len, len + 1);
6886 if (copy_to_user(priv_data->buf, &extra, len)) {
6887 hdd_err("Failed to copy data to user buffer");
6888 return -EFAULT;
6889 }
6890
6891 hdd_info("Get antenna mode: %d", antenna_mode);
6892
6893 return 0;
6894}
6895
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006896/*
6897 * dummy (no-op) hdd driver command handler
6898 */
6899static int drv_cmd_dummy(hdd_adapter_t *adapter,
6900 hdd_context_t *hdd_ctx,
6901 uint8_t *command,
6902 uint8_t command_len,
6903 hdd_priv_data_t *priv_data)
6904{
6905 hdd_info("%s: Ignoring driver command \"%s\"",
6906 adapter->dev->name, command);
6907 return 0;
6908}
6909
6910/*
6911 * handler for any unsupported wlan hdd driver command
6912 */
6913static int drv_cmd_invalid(hdd_adapter_t *adapter,
6914 hdd_context_t *hdd_ctx,
6915 uint8_t *command,
6916 uint8_t command_len,
6917 hdd_priv_data_t *priv_data)
6918{
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306919 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006920 TRACE_CODE_HDD_UNSUPPORTED_IOCTL,
6921 adapter->sessionId, 0));
6922
6923 hdd_warn("%s: Unsupported driver command \"%s\"",
6924 adapter->dev->name, command);
6925
6926 return -ENOTSUPP;
6927}
6928
6929/**
6930 * drv_cmd_set_fcc_channel() - handle fcc constraint request
6931 * @adapter: HDD adapter
6932 * @hdd_ctx: HDD context
6933 * @command: command ptr, SET_FCC_CHANNEL 0/1 is the command
6934 * @command_len: command len
6935 * @priv_data: private data
6936 *
6937 * Return: status
6938 */
6939static int drv_cmd_set_fcc_channel(hdd_adapter_t *adapter,
6940 hdd_context_t *hdd_ctx,
6941 uint8_t *command,
6942 uint8_t command_len,
6943 hdd_priv_data_t *priv_data)
6944{
6945 uint8_t *value;
6946 uint8_t fcc_constraint;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306947 QDF_STATUS status;
Amar Singhal83a047a2016-05-19 15:56:11 -07006948 bool scan_pending;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006949 int ret = 0;
6950
6951 /*
6952 * this command would be called by user-space when it detects WLAN
6953 * ON after airplane mode is set. When APM is set, WLAN turns off.
6954 * But it can be turned back on. Otherwise; when APM is turned back
6955 * off, WLAN would turn back on. So at that point the command is
6956 * expected to come down. 0 means disable, 1 means enable. The
6957 * constraint is removed when parameter 1 is set or different
6958 * country code is set
6959 */
6960
6961 value = command + command_len + 1;
6962
6963 ret = kstrtou8(value, 10, &fcc_constraint);
6964 if ((ret < 0) || (fcc_constraint > 1)) {
6965 /*
6966 * If the input value is greater than max value of datatype,
6967 * then also it is a failure
6968 */
6969 hdd_err("value out of range");
6970 return -EINVAL;
6971 }
6972
Amar Singhal83a047a2016-05-19 15:56:11 -07006973 scan_pending = !qdf_list_empty(&hdd_ctx->hdd_scan_req_q);
6974 status = sme_handle_set_fcc_channel(hdd_ctx->hHal, !fcc_constraint,
6975 scan_pending);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306976 if (status != QDF_STATUS_SUCCESS) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006977 hdd_err("sme disable fn. returned err");
6978 ret = -EPERM;
6979 }
6980
6981 return ret;
6982}
6983
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306984/**
6985 * hdd_parse_set_channel_switch_command() - Parse and validate CHANNEL_SWITCH
6986 * command
6987 * @value: Pointer to the command
6988 * @chan_number: Pointer to the channel number
6989 * @chan_bw: Pointer to the channel bandwidth
6990 *
6991 * Parses and provides the channel number and channel width from the input
6992 * command which is expected to be of the format: CHANNEL_SWITCH <CH> <BW>
6993 * <CH> is channel number to move (where 1 = channel 1, 149 = channel 149, ...)
6994 * <BW> is bandwidth to move (where 20 = BW 20, 40 = BW 40, 80 = BW 80)
6995 *
6996 * Return: 0 for success, non-zero for failure
6997 */
6998static int hdd_parse_set_channel_switch_command(uint8_t *value,
6999 uint32_t *chan_number,
7000 uint32_t *chan_bw)
7001{
7002 const uint8_t *in_ptr = value;
7003 int ret;
7004
7005 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
7006
7007 /* no argument after the command */
7008 if (NULL == in_ptr) {
7009 hdd_err("No argument after the command");
7010 return -EINVAL;
7011 }
7012
7013 /* no space after the command */
7014 if (SPACE_ASCII_VALUE != *in_ptr) {
7015 hdd_err("No space after the command ");
7016 return -EINVAL;
7017 }
7018
7019 /* remove empty spaces and move the next argument */
7020 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
7021 in_ptr++;
7022
7023 /* no argument followed by spaces */
7024 if ('\0' == *in_ptr) {
7025 hdd_err("No argument followed by spaces");
7026 return -EINVAL;
7027 }
7028
7029 /* get the two arguments: channel number and bandwidth */
7030 ret = sscanf(in_ptr, "%u %u", chan_number, chan_bw);
7031 if (ret != 2) {
7032 hdd_err("Arguments retrieval from cmd string failed");
7033 return -EINVAL;
7034 }
7035
7036 return 0;
7037}
7038
7039/**
7040 * drv_cmd_set_channel_switch() - Switch SAP/P2P-GO operating channel
7041 * @adapter: HDD adapter
7042 * @hdd_ctx: HDD context
7043 * @command: Pointer to the input command CHANNEL_SWITCH
7044 * @command_len: Command len
7045 * @priv_data: Private data
7046 *
7047 * Handles private IOCTL CHANNEL_SWITCH command to switch the operating channel
7048 * of SAP/P2P-GO
7049 *
7050 * Return: 0 for success, non-zero for failure
7051 */
7052static int drv_cmd_set_channel_switch(hdd_adapter_t *adapter,
7053 hdd_context_t *hdd_ctx,
7054 uint8_t *command,
7055 uint8_t command_len,
7056 hdd_priv_data_t *priv_data)
7057{
7058 struct net_device *dev = adapter->dev;
7059 int status;
7060 uint32_t chan_number = 0, chan_bw = 0;
7061 uint8_t *value = command;
Kiran Kumar Lokere13644672016-02-29 15:40:10 -08007062 enum phy_ch_width width;
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307063
Krunal Sonibe766b02016-03-10 13:00:44 -08007064 if ((adapter->device_mode != QDF_P2P_GO_MODE) &&
7065 (adapter->device_mode != QDF_SAP_MODE)) {
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307066 hdd_err("IOCTL CHANNEL_SWITCH not supported for mode %d",
7067 adapter->device_mode);
7068 return -EINVAL;
7069 }
7070
7071 status = hdd_parse_set_channel_switch_command(value,
7072 &chan_number, &chan_bw);
7073 if (status) {
7074 hdd_err("Invalid CHANNEL_SWITCH command");
7075 return status;
7076 }
7077
7078 if ((chan_bw != 20) && (chan_bw != 40) && (chan_bw != 80)) {
7079 hdd_err("BW %d is not allowed for CHANNEL_SWITCH", chan_bw);
7080 return -EINVAL;
7081 }
7082
7083 if (chan_bw == 80)
7084 width = CH_WIDTH_80MHZ;
7085 else if (chan_bw == 40)
7086 width = CH_WIDTH_40MHZ;
7087 else
7088 width = CH_WIDTH_20MHZ;
7089
7090 hdd_info("CH:%d BW:%d", chan_number, chan_bw);
7091
7092 status = hdd_softap_set_channel_change(dev, chan_number, width);
7093 if (status) {
7094 hdd_err("Set channel change fail");
7095 return status;
7096 }
7097
7098 return 0;
7099}
7100
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007101/*
7102 * The following table contains all supported WLAN HDD
7103 * IOCTL driver commands and the handler for each of them.
7104 */
7105static const hdd_drv_cmd_t hdd_drv_cmds[] = {
7106 {"P2P_DEV_ADDR", drv_cmd_p2p_dev_addr},
7107 {"P2P_SET_NOA", drv_cmd_p2p_set_noa},
7108 {"P2P_SET_PS", drv_cmd_p2p_set_ps},
7109 {"SETBAND", drv_cmd_set_band},
7110 {"SETWMMPS", drv_cmd_set_wmmps},
7111 {"COUNTRY", drv_cmd_country},
7112 {"SETSUSPENDMODE", drv_cmd_dummy},
7113 {"SET_AP_WPS_P2P_IE", drv_cmd_dummy},
7114 {"BTCOEXSCAN", drv_cmd_dummy},
7115 {"RXFILTER", drv_cmd_dummy},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007116 {"SETROAMTRIGGER", drv_cmd_set_roam_trigger},
7117 {"GETROAMTRIGGER", drv_cmd_get_roam_trigger},
7118 {"SETROAMSCANPERIOD", drv_cmd_set_roam_scan_period},
7119 {"GETROAMSCANPERIOD", drv_cmd_get_roam_scan_period},
7120 {"SETROAMSCANREFRESHPERIOD", drv_cmd_set_roam_scan_refresh_period},
7121 {"GETROAMSCANREFRESHPERIOD", drv_cmd_get_roam_scan_refresh_period},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007122 {"SETROAMMODE", drv_cmd_set_roam_mode},
7123 {"GETROAMMODE", drv_cmd_get_roam_mode},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007124 {"SETROAMDELTA", drv_cmd_set_roam_delta},
7125 {"GETROAMDELTA", drv_cmd_get_roam_delta},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007126 {"GETBAND", drv_cmd_get_band},
7127 {"SETROAMSCANCHANNELS", drv_cmd_set_roam_scan_channels},
7128 {"GETROAMSCANCHANNELS", drv_cmd_get_roam_scan_channels},
7129 {"GETCCXMODE", drv_cmd_get_ccx_mode},
7130 {"GETOKCMODE", drv_cmd_get_okc_mode},
7131 {"GETFASTROAM", drv_cmd_get_fast_roam},
7132 {"GETFASTTRANSITION", drv_cmd_get_fast_transition},
7133 {"SETROAMSCANCHANNELMINTIME", drv_cmd_set_roam_scan_channel_min_time},
7134 {"SENDACTIONFRAME", drv_cmd_send_action_frame},
7135 {"GETROAMSCANCHANNELMINTIME", drv_cmd_get_roam_scan_channel_min_time},
7136 {"SETSCANCHANNELTIME", drv_cmd_set_scan_channel_time},
7137 {"GETSCANCHANNELTIME", drv_cmd_get_scan_channel_time},
7138 {"SETSCANHOMETIME", drv_cmd_set_scan_home_time},
7139 {"GETSCANHOMETIME", drv_cmd_get_scan_home_time},
7140 {"SETROAMINTRABAND", drv_cmd_set_roam_intra_band},
7141 {"GETROAMINTRABAND", drv_cmd_get_roam_intra_band},
7142 {"SETSCANNPROBES", drv_cmd_set_scan_n_probes},
7143 {"GETSCANNPROBES", drv_cmd_get_scan_n_probes},
7144 {"SETSCANHOMEAWAYTIME", drv_cmd_set_scan_home_away_time},
7145 {"GETSCANHOMEAWAYTIME", drv_cmd_get_scan_home_away_time},
7146 {"REASSOC", drv_cmd_reassoc},
7147 {"SETWESMODE", drv_cmd_set_wes_mode},
7148 {"GETWESMODE", drv_cmd_get_wes_mode},
7149 {"SETOPPORTUNISTICRSSIDIFF", drv_cmd_set_opportunistic_rssi_diff},
7150 {"GETOPPORTUNISTICRSSIDIFF", drv_cmd_get_opportunistic_rssi_diff},
7151 {"SETROAMRESCANRSSIDIFF", drv_cmd_set_roam_rescan_rssi_diff},
7152 {"GETROAMRESCANRSSIDIFF", drv_cmd_get_roam_rescan_rssi_diff},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007153 {"SETFASTROAM", drv_cmd_set_fast_roam},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007154 {"SETFASTTRANSITION", drv_cmd_set_fast_transition},
7155 {"FASTREASSOC", drv_cmd_fast_reassoc},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007156 {"SETROAMSCANCONTROL", drv_cmd_set_roam_scan_control},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007157 {"SETOKCMODE", drv_cmd_set_okc_mode},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007158 {"GETROAMSCANCONTROL", drv_cmd_get_roam_scan_control},
7159 {"BTCOEXMODE", drv_cmd_bt_coex_mode},
7160 {"SCAN-ACTIVE", drv_cmd_scan_active},
7161 {"SCAN-PASSIVE", drv_cmd_scan_passive},
7162 {"GETDWELLTIME", drv_cmd_get_dwell_time},
7163 {"SETDWELLTIME", drv_cmd_set_dwell_time},
7164 {"MIRACAST", drv_cmd_miracast},
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08007165 {"SETIBSSBEACONOUIDATA", drv_cmd_set_ibss_beacon_oui_data},
7166 {"SETRMCENABLE", drv_cmd_set_rmc_enable},
7167 {"SETRMCACTIONPERIOD", drv_cmd_set_rmc_action_period},
7168 {"GETIBSSPEERINFOALL", drv_cmd_get_ibss_peer_info_all},
7169 {"GETIBSSPEERINFO", drv_cmd_get_ibss_peer_info},
7170 {"SETRMCTXRATE", drv_cmd_set_rmc_tx_rate},
7171 {"SETIBSSTXFAILEVENT", drv_cmd_set_ibss_tx_fail_event},
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08007172#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007173 {"SETCCXROAMSCANCHANNELS", drv_cmd_set_ccx_roam_scan_channels},
7174 {"GETTSMSTATS", drv_cmd_get_tsm_stats},
7175 {"SETCCKMIE", drv_cmd_set_cckm_ie},
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07007176 {"CCXBEACONREQ", drv_cmd_ccx_beacon_req},
7177 {"CCXPLMREQ", drv_cmd_ccx_plm_req},
7178 {"SETCCXMODE", drv_cmd_set_ccx_mode},
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08007179#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007180 {"SETMCRATE", drv_cmd_set_mc_rate},
7181 {"MAXTXPOWER", drv_cmd_max_tx_power},
7182 {"SETDFSSCANMODE", drv_cmd_set_dfs_scan_mode},
7183 {"GETDFSSCANMODE", drv_cmd_get_dfs_scan_mode},
7184 {"GETLINKSTATUS", drv_cmd_get_link_status},
7185#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
7186 {"ENABLEEXTWOW", drv_cmd_enable_ext_wow},
7187 {"SETAPP1PARAMS", drv_cmd_set_app1_params},
7188 {"SETAPP2PARAMS", drv_cmd_set_app2_params},
7189#endif
7190#ifdef FEATURE_WLAN_TDLS
7191 {"TDLSSECONDARYCHANNELOFFSET", drv_cmd_tdls_secondary_channel_offset},
7192 {"TDLSOFFCHANNELMODE", drv_cmd_tdls_off_channel_mode},
7193 {"TDLSOFFCHANNEL", drv_cmd_tdls_off_channel},
7194 {"TDLSSCAN", drv_cmd_tdls_scan},
7195#endif
7196 {"RSSI", drv_cmd_get_rssi},
7197 {"LINKSPEED", drv_cmd_get_linkspeed},
7198#ifdef FEATURE_NAPI
7199 {"NAPI", drv_cmd_napi},
7200#endif /* FEATURE_NAPI */
7201 {"RXFILTER-REMOVE", drv_cmd_rx_filter_remove},
7202 {"RXFILTER-ADD", drv_cmd_rx_filter_add},
7203 {"SET_FCC_CHANNEL", drv_cmd_set_fcc_channel},
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307204 {"CHANNEL_SWITCH", drv_cmd_set_channel_switch},
Archana Ramachandran393f3792015-11-13 17:13:21 -08007205 {"SETANTENNAMODE", drv_cmd_set_antenna_mode},
7206 {"GETANTENNAMODE", drv_cmd_get_antenna_mode},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007207};
7208
7209/**
7210 * hdd_drv_cmd_process() - chooses and runs the proper
7211 * handler based on the input command
7212 * @adapter: Pointer to the hdd adapter
7213 * @cmd: Pointer to the driver command
7214 * @priv_data: Pointer to the data associated with the command
7215 *
7216 * This function parses the input hdd driver command and runs
7217 * the proper handler
7218 *
7219 * Return: 0 for success non-zero for failure
7220 */
7221static int hdd_drv_cmd_process(hdd_adapter_t *adapter,
7222 uint8_t *cmd,
7223 hdd_priv_data_t *priv_data)
7224{
7225 hdd_context_t *hdd_ctx;
7226 int i;
7227 const int cmd_num_total = ARRAY_SIZE(hdd_drv_cmds);
7228 uint8_t *cmd_i = NULL;
7229 hdd_drv_cmd_handler_t handler = NULL;
7230 int len = 0;
7231
7232 if (!adapter || !cmd || !priv_data) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007233 hdd_err("at least 1 param is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007234 return -EINVAL;
7235 }
7236
7237 hdd_ctx = (hdd_context_t *)adapter->pHddCtx;
7238
7239 for (i = 0; i < cmd_num_total; i++) {
7240
7241 cmd_i = (uint8_t *)hdd_drv_cmds[i].cmd;
7242 handler = hdd_drv_cmds[i].handler;
7243 len = strlen(cmd_i);
7244
7245 if (!handler) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007246 hdd_err("no. %d handler is NULL", i);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007247 return -EINVAL;
7248 }
7249
7250 if (strncasecmp(cmd, cmd_i, len) == 0)
7251 return handler(adapter, hdd_ctx,
7252 cmd, len, priv_data);
7253 }
7254
7255 return drv_cmd_invalid(adapter, hdd_ctx, cmd, len, priv_data);
7256}
7257
7258/**
7259 * hdd_driver_command() - top level wlan hdd driver command handler
7260 * @adapter: Pointer to the hdd adapter
7261 * @priv_data: Pointer to the raw command data
7262 *
7263 * This function is the top level wlan hdd driver command handler. It
7264 * handles the command with the help of hdd_drv_cmd_process()
7265 *
7266 * Return: 0 for success non-zero for failure
7267 */
7268static int hdd_driver_command(hdd_adapter_t *adapter,
7269 hdd_priv_data_t *priv_data)
7270{
7271 uint8_t *command = NULL;
7272 int ret = 0;
7273
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307274 ENTER();
7275
Anurag Chouhan6d760662016-02-20 16:05:43 +05307276 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007277 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007278 return -EINVAL;
7279 }
7280
7281 /*
7282 * Note that valid pointers are provided by caller
7283 */
7284
7285 /* copy to local struct to avoid numerous changes to legacy code */
7286 if (priv_data->total_len <= 0 ||
7287 priv_data->total_len > WLAN_PRIV_DATA_MAX_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007288 hdd_warn("Invalid priv_data.total_len(%d)!!!",
7289 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007290 ret = -EINVAL;
7291 goto exit;
7292 }
7293
7294 /* Allocate +1 for '\0' */
7295 command = kmalloc(priv_data->total_len + 1, GFP_KERNEL);
7296 if (!command) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007297 hdd_err("failed to allocate memory");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007298 ret = -ENOMEM;
7299 goto exit;
7300 }
7301
7302 if (copy_from_user(command, priv_data->buf, priv_data->total_len)) {
7303 ret = -EFAULT;
7304 goto exit;
7305 }
7306
7307 /* Make sure the command is NUL-terminated */
7308 command[priv_data->total_len] = '\0';
7309
7310 hdd_info("%s: %s", adapter->dev->name, command);
7311 ret = hdd_drv_cmd_process(adapter, command, priv_data);
7312
7313exit:
7314 if (command)
7315 kfree(command);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307316 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007317 return ret;
7318}
7319
7320#ifdef CONFIG_COMPAT
7321static int hdd_driver_compat_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
7322{
7323 struct {
7324 compat_uptr_t buf;
7325 int used_len;
7326 int total_len;
7327 } compat_priv_data;
7328 hdd_priv_data_t priv_data;
7329 int ret = 0;
7330
7331 /*
7332 * Note that adapter and ifr have already been verified by caller,
7333 * and HDD context has also been validated
7334 */
7335 if (copy_from_user(&compat_priv_data, ifr->ifr_data,
7336 sizeof(compat_priv_data))) {
7337 ret = -EFAULT;
7338 goto exit;
7339 }
7340 priv_data.buf = compat_ptr(compat_priv_data.buf);
7341 priv_data.used_len = compat_priv_data.used_len;
7342 priv_data.total_len = compat_priv_data.total_len;
7343 ret = hdd_driver_command(adapter, &priv_data);
7344exit:
7345 return ret;
7346}
7347#else /* CONFIG_COMPAT */
7348static int hdd_driver_compat_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
7349{
7350 /* will never be invoked */
7351 return 0;
7352}
7353#endif /* CONFIG_COMPAT */
7354
7355static int hdd_driver_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
7356{
7357 hdd_priv_data_t priv_data;
7358 int ret = 0;
7359
7360 /*
7361 * Note that adapter and ifr have already been verified by caller,
7362 * and HDD context has also been validated
7363 */
7364 if (copy_from_user(&priv_data, ifr->ifr_data, sizeof(priv_data)))
7365 ret = -EFAULT;
7366 else
7367 ret = hdd_driver_command(adapter, &priv_data);
7368
7369 return ret;
7370}
7371
7372/**
7373 * __hdd_ioctl() - ioctl handler for wlan network interfaces
7374 * @dev: device upon which the ioctl was received
7375 * @ifr: ioctl request information
7376 * @cmd: ioctl command
7377 *
7378 * This function does initial processing of wlan device ioctls.
7379 * Currently two flavors of ioctls are supported. The primary ioctl
7380 * that is supported is the (SIOCDEVPRIVATE + 1) ioctl which is used
7381 * for Android "DRIVER" commands. The other ioctl that is
7382 * conditionally supported is the SIOCIOCTLTX99 ioctl which is used
7383 * for FTM on some platforms. This function simply verifies that the
7384 * driver is in a sane state, and that the ioctl is one of the
7385 * supported flavors, in which case flavor-specific handlers are
7386 * dispatched.
7387 *
7388 * Return: 0 on success, non-zero on error
7389 */
7390static int __hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7391{
7392 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
7393 hdd_context_t *hdd_ctx;
7394 int ret;
7395
Jeff Johnson3c3994a2016-02-11 08:12:30 -08007396 ENTER_DEV(dev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307397
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007398 if (dev != adapter->dev) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007399 hdd_alert("HDD adapter/dev inconsistency");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007400 ret = -ENODEV;
7401 goto exit;
7402 }
7403
7404 if ((!ifr) || (!ifr->ifr_data)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007405 hdd_err("invalid data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007406 ret = -EINVAL;
7407 goto exit;
7408 }
7409#if defined(QCA_WIFI_FTM) && defined(LINUX_QCMBR)
Anurag Chouhan6d760662016-02-20 16:05:43 +05307410 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007411 if (SIOCIOCTLTX99 == cmd) {
7412 ret = wlan_hdd_qcmbr_unified_ioctl(adapter, ifr);
7413 goto exit;
7414 }
7415 }
7416#endif
7417
7418 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
7419 ret = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307420 if (ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007421 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007422
7423 switch (cmd) {
7424 case (SIOCDEVPRIVATE + 1):
7425 if (is_compat_task())
7426 ret = hdd_driver_compat_ioctl(adapter, ifr);
7427 else
7428 ret = hdd_driver_ioctl(adapter, ifr);
7429 break;
7430 default:
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007431 hdd_err("unknown ioctl %d", cmd);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007432 ret = -EINVAL;
7433 break;
7434 }
7435exit:
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307436 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007437 return ret;
7438}
7439
7440/**
7441 * hdd_ioctl() - ioctl handler (wrapper) for wlan network interfaces
7442 * @dev: device upon which the ioctl was received
7443 * @ifr: ioctl request information
7444 * @cmd: ioctl command
7445 *
7446 * This function acts as an SSR-protecting wrapper to __hdd_ioctl()
7447 * which is where the ioctls are really handled.
7448 *
7449 * Return: 0 on success, non-zero on error
7450 */
7451int hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7452{
7453 int ret;
7454
7455 cds_ssr_protect(__func__);
7456 ret = __hdd_ioctl(dev, ifr, cmd);
7457 cds_ssr_unprotect(__func__);
7458 return ret;
7459}