blob: 683b17a8c5f3d339556c56ce45ada71b5085a3a6 [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;
Houston Hoffman59c097f2016-11-09 15:50:25 -0800201 static struct statsContext context;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800202 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 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001165
1166 hdr = (struct ieee80211_hdr_3addr *)frame;
1167 hdr->frame_control =
1168 cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301169 qdf_mem_copy(hdr->addr1, bssid, QDF_MAC_ADDR_SIZE);
1170 qdf_mem_copy(hdr->addr2, adapter->macAddressCurrent.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05301171 QDF_MAC_ADDR_SIZE);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301172 qdf_mem_copy(hdr->addr3, bssid, QDF_MAC_ADDR_SIZE);
1173 qdf_mem_copy(hdr + 1, payload, payload_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001174
1175#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
1176 params.chan = &chan;
1177 params.offchan = 0;
1178 params.wait = dwell_time;
1179 params.buf = frame;
1180 params.len = frame_len;
1181 params.no_cck = 1;
1182 params.dont_wait_for_ack = 1;
1183 ret = wlan_hdd_mgmt_tx(NULL, &adapter->wdev, &params, &cookie);
1184#else
1185 ret = wlan_hdd_mgmt_tx(NULL,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001186 &(adapter->wdev),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001187 &chan, 0,
Amar Singhal01098f72015-10-08 11:55:32 -07001188
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001189 dwell_time, frame, frame_len, 1, 1, &cookie);
1190#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
1191
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301192 qdf_mem_free(frame);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001193exit:
1194 return ret;
1195}
1196
1197/**
1198 * hdd_parse_sendactionframe_v1() - parse version 1 of the
1199 * SENDACTIONFRAME command
1200 * @adapter: Adapter upon which the command was received
1201 * @command: ASCII text command that was received
1202 *
1203 * This function parses the v1 SENDACTIONFRAME command with the format
1204 *
1205 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DW xxxxxx
1206 *
1207 * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the
1208 * BSSID, CH is the ASCII representation of the channel, DW is the
1209 * ASCII representation of the dwell time, and xxxxxx is the Hex-ASCII
1210 * payload. For example
1211 *
1212 * SENDACTIONFRAME 00:0a:0b:11:22:33 48 40 aabbccddee
1213 *
1214 * Return: 0 for success non-zero for failure
1215 */
1216static int
1217hdd_parse_sendactionframe_v1(hdd_adapter_t *adapter, const char *command)
1218{
1219 uint8_t channel = 0;
1220 uint8_t dwell_time = 0;
1221 uint8_t payload_len = 0;
1222 uint8_t *payload = NULL;
1223 tSirMacAddr bssid;
1224 int ret;
1225
1226 ret = hdd_parse_send_action_frame_v1_data(command, bssid, &channel,
1227 &dwell_time, &payload,
1228 &payload_len);
1229 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001230 hdd_err("Failed to parse send action frame data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001231 } else {
1232 ret = hdd_sendactionframe(adapter, bssid, channel,
1233 dwell_time, payload_len, payload);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301234 qdf_mem_free(payload);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001235 }
1236
1237 return ret;
1238}
1239
1240/**
1241 * hdd_parse_sendactionframe_v2() - parse version 2 of the
1242 * SENDACTIONFRAME command
1243 * @adapter: Adapter upon which the command was received
1244 * @command: Command that was received, ASCII command
1245 * followed by binary data
1246 *
1247 * This function parses the v2 SENDACTIONFRAME command with the format
1248 *
1249 * SENDACTIONFRAME <android_wifi_af_params>
1250 *
1251 * Return: 0 for success non-zero for failure
1252 */
1253static int
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001254hdd_parse_sendactionframe_v2(hdd_adapter_t *adapter,
1255 const char *command, int total_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001256{
1257 struct android_wifi_af_params *params;
1258 tSirMacAddr bssid;
1259 int ret;
1260
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001261 /* The params are located after "SENDACTIONFRAME " */
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001262 total_len -= 16;
1263 params = (struct android_wifi_af_params *)(command + 16);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001264
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001265 if (params->len <= 0 || params->len > ANDROID_WIFI_ACTION_FRAME_SIZE ||
1266 (params->len > total_len)) {
1267 hdd_err("Invalid payload length: %d", params->len);
1268 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001269 }
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001270
1271 if (!mac_pton(params->bssid, (u8 *)&bssid)) {
1272 hdd_err("MAC address parsing failed");
1273 return -EINVAL;
1274 }
1275
1276 if (params->channel < 0 ||
1277 params->channel > WNI_CFG_CURRENT_CHANNEL_STAMAX) {
1278 hdd_err("Invalid channel: %d", params->channel);
1279 return -EINVAL;
1280 }
1281
1282 if (params->dwell_time < 0) {
1283 hdd_err("Invalid dwell_time: %d", params->dwell_time);
1284 return -EINVAL;
1285 }
1286
1287 ret = hdd_sendactionframe(adapter, bssid, params->channel,
1288 params->dwell_time, params->len, params->data);
1289
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001290 return ret;
1291}
1292
1293/**
1294 * hdd_parse_sendactionframe() - parse the SENDACTIONFRAME command
1295 * @adapter: Adapter upon which the command was received
1296 * @command: Command that was received
1297 *
1298 * There are two different versions of the SENDACTIONFRAME command.
1299 * Version 1 of the command contains a parameter list that is ASCII
1300 * characters whereas version 2 contains a combination of ASCII and
1301 * binary payload. Determine if a version 1 or a version 2 command is
1302 * being parsed by examining the parameters, and then dispatch the
1303 * parser that is appropriate for the version of the command.
1304 *
1305 * Return: 0 for success non-zero for failure
1306 */
1307static int
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001308hdd_parse_sendactionframe(hdd_adapter_t *adapter, const char *command,
1309 int total_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001310{
1311 int ret;
1312
1313 /*
1314 * both versions start with "SENDACTIONFRAME "
1315 * v1 has a bssid and other parameters as an ASCII string
1316 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DWELL LEN FRAME
1317 * v2 has a C struct
1318 * SENDACTIONFRAME <binary c struct>
1319 *
1320 * The first field in the v2 struct is also the bssid in ASCII.
1321 * But in the case of a v2 message the BSSID is NUL-terminated.
1322 * Hence we can peek at that offset to see if this is V1 or V2
1323 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx*
1324 * 111111111122222222223333
1325 * 0123456789012345678901234567890123
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001326 * For both the commands, a valid command must have atleast
1327 * first 34 length of data.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001328 */
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001329 if (total_len < 34) {
1330 hdd_err("Invalid command (total_len=%d)", total_len);
1331 return -EINVAL;
1332 }
1333
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001334 if (command[33]) {
1335 ret = hdd_parse_sendactionframe_v1(adapter, command);
1336 } else {
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07001337 ret = hdd_parse_sendactionframe_v2(adapter, command, total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001338 }
1339
1340 return ret;
1341}
1342
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001343/**
1344 * hdd_parse_channellist() - HDD Parse channel list
1345 * @pValue: Pointer to input channel list
1346 * @ChannelList: Pointer to local output array to record
1347 * channel list
1348 * @pNumChannels: Pointer to number of roam scan channels
1349 *
1350 * This function parses the channel list passed in the format
1351 * SETROAMSCANCHANNELS<space><Number of channels><space>Channel 1<space>Channel 2<space>Channel N
1352 * if the Number of channels (N) does not match with the actual number
1353 * of channels passed then take the minimum of N and count of
1354 * (Ch1, Ch2, ...Ch M). For example, if SETROAMSCANCHANNELS 3 36 40 44 48,
1355 * only 36, 40 and 44 shall be taken. If SETROAMSCANCHANNELS 5 36 40 44 48,
1356 * ignore 5 and take 36, 40, 44 and 48. This function does not take care of
1357 * removing duplicate channels from the list
1358 *
1359 * Return: 0 for success non-zero for failure
1360 */
1361static int
1362hdd_parse_channellist(const uint8_t *pValue, uint8_t *pChannelList,
1363 uint8_t *pNumChannels)
1364{
1365 const uint8_t *inPtr = pValue;
1366 int tempInt;
1367 int j = 0;
1368 int v = 0;
1369 char buf[32];
1370
1371 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
1372 /* no argument after the command */
1373 if (NULL == inPtr) {
1374 return -EINVAL;
1375 }
1376
1377 /* no space after the command */
1378 else if (SPACE_ASCII_VALUE != *inPtr) {
1379 return -EINVAL;
1380 }
1381
1382 /* remove empty spaces */
1383 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
1384 inPtr++;
1385
1386 /* no argument followed by spaces */
1387 if ('\0' == *inPtr) {
1388 return -EINVAL;
1389 }
1390
1391 /* get the first argument ie the number of channels */
1392 v = sscanf(inPtr, "%31s ", buf);
1393 if (1 != v)
1394 return -EINVAL;
1395
1396 v = kstrtos32(buf, 10, &tempInt);
1397 if ((v < 0) ||
1398 (tempInt <= 0) || (tempInt > WNI_CFG_VALID_CHANNEL_LIST_LEN)) {
1399 return -EINVAL;
1400 }
1401
1402 *pNumChannels = tempInt;
1403
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001404 hdd_info("Number of channels are: %d", *pNumChannels);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001405
1406 for (j = 0; j < (*pNumChannels); j++) {
1407 /*
1408 * inPtr pointing to the beginning of first space after number
1409 * of channels
1410 */
1411 inPtr = strpbrk(inPtr, " ");
1412 /* no channel list after the number of channels argument */
1413 if (NULL == inPtr) {
1414 if (0 != j) {
1415 *pNumChannels = j;
1416 return 0;
1417 } else {
1418 return -EINVAL;
1419 }
1420 }
1421
1422 /* remove empty space */
1423 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
1424 inPtr++;
1425
1426 /*
1427 * no channel list after the number of channels
1428 * argument and spaces
1429 */
1430 if ('\0' == *inPtr) {
1431 if (0 != j) {
1432 *pNumChannels = j;
1433 return 0;
1434 } else {
1435 return -EINVAL;
1436 }
1437 }
1438
1439 v = sscanf(inPtr, "%31s ", buf);
1440 if (1 != v)
1441 return -EINVAL;
1442
1443 v = kstrtos32(buf, 10, &tempInt);
1444 if ((v < 0) ||
1445 (tempInt <= 0) ||
1446 (tempInt > WNI_CFG_CURRENT_CHANNEL_STAMAX)) {
1447 return -EINVAL;
1448 }
1449 pChannelList[j] = tempInt;
1450
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001451 hdd_info("Channel %d added to preferred channel list",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001452 pChannelList[j]);
1453 }
1454
1455 return 0;
1456}
1457
1458/**
1459 * hdd_parse_set_roam_scan_channels_v1() - parse version 1 of the
1460 * SETROAMSCANCHANNELS command
1461 * @adapter: Adapter upon which the command was received
1462 * @command: ASCII text command that was received
1463 *
1464 * This function parses the v1 SETROAMSCANCHANNELS command with the format
1465 *
1466 * SETROAMSCANCHANNELS N C1 C2 ... Cn
1467 *
1468 * Where "N" is the ASCII representation of the number of channels and
1469 * C1 thru Cn is the ASCII representation of the channels. For example
1470 *
1471 * SETROAMSCANCHANNELS 4 36 40 44 48
1472 *
1473 * Return: 0 for success non-zero for failure
1474 */
1475static int
1476hdd_parse_set_roam_scan_channels_v1(hdd_adapter_t *adapter,
1477 const char *command)
1478{
1479 uint8_t channel_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
1480 uint8_t num_chan = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301481 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001482 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1483 int ret;
1484
1485 ret = hdd_parse_channellist(command, channel_list, &num_chan);
1486 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001487 hdd_err("Failed to parse channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001488 goto exit;
1489 }
1490
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301491 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001492 TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL,
1493 adapter->sessionId, num_chan));
1494
1495 if (num_chan > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001496 hdd_err("number of channels (%d) supported exceeded max (%d)",
1497 num_chan, WNI_CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001498 ret = -EINVAL;
1499 goto exit;
1500 }
1501
1502 status =
1503 sme_change_roam_scan_channel_list(hdd_ctx->hHal,
1504 adapter->sessionId,
1505 channel_list, num_chan);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301506 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001507 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001508 ret = -EINVAL;
1509 goto exit;
1510 }
1511exit:
1512 return ret;
1513}
1514
1515/**
1516 * hdd_parse_set_roam_scan_channels_v2() - parse version 2 of the
1517 * SETROAMSCANCHANNELS command
1518 * @adapter: Adapter upon which the command was received
1519 * @command: Command that was received, ASCII command
1520 * followed by binary data
1521 *
1522 * This function parses the v2 SETROAMSCANCHANNELS command with the format
1523 *
1524 * SETROAMSCANCHANNELS [N][C1][C2][Cn]
1525 *
1526 * The command begins with SETROAMSCANCHANNELS followed by a space, but
1527 * what follows the space is an array of u08 parameters. For example
1528 *
1529 * SETROAMSCANCHANNELS [0x04 0x24 0x28 0x2c 0x30]
1530 *
1531 * Return: 0 for success non-zero for failure
1532 */
1533static int
1534hdd_parse_set_roam_scan_channels_v2(hdd_adapter_t *adapter,
1535 const char *command)
1536{
1537 const uint8_t *value;
1538 uint8_t channel_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
1539 uint8_t channel;
1540 uint8_t num_chan;
1541 int i;
1542 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301543 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001544 int ret = 0;
1545
1546 /* array of values begins after "SETROAMSCANCHANNELS " */
1547 value = command + 20;
1548
1549 num_chan = *value++;
1550 if (num_chan > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001551 hdd_err("number of channels (%d) supported exceeded max (%d)",
1552 num_chan, WNI_CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001553 ret = -EINVAL;
1554 goto exit;
1555 }
1556
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301557 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001558 TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL,
1559 adapter->sessionId, num_chan));
1560
1561 for (i = 0; i < num_chan; i++) {
1562 channel = *value++;
1563 if (channel > WNI_CFG_CURRENT_CHANNEL_STAMAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001564 hdd_err("index %d invalid channel %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001565 i, channel);
1566 ret = -EINVAL;
1567 goto exit;
1568 }
1569 channel_list[i] = channel;
1570 }
1571 status =
1572 sme_change_roam_scan_channel_list(hdd_ctx->hHal,
1573 adapter->sessionId,
1574 channel_list, num_chan);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301575 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001576 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001577 ret = -EINVAL;
1578 goto exit;
1579 }
1580exit:
1581 return ret;
1582}
1583
1584/**
1585 * hdd_parse_set_roam_scan_channels() - parse the
1586 * SETROAMSCANCHANNELS command
1587 * @adapter: Adapter upon which the command was received
1588 * @command: Command that was received
1589 *
1590 * There are two different versions of the SETROAMSCANCHANNELS command.
1591 * Version 1 of the command contains a parameter list that is ASCII
1592 * characters whereas version 2 contains a binary payload. Determine
1593 * if a version 1 or a version 2 command is being parsed by examining
1594 * the parameters, and then dispatch the parser that is appropriate for
1595 * the command.
1596 *
1597 * Return: 0 for success non-zero for failure
1598 */
1599static int
1600hdd_parse_set_roam_scan_channels(hdd_adapter_t *adapter, const char *command)
1601{
1602 const char *cursor;
1603 char ch;
1604 bool v1;
1605 int ret;
1606
1607 /* start after "SETROAMSCANCHANNELS " */
1608 cursor = command + 20;
1609
1610 /* assume we have a version 1 command until proven otherwise */
1611 v1 = true;
1612
1613 /* v1 params will only contain ASCII digits and space */
1614 while ((ch = *cursor++) && v1) {
1615 if (!(isdigit(ch) || isspace(ch))) {
1616 v1 = false;
1617 }
1618 }
1619 if (v1) {
1620 ret = hdd_parse_set_roam_scan_channels_v1(adapter, command);
1621 } else {
1622 ret = hdd_parse_set_roam_scan_channels_v2(adapter, command);
1623 }
1624
1625 return ret;
1626}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001627
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08001628#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001629/**
1630 * hdd_parse_plm_cmd() - HDD Parse Plm command
1631 * @pValue: Pointer to input data
1632 * @pPlmRequest:Pointer to output struct tpSirPlmReq
1633 *
1634 * This function parses the plm command passed in the format
1635 * CCXPLMREQ<space><enable><space><dialog_token><space>
1636 * <meas_token><space><num_of_bursts><space><burst_int><space>
1637 * <measu duration><space><burst_len><space><desired_tx_pwr>
1638 * <space><multcast_addr><space><number_of_channels>
1639 * <space><channel_numbers>
1640 *
1641 * Return: 0 for success non-zero for failure
1642 */
Jeff Johnsonf731b302016-10-05 16:00:55 -07001643static QDF_STATUS hdd_parse_plm_cmd(uint8_t *pValue, tSirPlmReq *pPlmRequest)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001644{
1645 uint8_t *cmdPtr = NULL;
1646 int count, content = 0, ret = 0;
1647 char buf[32];
1648
1649 /* move to argument list */
1650 cmdPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
1651 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301652 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001653
1654 /* no space after the command */
1655 if (SPACE_ASCII_VALUE != *cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301656 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001657
1658 /* remove empty spaces */
1659 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1660 cmdPtr++;
1661
1662 /* START/STOP PLM req */
1663 ret = sscanf(cmdPtr, "%31s ", buf);
1664 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301665 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001666
1667 ret = kstrtos32(buf, 10, &content);
1668 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301669 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001670
1671 pPlmRequest->enable = content;
1672 cmdPtr = strpbrk(cmdPtr, " ");
1673
1674 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301675 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001676
1677 /* remove empty spaces */
1678 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1679 cmdPtr++;
1680
1681 /* Dialog token of radio meas req containing meas reqIE */
1682 ret = sscanf(cmdPtr, "%31s ", buf);
1683 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301684 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001685
1686 ret = kstrtos32(buf, 10, &content);
1687 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301688 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001689
1690 pPlmRequest->diag_token = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001691 hdd_debug("diag token %d", pPlmRequest->diag_token);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001692 cmdPtr = strpbrk(cmdPtr, " ");
1693
1694 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301695 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001696
1697 /* remove empty spaces */
1698 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1699 cmdPtr++;
1700
1701 /* measurement token of meas req IE */
1702 ret = sscanf(cmdPtr, "%31s ", buf);
1703 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301704 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001705
1706 ret = kstrtos32(buf, 10, &content);
1707 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301708 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001709
1710 pPlmRequest->meas_token = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001711 hdd_debug("meas token %d", pPlmRequest->meas_token);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001712
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001713 hdd_err("PLM req %s", pPlmRequest->enable ? "START" : "STOP");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001714 if (pPlmRequest->enable) {
1715
1716 cmdPtr = strpbrk(cmdPtr, " ");
1717
1718 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301719 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001720
1721 /* remove empty spaces */
1722 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1723 cmdPtr++;
1724
1725 /* total number of bursts after which STA stops sending */
1726 ret = sscanf(cmdPtr, "%31s ", buf);
1727 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301728 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001729
1730 ret = kstrtos32(buf, 10, &content);
1731 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301732 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001733
1734 if (content < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301735 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001736
1737 pPlmRequest->numBursts = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001738 hdd_debug("num burst %d", pPlmRequest->numBursts);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001739 cmdPtr = strpbrk(cmdPtr, " ");
1740
1741 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301742 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001743
1744 /* remove empty spaces */
1745 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1746 cmdPtr++;
1747
1748 /* burst interval in seconds */
1749 ret = sscanf(cmdPtr, "%31s ", buf);
1750 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301751 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001752
1753 ret = kstrtos32(buf, 10, &content);
1754 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301755 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001756
1757 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301758 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001759
1760 pPlmRequest->burstInt = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001761 hdd_debug("burst Int %d", pPlmRequest->burstInt);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001762 cmdPtr = strpbrk(cmdPtr, " ");
1763
1764 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301765 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001766
1767 /* remove empty spaces */
1768 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1769 cmdPtr++;
1770
1771 /* Meas dur in TU's,STA goes off-ch and transmit PLM bursts */
1772 ret = sscanf(cmdPtr, "%31s ", buf);
1773 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301774 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001775
1776 ret = kstrtos32(buf, 10, &content);
1777 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301778 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001779
1780 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301781 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001782
1783 pPlmRequest->measDuration = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001784 hdd_debug("measDur %d", pPlmRequest->measDuration);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001785 cmdPtr = strpbrk(cmdPtr, " ");
1786
1787 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301788 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001789
1790 /* remove empty spaces */
1791 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1792 cmdPtr++;
1793
1794 /* burst length of PLM bursts */
1795 ret = sscanf(cmdPtr, "%31s ", buf);
1796 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301797 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001798
1799 ret = kstrtos32(buf, 10, &content);
1800 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301801 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001802
1803 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301804 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001805
1806 pPlmRequest->burstLen = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001807 hdd_debug("burstLen %d", pPlmRequest->burstLen);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001808 cmdPtr = strpbrk(cmdPtr, " ");
1809
1810 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301811 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001812
1813 /* remove empty spaces */
1814 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1815 cmdPtr++;
1816
1817 /* desired tx power for transmission of PLM bursts */
1818 ret = sscanf(cmdPtr, "%31s ", buf);
1819 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301820 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001821
1822 ret = kstrtos32(buf, 10, &content);
1823 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301824 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001825
1826 if (content <= 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301827 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001828
1829 pPlmRequest->desiredTxPwr = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001830 hdd_debug("desiredTxPwr %d",
1831 pPlmRequest->desiredTxPwr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001832
Anurag Chouhan6d760662016-02-20 16:05:43 +05301833 for (count = 0; count < QDF_MAC_ADDR_SIZE; count++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001834 cmdPtr = strpbrk(cmdPtr, " ");
1835
1836 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301837 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001838
1839 /* remove empty spaces */
1840 while ((SPACE_ASCII_VALUE == *cmdPtr)
1841 && ('\0' != *cmdPtr))
1842 cmdPtr++;
1843
1844 ret = sscanf(cmdPtr, "%31s ", buf);
1845 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301846 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001847
1848 ret = kstrtos32(buf, 16, &content);
1849 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301850 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001851
Srinivas Girigowda5146dee2015-11-18 21:46:48 -08001852 pPlmRequest->mac_addr.bytes[count] = content;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001853 }
1854
Srinivas Girigowda5146dee2015-11-18 21:46:48 -08001855 hdd_debug("MC addr " MAC_ADDRESS_STR,
1856 MAC_ADDR_ARRAY(pPlmRequest->mac_addr.bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001857
1858 cmdPtr = strpbrk(cmdPtr, " ");
1859
1860 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301861 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001862
1863 /* remove empty spaces */
1864 while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr))
1865 cmdPtr++;
1866
1867 /* number of channels */
1868 ret = sscanf(cmdPtr, "%31s ", buf);
1869 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301870 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001871
1872 ret = kstrtos32(buf, 10, &content);
1873 if (ret < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301874 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001875
1876 if (content < 0)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301877 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001878
Srinivas Girigowda0fb6cc42016-08-26 14:53:59 -07001879 content = QDF_MIN(content, WNI_CFG_VALID_CHANNEL_LIST_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001880 pPlmRequest->plmNumCh = content;
Srinivas Girigowda0fb6cc42016-08-26 14:53:59 -07001881 hdd_debug("numch: %d", pPlmRequest->plmNumCh);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001882
1883 /* Channel numbers */
1884 for (count = 0; count < pPlmRequest->plmNumCh; count++) {
1885 cmdPtr = strpbrk(cmdPtr, " ");
1886
1887 if (NULL == cmdPtr)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301888 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001889
1890 /* remove empty spaces */
1891 while ((SPACE_ASCII_VALUE == *cmdPtr)
1892 && ('\0' != *cmdPtr))
1893 cmdPtr++;
1894
1895 ret = sscanf(cmdPtr, "%31s ", buf);
1896 if (1 != ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301897 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001898
1899 ret = kstrtos32(buf, 10, &content);
Srinivas Girigowda0fb6cc42016-08-26 14:53:59 -07001900 if (ret < 0 || content <= 0 ||
1901 content > WNI_CFG_CURRENT_CHANNEL_STAMAX)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301902 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001903
1904 pPlmRequest->plmChList[count] = content;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001905 hdd_debug(" ch- %d", pPlmRequest->plmChList[count]);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001906 }
1907 }
1908 /* If PLM START */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301909 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001910}
1911#endif
1912
1913#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
1914static void wlan_hdd_ready_to_extwow(void *callbackContext, bool is_success)
1915{
1916 hdd_context_t *hdd_ctx = (hdd_context_t *) callbackContext;
1917 int rc;
1918
1919 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301920 if (rc)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001921 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001922 hdd_ctx->ext_wow_should_suspend = is_success;
1923 complete(&hdd_ctx->ready_to_extwow);
1924}
1925
1926static int hdd_enable_ext_wow(hdd_adapter_t *adapter,
1927 tpSirExtWoWParams arg_params)
1928{
1929 tSirExtWoWParams params;
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301930 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001931 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1932 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
1933 int rc;
1934
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301935 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001936
1937 INIT_COMPLETION(hdd_ctx->ready_to_extwow);
1938
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301939 qdf_ret_status = sme_configure_ext_wow(hHal, &params,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001940 &wlan_hdd_ready_to_extwow,
1941 hdd_ctx);
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301942 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001943 hdd_err("sme_configure_ext_wow returned failure %d",
1944 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001945 return -EPERM;
1946 }
1947
1948 rc = wait_for_completion_timeout(&hdd_ctx->ready_to_extwow,
1949 msecs_to_jiffies(WLAN_WAIT_TIME_READY_TO_EXTWOW));
1950 if (!rc) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001951 hdd_err("Failed to get ready to extwow");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001952 return -EPERM;
1953 }
1954
1955 if (hdd_ctx->ext_wow_should_suspend) {
1956 if (hdd_ctx->config->extWowGotoSuspend) {
1957 pm_message_t state;
1958
1959 state.event = PM_EVENT_SUSPEND;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001960 hdd_info("Received ready to ExtWoW. Going to suspend");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001961
1962 rc = wlan_hdd_cfg80211_suspend_wlan(hdd_ctx->wiphy, NULL);
1963 if (rc < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001964 hdd_err("wlan_hdd_cfg80211_suspend_wlan failed, error = %d",
1965 rc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001966 return rc;
1967 }
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301968 qdf_ret_status = wlan_hdd_bus_suspend(state);
1969 if (qdf_ret_status != QDF_STATUS_SUCCESS) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001970 hdd_err("wlan_hdd_suspend failed, status = %d",
1971 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001972 wlan_hdd_cfg80211_resume_wlan(hdd_ctx->wiphy);
1973 return -EPERM;
1974 }
1975 }
1976 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001977 hdd_err("Received ready to ExtWoW failure");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001978 return -EPERM;
1979 }
1980
1981 return 0;
1982}
1983
1984static int hdd_enable_ext_wow_parser(hdd_adapter_t *adapter, int vdev_id,
1985 int value)
1986{
1987 tSirExtWoWParams params;
1988 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1989 int rc;
1990
1991 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301992 if (rc)
1993 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001994
1995 if (value < EXT_WOW_TYPE_APP_TYPE1 ||
1996 value > EXT_WOW_TYPE_APP_TYPE1_2) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07001997 hdd_err("Invalid type");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001998 return -EINVAL;
1999 }
2000
2001 if (value == EXT_WOW_TYPE_APP_TYPE1 &&
2002 hdd_ctx->is_extwow_app_type1_param_set)
2003 params.type = value;
2004 else if (value == EXT_WOW_TYPE_APP_TYPE2 &&
2005 hdd_ctx->is_extwow_app_type2_param_set)
2006 params.type = value;
2007 else if (value == EXT_WOW_TYPE_APP_TYPE1_2 &&
2008 hdd_ctx->is_extwow_app_type1_param_set &&
2009 hdd_ctx->is_extwow_app_type2_param_set)
2010 params.type = value;
2011 else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002012 hdd_err("Set app params before enable it value %d",
2013 value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002014 return -EINVAL;
2015 }
2016
2017 params.vdev_id = vdev_id;
2018 params.wakeup_pin_num = hdd_ctx->config->extWowApp1WakeupPinNumber |
2019 (hdd_ctx->config->extWowApp2WakeupPinNumber
2020 << 8);
2021
2022 return hdd_enable_ext_wow(adapter, &params);
2023}
2024
2025static int hdd_set_app_type1_params(tHalHandle hHal,
2026 tpSirAppType1Params arg_params)
2027{
2028 tSirAppType1Params params;
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05302029 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002030
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302031 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002032
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05302033 qdf_ret_status = sme_configure_app_type1_params(hHal, &params);
2034 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002035 hdd_err("sme_configure_app_type1_params returned failure %d",
2036 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002037 return -EPERM;
2038 }
2039
2040 return 0;
2041}
2042
2043static int hdd_set_app_type1_parser(hdd_adapter_t *adapter,
2044 char *arg, int len)
2045{
2046 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2047 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
2048 char id[20], password[20];
2049 tSirAppType1Params params;
Srinivas Girigowda04209912015-11-24 12:11:13 -08002050 int rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002051
2052 rc = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302053 if (rc)
2054 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002055
2056 if (2 != sscanf(arg, "%8s %16s", id, password)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002057 hdd_err("Invalid Number of arguments");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002058 return -EINVAL;
2059 }
2060
2061 memset(&params, 0, sizeof(tSirAppType1Params));
2062 params.vdev_id = adapter->sessionId;
Anurag Chouhanc5548422016-02-24 18:33:27 +05302063 qdf_copy_macaddr(&params.wakee_mac_addr, &adapter->macAddressCurrent);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002064
2065 params.id_length = strlen(id);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302066 qdf_mem_copy(params.identification_id, id, params.id_length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002067 params.pass_length = strlen(password);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302068 qdf_mem_copy(params.password, password, params.pass_length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002069
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002070 hdd_info("%d %pM %.8s %u %.16s %u",
2071 params.vdev_id, params.wakee_mac_addr.bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002072 params.identification_id, params.id_length,
2073 params.password, params.pass_length);
2074
2075 return hdd_set_app_type1_params(hHal, &params);
2076}
2077
2078static int hdd_set_app_type2_params(tHalHandle hHal,
2079 tpSirAppType2Params arg_params)
2080{
2081 tSirAppType2Params params;
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05302082 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002083
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302084 qdf_mem_copy(&params, arg_params, sizeof(params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002085
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05302086 qdf_ret_status = sme_configure_app_type2_params(hHal, &params);
2087 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002088 hdd_err("sme_configure_app_type2_params returned failure %d",
2089 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002090 return -EPERM;
2091 }
2092
2093 return 0;
2094}
2095
2096static int hdd_set_app_type2_parser(hdd_adapter_t *adapter,
2097 char *arg, int len)
2098{
2099 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2100 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
2101 char mac_addr[20], rc4_key[20];
Anurag Chouhan6d760662016-02-20 16:05:43 +05302102 unsigned int gateway_mac[QDF_MAC_ADDR_SIZE];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002103 tSirAppType2Params params;
2104 int ret;
2105
2106 ret = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302107 if (ret)
2108 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002109
2110 memset(&params, 0, sizeof(tSirAppType2Params));
2111
Bhargav Shahf4fd97d2015-07-08 10:21:37 +05302112 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 -08002113 mac_addr, rc4_key, (unsigned int *)&params.ip_id,
2114 (unsigned int *)&params.ip_device_ip,
2115 (unsigned int *)&params.ip_server_ip,
2116 (unsigned int *)&params.tcp_seq,
2117 (unsigned int *)&params.tcp_ack_seq,
Bhargav Shahf4fd97d2015-07-08 10:21:37 +05302118 (uint16_t *)&params.tcp_src_port,
2119 (uint16_t *)&params.tcp_dst_port,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002120 (unsigned int *)&params.keepalive_init,
2121 (unsigned int *)&params.keepalive_min,
2122 (unsigned int *)&params.keepalive_max,
2123 (unsigned int *)&params.keepalive_inc,
2124 (unsigned int *)&params.tcp_tx_timeout_val,
2125 (unsigned int *)&params.tcp_rx_timeout_val);
2126
2127 if (ret != 15 && ret != 7) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002128 hdd_err("Invalid Number of arguments");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002129 return -EINVAL;
2130 }
2131
2132 if (6 !=
2133 sscanf(mac_addr, "%02x:%02x:%02x:%02x:%02x:%02x", &gateway_mac[0],
2134 &gateway_mac[1], &gateway_mac[2], &gateway_mac[3],
2135 &gateway_mac[4], &gateway_mac[5])) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002136 hdd_err("Invalid MacAddress Input %s", mac_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002137 return -EINVAL;
2138 }
2139
2140 if (params.tcp_src_port > WLAN_HDD_MAX_TCP_PORT ||
2141 params.tcp_dst_port > WLAN_HDD_MAX_TCP_PORT) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002142 hdd_err("Invalid TCP Port Number");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002143 return -EINVAL;
2144 }
2145
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302146 qdf_mem_copy(&params.gateway_mac.bytes, (uint8_t *) &gateway_mac,
Anurag Chouhan6d760662016-02-20 16:05:43 +05302147 QDF_MAC_ADDR_SIZE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002148
2149 params.rc4_key_len = strlen(rc4_key);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302150 qdf_mem_copy(params.rc4_key, rc4_key, params.rc4_key_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002151
2152 params.vdev_id = adapter->sessionId;
2153 params.tcp_src_port = (params.tcp_src_port != 0) ?
2154 params.tcp_src_port : hdd_ctx->config->extWowApp2TcpSrcPort;
2155 params.tcp_dst_port = (params.tcp_dst_port != 0) ?
2156 params.tcp_dst_port : hdd_ctx->config->extWowApp2TcpDstPort;
2157 params.keepalive_init = (params.keepalive_init != 0) ?
2158 params.keepalive_init : hdd_ctx->config->
2159 extWowApp2KAInitPingInterval;
2160 params.keepalive_min =
2161 (params.keepalive_min != 0) ?
2162 params.keepalive_min :
2163 hdd_ctx->config->extWowApp2KAMinPingInterval;
2164 params.keepalive_max =
2165 (params.keepalive_max != 0) ?
2166 params.keepalive_max :
2167 hdd_ctx->config->extWowApp2KAMaxPingInterval;
2168 params.keepalive_inc =
2169 (params.keepalive_inc != 0) ?
2170 params.keepalive_inc :
2171 hdd_ctx->config->extWowApp2KAIncPingInterval;
2172 params.tcp_tx_timeout_val =
2173 (params.tcp_tx_timeout_val != 0) ?
2174 params.tcp_tx_timeout_val :
2175 hdd_ctx->config->extWowApp2TcpTxTimeout;
2176 params.tcp_rx_timeout_val =
2177 (params.tcp_rx_timeout_val != 0) ?
2178 params.tcp_rx_timeout_val :
2179 hdd_ctx->config->extWowApp2TcpRxTimeout;
2180
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002181 hdd_info("%pM %.16s %u %u %u %u %u %u %u %u %u %u %u %u %u",
2182 gateway_mac, rc4_key, params.ip_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002183 params.ip_device_ip, params.ip_server_ip, params.tcp_seq,
2184 params.tcp_ack_seq, params.tcp_src_port, params.tcp_dst_port,
2185 params.keepalive_init, params.keepalive_min,
2186 params.keepalive_max, params.keepalive_inc,
2187 params.tcp_tx_timeout_val, params.tcp_rx_timeout_val);
2188
2189 return hdd_set_app_type2_params(hHal, &params);
2190}
2191#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
2192
2193/**
2194 * hdd_parse_setmaxtxpower_command() - HDD Parse MAXTXPOWER command
2195 * @pValue: Pointer to MAXTXPOWER command
2196 * @pDbm: Pointer to tx power
2197 *
2198 * This function parses the MAXTXPOWER command passed in the format
2199 * MAXTXPOWER<space>X(Tx power in dbm)
2200 *
2201 * For example input commands:
2202 * 1) MAXTXPOWER -8 -> This is translated into set max TX power to -8 dbm
2203 * 2) MAXTXPOWER -23 -> This is translated into set max TX power to -23 dbm
2204 *
2205 * Return: 0 for success non-zero for failure
2206 */
2207static int hdd_parse_setmaxtxpower_command(uint8_t *pValue, int *pTxPower)
2208{
2209 uint8_t *inPtr = pValue;
2210 int tempInt;
2211 int v = 0;
2212 *pTxPower = 0;
2213
2214 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2215 /* no argument after the command */
2216 if (NULL == inPtr) {
2217 return -EINVAL;
2218 }
2219
2220 /* no space after the command */
2221 else if (SPACE_ASCII_VALUE != *inPtr) {
2222 return -EINVAL;
2223 }
2224
2225 /* remove empty spaces */
2226 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2227 inPtr++;
2228
2229 /* no argument followed by spaces */
2230 if ('\0' == *inPtr) {
2231 return 0;
2232 }
2233
2234 v = kstrtos32(inPtr, 10, &tempInt);
2235
2236 /* Range checking for passed parameter */
2237 if ((tempInt < HDD_MIN_TX_POWER) || (tempInt > HDD_MAX_TX_POWER)) {
2238 return -EINVAL;
2239 }
2240
2241 *pTxPower = tempInt;
2242
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002243 hdd_info("SETMAXTXPOWER: %d", *pTxPower);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002244
2245 return 0;
2246} /* End of hdd_parse_setmaxtxpower_command */
2247
2248static int hdd_get_dwell_time(struct hdd_config *pCfg, uint8_t *command,
2249 char *extra, uint8_t n, uint8_t *len)
2250{
2251 int ret = 0;
2252
2253 if (!pCfg || !command || !extra || !len) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002254 hdd_err("argument passed for GETDWELLTIME is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002255 ret = -EINVAL;
2256 return ret;
2257 }
2258
2259 if (strncmp(command, "GETDWELLTIME ACTIVE MAX", 23) == 0) {
2260 *len = scnprintf(extra, n, "GETDWELLTIME ACTIVE MAX %u\n",
2261 (int)pCfg->nActiveMaxChnTime);
2262 return ret;
2263 } else if (strncmp(command, "GETDWELLTIME ACTIVE MIN", 23) == 0) {
2264 *len = scnprintf(extra, n, "GETDWELLTIME ACTIVE MIN %u\n",
2265 (int)pCfg->nActiveMinChnTime);
2266 return ret;
2267 } else if (strncmp(command, "GETDWELLTIME PASSIVE MAX", 24) == 0) {
2268 *len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MAX %u\n",
2269 (int)pCfg->nPassiveMaxChnTime);
2270 return ret;
2271 } else if (strncmp(command, "GETDWELLTIME PASSIVE MIN", 24) == 0) {
2272 *len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MIN %u\n",
2273 (int)pCfg->nPassiveMinChnTime);
2274 return ret;
2275 } else if (strncmp(command, "GETDWELLTIME", 12) == 0) {
2276 *len = scnprintf(extra, n, "GETDWELLTIME %u \n",
2277 (int)pCfg->nActiveMaxChnTime);
2278 return ret;
2279 } else {
2280 ret = -EINVAL;
2281 }
2282
2283 return ret;
2284}
2285
2286static int hdd_set_dwell_time(hdd_adapter_t *adapter, uint8_t *command)
2287{
2288 tHalHandle hHal;
2289 struct hdd_config *pCfg;
2290 uint8_t *value = command;
2291 tSmeConfigParams smeConfig;
2292 int val = 0, temp = 0;
2293
2294 pCfg = (WLAN_HDD_GET_CTX(adapter))->config;
2295 hHal = WLAN_HDD_GET_HAL_CTX(adapter);
2296 if (!pCfg || !hHal) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002297 hdd_err("argument passed for SETDWELLTIME is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002298 return -EINVAL;
2299 }
2300
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302301 qdf_mem_zero(&smeConfig, sizeof(smeConfig));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002302 sme_get_config_param(hHal, &smeConfig);
2303
2304 if (strncmp(command, "SETDWELLTIME ACTIVE MAX", 23) == 0) {
2305 value = value + 24;
2306 temp = kstrtou32(value, 10, &val);
2307 if (temp != 0 || val < CFG_ACTIVE_MAX_CHANNEL_TIME_MIN ||
2308 val > CFG_ACTIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002309 hdd_err("argument passed for SETDWELLTIME ACTIVE MAX is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002310 return -EFAULT;
2311 }
2312 pCfg->nActiveMaxChnTime = val;
2313 smeConfig.csrConfig.nActiveMaxChnTime = val;
2314 sme_update_config(hHal, &smeConfig);
2315 } else if (strncmp(command, "SETDWELLTIME ACTIVE MIN", 23) == 0) {
2316 value = value + 24;
2317 temp = kstrtou32(value, 10, &val);
2318 if (temp != 0 || val < CFG_ACTIVE_MIN_CHANNEL_TIME_MIN ||
2319 val > CFG_ACTIVE_MIN_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002320 hdd_err("argument passed for SETDWELLTIME ACTIVE MIN is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002321 return -EFAULT;
2322 }
2323 pCfg->nActiveMinChnTime = val;
2324 smeConfig.csrConfig.nActiveMinChnTime = val;
2325 sme_update_config(hHal, &smeConfig);
2326 } else if (strncmp(command, "SETDWELLTIME PASSIVE MAX", 24) == 0) {
2327 value = value + 25;
2328 temp = kstrtou32(value, 10, &val);
2329 if (temp != 0 || val < CFG_PASSIVE_MAX_CHANNEL_TIME_MIN ||
2330 val > CFG_PASSIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002331 hdd_err("argument passed for SETDWELLTIME PASSIVE MAX is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002332 return -EFAULT;
2333 }
2334 pCfg->nPassiveMaxChnTime = val;
2335 smeConfig.csrConfig.nPassiveMaxChnTime = val;
2336 sme_update_config(hHal, &smeConfig);
2337 } else if (strncmp(command, "SETDWELLTIME PASSIVE MIN", 24) == 0) {
2338 value = value + 25;
2339 temp = kstrtou32(value, 10, &val);
2340 if (temp != 0 || val < CFG_PASSIVE_MIN_CHANNEL_TIME_MIN ||
2341 val > CFG_PASSIVE_MIN_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002342 hdd_err("argument passed for SETDWELLTIME PASSIVE MIN is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002343 return -EFAULT;
2344 }
2345 pCfg->nPassiveMinChnTime = val;
2346 smeConfig.csrConfig.nPassiveMinChnTime = val;
2347 sme_update_config(hHal, &smeConfig);
2348 } else if (strncmp(command, "SETDWELLTIME", 12) == 0) {
2349 value = value + 13;
2350 temp = kstrtou32(value, 10, &val);
2351 if (temp != 0 || val < CFG_ACTIVE_MAX_CHANNEL_TIME_MIN ||
2352 val > CFG_ACTIVE_MAX_CHANNEL_TIME_MAX) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002353 hdd_err("argument passed for SETDWELLTIME is incorrect");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002354 return -EFAULT;
2355 }
2356 pCfg->nActiveMaxChnTime = val;
2357 smeConfig.csrConfig.nActiveMaxChnTime = val;
2358 sme_update_config(hHal, &smeConfig);
2359 } else {
2360 return -EINVAL;
2361 }
2362
2363 return 0;
2364}
2365
2366static void hdd_get_link_status_cb(uint8_t status, void *context)
2367{
2368 struct statsContext *pLinkContext;
2369 hdd_adapter_t *adapter;
2370
2371 if (NULL == context) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002372 hdd_err("Bad context [%p]", context);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002373 return;
2374 }
2375
2376 pLinkContext = context;
2377 adapter = pLinkContext->pAdapter;
2378
2379 spin_lock(&hdd_context_lock);
2380
2381 if ((NULL == adapter) ||
2382 (LINK_STATUS_MAGIC != pLinkContext->magic)) {
2383 /*
2384 * the caller presumably timed out so there is
2385 * nothing we can do
2386 */
2387 spin_unlock(&hdd_context_lock);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002388 hdd_warn("Invalid context, adapter [%p] magic [%08x]",
2389 adapter, pLinkContext->magic);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002390 return;
2391 }
2392
2393 /* context is valid so caller is still waiting */
2394
2395 /* paranoia: invalidate the magic */
2396 pLinkContext->magic = 0;
2397
2398 /* copy over the status */
2399 adapter->linkStatus = status;
2400
2401 /* notify the caller */
2402 complete(&pLinkContext->completion);
2403
2404 /* serialization is complete */
2405 spin_unlock(&hdd_context_lock);
2406}
2407
2408/**
2409 * wlan_hdd_get_link_status() - get link status
2410 * @pAdapter: pointer to the adapter
2411 *
2412 * This function sends a request to query the link status and waits
2413 * on a timer to invoke the callback. if the callback is invoked then
2414 * latest link status shall be returned or otherwise cached value
2415 * will be returned.
2416 *
2417 * Return: On success, link status shall be returned.
2418 * On error or not associated, link status 0 will be returned.
2419 */
2420static int wlan_hdd_get_link_status(hdd_adapter_t *adapter)
2421{
2422
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002423 hdd_station_ctx_t *pHddStaCtx =
2424 WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Houston Hoffman59c097f2016-11-09 15:50:25 -08002425 static struct statsContext context;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302426 QDF_STATUS hstatus;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002427 unsigned long rc;
2428
Prashanth Bhatta9e143052015-12-04 11:56:47 -08002429 if (cds_is_driver_recovering()) {
2430 hdd_warn("Recovery in Progress. State: 0x%x Ignore!!!",
2431 cds_get_driver_state());
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002432 return 0;
2433 }
2434
Krunal Sonibe766b02016-03-10 13:00:44 -08002435 if ((QDF_STA_MODE != adapter->device_mode) &&
2436 (QDF_P2P_CLIENT_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002437 hdd_warn("Unsupported in mode %s(%d)",
2438 hdd_device_mode_to_string(adapter->device_mode),
2439 adapter->device_mode);
2440 return 0;
2441 }
2442
2443 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
2444 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
2445 /* If not associated, then expected link status return
2446 * value is 0
2447 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002448 hdd_info("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002449 return 0;
2450 }
2451
2452 init_completion(&context.completion);
2453 context.pAdapter = adapter;
2454 context.magic = LINK_STATUS_MAGIC;
2455 hstatus = sme_get_link_status(WLAN_HDD_GET_HAL_CTX(adapter),
2456 hdd_get_link_status_cb,
2457 &context, adapter->sessionId);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302458 if (QDF_STATUS_SUCCESS != hstatus) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002459 hdd_err("Unable to retrieve link status");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002460 /* return a cached value */
2461 } else {
2462 /* request is sent -- wait for the response */
2463 rc = wait_for_completion_timeout(&context.completion,
2464 msecs_to_jiffies(WLAN_WAIT_TIME_LINK_STATUS));
2465 if (!rc)
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002466 hdd_err("SME timed out while retrieving link status");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002467 }
2468
2469 spin_lock(&hdd_context_lock);
2470 context.magic = 0;
2471 spin_unlock(&hdd_context_lock);
2472
2473 /* either callback updated adapter stats or it has cached data */
2474 return adapter->linkStatus;
2475}
2476
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002477static void hdd_tx_fail_ind_callback(uint8_t *MacAddr, uint8_t seqNo)
2478{
2479 int payload_len;
2480 struct sk_buff *skb;
2481 struct nlmsghdr *nlh;
2482 uint8_t *data;
2483
2484 payload_len = ETH_ALEN;
2485
Ryan Hsu5e2e2052016-04-28 10:19:38 -07002486 if (0 == cesium_pid || cesium_nl_srv_sock == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002487 hdd_err("cesium process not registered");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002488 return;
2489 }
2490
2491 skb = nlmsg_new(payload_len, GFP_ATOMIC);
2492 if (skb == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002493 hdd_err("nlmsg_new() failed for msg size[%d]",
2494 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002495 return;
2496 }
2497
2498 nlh = nlmsg_put(skb, cesium_pid, seqNo, 0, payload_len, NLM_F_REQUEST);
2499
2500 if (NULL == nlh) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002501 hdd_err("nlmsg_put() failed for msg size[%d]",
2502 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002503
2504 kfree_skb(skb);
2505 return;
2506 }
2507
2508 data = nlmsg_data(nlh);
2509 memcpy(data, MacAddr, ETH_ALEN);
2510
2511 if (nlmsg_unicast(cesium_nl_srv_sock, skb, cesium_pid) < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002512 hdd_err("nlmsg_unicast() failed for msg size[%d]",
2513 NLMSG_SPACE(payload_len));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08002514 }
2515
2516 return;
2517}
2518
2519
2520/**
2521 * hdd_ParseuserParams - return a pointer to the next argument
2522 * @pValue: Input argument string
2523 * @ppArg: Output pointer to the next argument
2524 *
2525 * This function parses argument stream and finds the pointer
2526 * to the next argument
2527 *
2528 * Return: 0 if the next argument found; -EINVAL otherwise
2529 */
2530static int hdd_parse_user_params(uint8_t *pValue, uint8_t **ppArg)
2531{
2532 uint8_t *pVal;
2533
2534 pVal = strnchr(pValue, strlen(pValue), ' ');
2535
2536 if (NULL == pVal) {
2537 /* no argument remains */
2538 return -EINVAL;
2539 } else if (SPACE_ASCII_VALUE != *pVal) {
2540 /* no space after the current argument */
2541 return -EINVAL;
2542 }
2543
2544 pVal++;
2545
2546 /* remove empty spaces */
2547 while ((SPACE_ASCII_VALUE == *pVal) && ('\0' != *pVal)) {
2548 pVal++;
2549 }
2550
2551 /* no argument followed by spaces */
2552 if ('\0' == *pVal) {
2553 return -EINVAL;
2554 }
2555
2556 *ppArg = pVal;
2557
2558 return 0;
2559}
2560
2561/**
2562 * hdd_parse_ibsstx_fail_event_params - Parse params
2563 * for SETIBSSTXFAILEVENT
2564 * @pValue: Input ibss tx fail event argument
2565 * @tx_fail_count: (Output parameter) Tx fail counter
2566 * @pid: (Output parameter) PID
2567 *
2568 * Return: 0 if the parsing succeeds; -EINVAL otherwise
2569 */
2570static int hdd_parse_ibsstx_fail_event_params(uint8_t *pValue,
2571 uint8_t *tx_fail_count,
2572 uint16_t *pid)
2573{
2574 uint8_t *param = NULL;
2575 int ret;
2576
2577 ret = hdd_parse_user_params(pValue, &param);
2578
2579 if (0 == ret && NULL != param) {
2580 if (1 != sscanf(param, "%hhu", tx_fail_count)) {
2581 ret = -EINVAL;
2582 goto done;
2583 }
2584 } else {
2585 goto done;
2586 }
2587
2588 if (0 == *tx_fail_count) {
2589 *pid = 0;
2590 goto done;
2591 }
2592
2593 pValue = param;
2594 pValue++;
2595
2596 ret = hdd_parse_user_params(pValue, &param);
2597
2598 if (0 == ret) {
2599 if (1 != sscanf(param, "%hu", pid)) {
2600 ret = -EINVAL;
2601 goto done;
2602 }
2603 } else {
2604 goto done;
2605 }
2606
2607done:
2608 return ret;
2609}
2610
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08002611#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002612/**
2613 * hdd_parse_ese_beacon_req() - Parse ese beacon request
2614 * @pValue: Pointer to data
2615 * @pEseBcnReq: Output pointer to store parsed ie information
2616 *
2617 * This function parses the ese beacon request passed in the format
2618 * CCXBEACONREQ<space><Number of fields><space><Measurement token>
2619 * <space>Channel 1<space>Scan Mode <space>Meas Duration<space>Channel N
2620 * <space>Scan Mode N<space>Meas Duration N
2621 *
2622 * If the Number of bcn req fields (N) does not match with the
2623 * actual number of fields passed then take N.
2624 * <Meas Token><Channel><Scan Mode> and <Meas Duration> are treated
2625 * as one pair. For example, CCXBEACONREQ 2 1 1 1 30 2 44 0 40.
2626 * This function does not take care of removing duplicate channels from the
2627 * list
2628 *
2629 * Return: 0 for success non-zero for failure
2630 */
2631static int hdd_parse_ese_beacon_req(uint8_t *pValue,
2632 tCsrEseBeaconReq *pEseBcnReq)
2633{
2634 uint8_t *inPtr = pValue;
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002635 uint8_t input = 0;
2636 uint32_t tempInt = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002637 int j = 0, i = 0, v = 0;
2638 char buf[32];
2639
2640 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2641 /* no argument after the command */
2642 if (NULL == inPtr) {
2643 return -EINVAL;
2644 }
2645 /* no space after the command */
2646 else if (SPACE_ASCII_VALUE != *inPtr) {
2647 return -EINVAL;
2648 }
2649
2650 /* remove empty spaces */
2651 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2652 inPtr++;
2653
2654 /* no argument followed by spaces */
2655 if ('\0' == *inPtr)
2656 return -EINVAL;
2657
Srinivas Girigowda476deeb2016-07-19 16:21:29 -07002658 /* Getting the first argument ie Number of IE fields */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002659 v = sscanf(inPtr, "%31s ", buf);
2660 if (1 != v)
2661 return -EINVAL;
2662
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002663 v = kstrtou8(buf, 10, &input);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002664 if (v < 0)
2665 return -EINVAL;
2666
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002667 input = QDF_MIN(input, SIR_ESE_MAX_MEAS_IE_REQS);
2668 pEseBcnReq->numBcnReqIe = input;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002669
Srinivas Girigowda476deeb2016-07-19 16:21:29 -07002670 hdd_info("Number of Bcn Req Ie fields: %d", pEseBcnReq->numBcnReqIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002671
2672 for (j = 0; j < (pEseBcnReq->numBcnReqIe); j++) {
2673 for (i = 0; i < 4; i++) {
2674 /*
2675 * inPtr pointing to the beginning of 1st space
2676 * after number of ie fields
2677 */
2678 inPtr = strpbrk(inPtr, " ");
2679 /* no ie data after the number of ie fields argument */
2680 if (NULL == inPtr)
2681 return -EINVAL;
2682
2683 /* remove empty space */
2684 while ((SPACE_ASCII_VALUE == *inPtr)
2685 && ('\0' != *inPtr))
2686 inPtr++;
2687
2688 /*
2689 * no ie data after the number of ie fields
2690 * argument and spaces
2691 */
2692 if ('\0' == *inPtr)
2693 return -EINVAL;
2694
2695 v = sscanf(inPtr, "%31s ", buf);
2696 if (1 != v)
2697 return -EINVAL;
2698
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002699 v = kstrtou32(buf, 10, &tempInt);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002700 if (v < 0)
2701 return -EINVAL;
2702
2703 switch (i) {
2704 case 0: /* Measurement token */
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002705 if (!tempInt) {
2706 hdd_err("Invalid Measurement Token: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002707 tempInt);
2708 return -EINVAL;
2709 }
2710 pEseBcnReq->bcnReq[j].measurementToken =
2711 tempInt;
2712 break;
2713
2714 case 1: /* Channel number */
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002715 if (!tempInt ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002716 (tempInt >
2717 WNI_CFG_CURRENT_CHANNEL_STAMAX)) {
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002718 hdd_err("Invalid Channel Number: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002719 tempInt);
2720 return -EINVAL;
2721 }
2722 pEseBcnReq->bcnReq[j].channel = tempInt;
2723 break;
2724
2725 case 2: /* Scan mode */
2726 if ((tempInt < eSIR_PASSIVE_SCAN)
2727 || (tempInt > eSIR_BEACON_TABLE)) {
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002728 hdd_err("Invalid Scan Mode: %u Expected{0|1|2}",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002729 tempInt);
2730 return -EINVAL;
2731 }
2732 pEseBcnReq->bcnReq[j].scanMode = tempInt;
2733 break;
2734
2735 case 3: /* Measurement duration */
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002736 if ((!tempInt
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002737 && (pEseBcnReq->bcnReq[j].scanMode !=
2738 eSIR_BEACON_TABLE)) ||
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002739 (pEseBcnReq->bcnReq[j].scanMode ==
2740 eSIR_BEACON_TABLE)) {
2741 hdd_err("Invalid Measurement Duration: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002742 tempInt);
2743 return -EINVAL;
2744 }
2745 pEseBcnReq->bcnReq[j].measurementDuration =
2746 tempInt;
2747 break;
2748 }
2749 }
2750 }
2751
2752 for (j = 0; j < pEseBcnReq->numBcnReqIe; j++) {
Srinivas Girigowda67e2da62016-07-19 16:33:01 -07002753 hdd_info("Index: %d Measurement Token: %u Channel: %u Scan Mode: %u Measurement Duration: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002754 j,
2755 pEseBcnReq->bcnReq[j].measurementToken,
2756 pEseBcnReq->bcnReq[j].channel,
2757 pEseBcnReq->bcnReq[j].scanMode,
2758 pEseBcnReq->bcnReq[j].measurementDuration);
2759 }
2760
2761 return 0;
2762}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002763
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002764/**
2765 * hdd_parse_get_cckm_ie() - HDD Parse and fetch the CCKM IE
2766 * @pValue: Pointer to input data
2767 * @pCckmIe: Pointer to output cckm Ie
2768 * @pCckmIeLen: Pointer to output cckm ie length
2769 *
2770 * This function parses the SETCCKM IE command
2771 * SETCCKMIE<space><ie data>
2772 *
2773 * Return: 0 for success non-zero for failure
2774 */
2775static int hdd_parse_get_cckm_ie(uint8_t *pValue, uint8_t **pCckmIe,
2776 uint8_t *pCckmIeLen)
2777{
2778 uint8_t *inPtr = pValue;
2779 uint8_t *dataEnd;
2780 int j = 0;
2781 int i = 0;
2782 uint8_t tempByte = 0;
2783 inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE);
2784 /* no argument after the command */
2785 if (NULL == inPtr) {
2786 return -EINVAL;
2787 }
2788 /* no space after the command */
2789 else if (SPACE_ASCII_VALUE != *inPtr) {
2790 return -EINVAL;
2791 }
2792 /* remove empty spaces */
2793 while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr))
2794 inPtr++;
2795 /* no argument followed by spaces */
2796 if ('\0' == *inPtr) {
2797 return -EINVAL;
2798 }
2799 /* find the length of data */
2800 dataEnd = inPtr;
2801 while (('\0' != *dataEnd)) {
2802 dataEnd++;
2803 ++(*pCckmIeLen);
2804 }
2805 if (*pCckmIeLen <= 0)
2806 return -EINVAL;
2807 /*
2808 * Allocate the number of bytes based on the number of input characters
2809 * whether it is even or odd.
2810 * if the number of input characters are even, then we need N / 2 byte.
2811 * if the number of input characters are odd, then we need do
2812 * (N + 1) / 2 to compensate rounding off.
2813 * For example, if N = 18, then (18 + 1) / 2 = 9 bytes are enough.
2814 * If N = 19, then we need 10 bytes, hence (19 + 1) / 2 = 10 bytes
2815 */
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302816 *pCckmIe = qdf_mem_malloc((*pCckmIeLen + 1) / 2);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002817 if (NULL == *pCckmIe) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002818 hdd_err("qdf_mem_malloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002819 return -ENOMEM;
2820 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002821 /*
2822 * the buffer received from the upper layer is character buffer,
2823 * we need to prepare the buffer taking 2 characters in to a U8 hex
2824 * decimal number for example 7f0000f0...form a buffer to contain
2825 * 7f in 0th location, 00 in 1st and f0 in 3rd location
2826 */
2827 for (i = 0, j = 0; j < *pCckmIeLen; j += 2) {
2828 tempByte = (hex_to_bin(inPtr[j]) << 4) |
2829 (hex_to_bin(inPtr[j + 1]));
2830 (*pCckmIe)[i++] = tempByte;
2831 }
2832 *pCckmIeLen = i;
2833 return 0;
2834}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08002835#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002836
2837int wlan_hdd_set_mc_rate(hdd_adapter_t *pAdapter, int targetRate)
2838{
2839 tSirRateUpdateInd rateUpdate = {0};
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302840 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002841 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
2842 struct hdd_config *pConfig = NULL;
2843
2844 if (pHddCtx == NULL) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002845 hdd_err("HDD context is null");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002846 return -EINVAL;
2847 }
Krunal Sonibe766b02016-03-10 13:00:44 -08002848 if ((QDF_IBSS_MODE != pAdapter->device_mode) &&
2849 (QDF_SAP_MODE != pAdapter->device_mode) &&
2850 (QDF_STA_MODE != pAdapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002851 hdd_err("Received SETMCRATE cmd in invalid mode %s(%d)",
2852 hdd_device_mode_to_string(pAdapter->device_mode),
2853 pAdapter->device_mode);
2854 hdd_err("SETMCRATE cmd is allowed only in STA, IBSS or SOFTAP mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002855 return -EINVAL;
2856 }
2857 pConfig = pHddCtx->config;
2858 rateUpdate.nss = (pConfig->enable2x2 == 0) ? 0 : 1;
2859 rateUpdate.dev_mode = pAdapter->device_mode;
2860 rateUpdate.mcastDataRate24GHz = targetRate;
2861 rateUpdate.mcastDataRate24GHzTxFlag = 1;
2862 rateUpdate.mcastDataRate5GHz = targetRate;
2863 rateUpdate.bcastDataRate = -1;
Anurag Chouhanc5548422016-02-24 18:33:27 +05302864 qdf_copy_macaddr(&rateUpdate.bssid, &pAdapter->macAddressCurrent);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002865 hdd_info("MC Target rate %d, mac = %pM, dev_mode %s(%d)",
2866 rateUpdate.mcastDataRate24GHz, rateUpdate.bssid.bytes,
2867 hdd_device_mode_to_string(pAdapter->device_mode),
2868 pAdapter->device_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002869 status = sme_send_rate_update_ind(pHddCtx->hHal, &rateUpdate);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302870 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002871 hdd_err("SETMCRATE failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002872 return -EFAULT;
2873 }
2874 return 0;
2875}
2876
2877static int drv_cmd_p2p_dev_addr(hdd_adapter_t *adapter,
2878 hdd_context_t *hdd_ctx,
2879 uint8_t *command,
2880 uint8_t command_len,
2881 hdd_priv_data_t *priv_data)
2882{
2883 int ret = 0;
2884
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302885 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002886 TRACE_CODE_HDD_P2P_DEV_ADDR_IOCTL,
2887 adapter->sessionId,
2888 (unsigned)(*(hdd_ctx->p2pDeviceAddress.bytes + 2)
2889 << 24 | *(hdd_ctx->p2pDeviceAddress.bytes
2890 + 3) << 16 | *(hdd_ctx->
2891 p2pDeviceAddress.bytes + 4) << 8 |
2892 *(hdd_ctx->p2pDeviceAddress.bytes +
2893 5))));
2894
2895 if (copy_to_user(priv_data->buf, hdd_ctx->p2pDeviceAddress.bytes,
2896 sizeof(tSirMacAddr))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002897 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002898 ret = -EFAULT;
2899 }
2900
2901 return ret;
2902}
2903
2904/**
2905 * drv_cmd_p2p_set_noa() - Handler for P2P_SET_NOA driver command
2906 * @adapter: Adapter on which the command was received
2907 * @hdd_ctx: HDD global context
2908 * @command: Entire driver command received from userspace
2909 * @command_len: Length of @command
2910 * @priv_data: Pointer to ioctl private data structure
2911 *
2912 * This is a trivial command hander function which simply forwards the
2913 * command to the actual command processor within the P2P module.
2914 *
2915 * Return: 0 on success, non-zero on failure
2916 */
2917static int drv_cmd_p2p_set_noa(hdd_adapter_t *adapter,
2918 hdd_context_t *hdd_ctx,
2919 uint8_t *command,
2920 uint8_t command_len,
2921 hdd_priv_data_t *priv_data)
2922{
2923 return hdd_set_p2p_noa(adapter->dev, command);
2924}
2925
2926/**
2927 * drv_cmd_p2p_set_ps() - Handler for P2P_SET_PS driver command
2928 * @adapter: Adapter on which the command was received
2929 * @hdd_ctx: HDD global context
2930 * @command: Entire driver command received from userspace
2931 * @command_len: Length of @command
2932 * @priv_data: Pointer to ioctl private data structure
2933 *
2934 * This is a trivial command hander function which simply forwards the
2935 * command to the actual command processor within the P2P module.
2936 *
2937 * Return: 0 on success, non-zero on failure
2938 */
2939static int drv_cmd_p2p_set_ps(hdd_adapter_t *adapter,
2940 hdd_context_t *hdd_ctx,
2941 uint8_t *command,
2942 uint8_t command_len,
2943 hdd_priv_data_t *priv_data)
2944{
2945 return hdd_set_p2p_opps(adapter->dev, command);
2946}
2947
2948static int drv_cmd_set_band(hdd_adapter_t *adapter,
2949 hdd_context_t *hdd_ctx,
2950 uint8_t *command,
2951 uint8_t command_len,
2952 hdd_priv_data_t *priv_data)
2953{
2954 int ret = 0;
2955
2956 uint8_t *ptr = command;
2957
2958 /* Change band request received */
2959
2960 /*
2961 * First 8 bytes will have "SETBAND " and
2962 * 9 byte will have band setting value
2963 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07002964 hdd_info("SetBandCommand Info comm %s UL %d, TL %d",
2965 command, priv_data->used_len,
2966 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002967
2968 /* Change band request received */
2969 ret = hdd_set_band_helper(adapter->dev, ptr);
2970
2971 return ret;
2972}
2973
2974static int drv_cmd_set_wmmps(hdd_adapter_t *adapter,
2975 hdd_context_t *hdd_ctx,
2976 uint8_t *command,
2977 uint8_t command_len,
2978 hdd_priv_data_t *priv_data)
2979{
2980 return hdd_wmmps_helper(adapter, command);
2981}
2982
2983static int drv_cmd_country(hdd_adapter_t *adapter,
2984 hdd_context_t *hdd_ctx,
2985 uint8_t *command,
2986 uint8_t command_len,
2987 hdd_priv_data_t *priv_data)
2988{
2989 int ret = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302990 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002991 unsigned long rc;
2992 char *country_code;
2993
2994 country_code = command + 8;
2995
2996 INIT_COMPLETION(adapter->change_country_code);
2997
2998 status = sme_change_country_code(hdd_ctx->hHal,
2999 wlan_hdd_change_country_code_callback,
3000 country_code,
3001 adapter,
3002 hdd_ctx->pcds_context,
3003 eSIR_TRUE,
3004 eSIR_TRUE);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303005 if (status == QDF_STATUS_SUCCESS) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003006 rc = wait_for_completion_timeout(
3007 &adapter->change_country_code,
3008 msecs_to_jiffies(WLAN_WAIT_TIME_COUNTRY));
3009 if (!rc)
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003010 hdd_err("SME while setting country code timed out");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003011 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003012 hdd_err("SME Change Country code fail, status %d",
3013 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003014 ret = -EINVAL;
3015 }
3016
3017 return ret;
3018}
3019
3020static int drv_cmd_set_roam_trigger(hdd_adapter_t *adapter,
3021 hdd_context_t *hdd_ctx,
3022 uint8_t *command,
3023 uint8_t command_len,
3024 hdd_priv_data_t *priv_data)
3025{
3026 int ret = 0;
3027 uint8_t *value = command;
3028 int8_t rssi = 0;
3029 uint8_t lookUpThreshold = CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_DEFAULT;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303030 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003031
3032 /* Move pointer to ahead of SETROAMTRIGGER<delimiter> */
3033 value = value + command_len + 1;
3034
3035 /* Convert the value from ascii to integer */
3036 ret = kstrtos8(value, 10, &rssi);
3037 if (ret < 0) {
3038 /*
3039 * If the input value is greater than max value of datatype,
3040 * then also kstrtou8 fails
3041 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003042 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
3043 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN,
3044 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003045 ret = -EINVAL;
3046 goto exit;
3047 }
3048
3049 lookUpThreshold = abs(rssi);
3050
3051 if ((lookUpThreshold < CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN)
3052 || (lookUpThreshold > CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003053 hdd_err("Neighbor lookup threshold value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003054 lookUpThreshold,
3055 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN,
3056 CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX);
3057 ret = -EINVAL;
3058 goto exit;
3059 }
3060
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303061 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003062 TRACE_CODE_HDD_SETROAMTRIGGER_IOCTL,
3063 adapter->sessionId, lookUpThreshold));
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003064 hdd_info("Received Command to Set Roam trigger (Neighbor lookup threshold) = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003065 lookUpThreshold);
3066
3067 hdd_ctx->config->nNeighborLookupRssiThreshold = lookUpThreshold;
3068 status = sme_set_neighbor_lookup_rssi_threshold(hdd_ctx->hHal,
3069 adapter->sessionId,
3070 lookUpThreshold);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303071 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003072 hdd_err("Failed to set roam trigger, try again");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003073 ret = -EPERM;
3074 goto exit;
3075 }
3076
3077exit:
3078 return ret;
3079}
3080
3081static int drv_cmd_get_roam_trigger(hdd_adapter_t *adapter,
3082 hdd_context_t *hdd_ctx,
3083 uint8_t *command,
3084 uint8_t command_len,
3085 hdd_priv_data_t *priv_data)
3086{
3087 int ret = 0;
3088 uint8_t lookUpThreshold =
3089 sme_get_neighbor_lookup_rssi_threshold(hdd_ctx->hHal);
3090 int rssi = (-1) * lookUpThreshold;
3091 char extra[32];
3092 uint8_t len = 0;
3093
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303094 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003095 TRACE_CODE_HDD_GETROAMTRIGGER_IOCTL,
3096 adapter->sessionId, lookUpThreshold));
3097
3098 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303099 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003100 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003101 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003102 ret = -EFAULT;
3103 }
3104
3105 return ret;
3106}
3107
3108static int drv_cmd_set_roam_scan_period(hdd_adapter_t *adapter,
3109 hdd_context_t *hdd_ctx,
3110 uint8_t *command,
3111 uint8_t command_len,
3112 hdd_priv_data_t *priv_data)
3113{
3114 int ret = 0;
3115 uint8_t *value = command;
3116 uint8_t roamScanPeriod = 0;
3117 uint16_t neighborEmptyScanRefreshPeriod =
3118 CFG_EMPTY_SCAN_REFRESH_PERIOD_DEFAULT;
3119
3120 /* input refresh period is in terms of seconds */
3121
3122 /* Move pointer to ahead of SETROAMSCANPERIOD<delimiter> */
3123 value = value + command_len + 1;
3124
3125 /* Convert the value from ascii to integer */
3126 ret = kstrtou8(value, 10, &roamScanPeriod);
3127 if (ret < 0) {
3128 /*
3129 * If the input value is greater than max value of datatype,
3130 * then also kstrtou8 fails
3131 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003132 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
3133 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000),
3134 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003135 ret = -EINVAL;
3136 goto exit;
3137 }
3138
3139 if ((roamScanPeriod < (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000))
3140 || (roamScanPeriod > (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003141 hdd_err("Roam scan period value %d is out of range (Min: %d Max: %d)",
3142 roamScanPeriod,
3143 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000),
3144 (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003145 ret = -EINVAL;
3146 goto exit;
3147 }
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303148 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003149 TRACE_CODE_HDD_SETROAMSCANPERIOD_IOCTL,
3150 adapter->sessionId, roamScanPeriod));
3151 neighborEmptyScanRefreshPeriod = roamScanPeriod * 1000;
3152
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003153 hdd_info("Received Command to Set roam scan period (Empty Scan refresh period) = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003154 roamScanPeriod);
3155
3156 hdd_ctx->config->nEmptyScanRefreshPeriod =
3157 neighborEmptyScanRefreshPeriod;
3158 sme_update_empty_scan_refresh_period(hdd_ctx->hHal,
3159 adapter->sessionId,
3160 neighborEmptyScanRefreshPeriod);
3161
3162exit:
3163 return ret;
3164}
3165
3166static int drv_cmd_get_roam_scan_period(hdd_adapter_t *adapter,
3167 hdd_context_t *hdd_ctx,
3168 uint8_t *command,
3169 uint8_t command_len,
3170 hdd_priv_data_t *priv_data)
3171{
3172 int ret = 0;
3173 uint16_t nEmptyScanRefreshPeriod =
3174 sme_get_empty_scan_refresh_period(hdd_ctx->hHal);
3175 char extra[32];
3176 uint8_t len = 0;
3177
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303178 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003179 TRACE_CODE_HDD_GETROAMSCANPERIOD_IOCTL,
3180 adapter->sessionId,
3181 nEmptyScanRefreshPeriod));
3182 len = scnprintf(extra, sizeof(extra), "%s %d",
3183 "GETROAMSCANPERIOD",
3184 (nEmptyScanRefreshPeriod / 1000));
3185 /* Returned value is in units of seconds */
Anurag Chouhan6d760662016-02-20 16:05:43 +05303186 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003187 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003188 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003189 ret = -EFAULT;
3190 }
3191
3192 return ret;
3193}
3194
3195static int drv_cmd_set_roam_scan_refresh_period(hdd_adapter_t *adapter,
3196 hdd_context_t *hdd_ctx,
3197 uint8_t *command,
3198 uint8_t command_len,
3199 hdd_priv_data_t *priv_data)
3200{
3201 int ret = 0;
3202 uint8_t *value = command;
3203 uint8_t roamScanRefreshPeriod = 0;
3204 uint16_t neighborScanRefreshPeriod =
3205 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_DEFAULT;
3206
3207 /* input refresh period is in terms of seconds */
3208 /* Move pointer to ahead of SETROAMSCANREFRESHPERIOD<delimiter> */
3209 value = value + command_len + 1;
3210
3211 /* Convert the value from ascii to integer */
3212 ret = kstrtou8(value, 10, &roamScanRefreshPeriod);
3213 if (ret < 0) {
3214 /*
3215 * If the input value is greater than max value of datatype,
3216 * then also kstrtou8 fails
3217 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003218 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
3219 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN / 1000,
3220 CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX / 1000);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003221 ret = -EINVAL;
3222 goto exit;
3223 }
3224
3225 if ((roamScanRefreshPeriod <
3226 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN / 1000))
3227 || (roamScanRefreshPeriod >
3228 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX / 1000))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003229 hdd_err("Neighbor scan results refresh period value %d is out of range (Min: %d Max: %d)",
3230 roamScanRefreshPeriod,
3231 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN
3232 / 1000),
3233 (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX
3234 / 1000));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003235 ret = -EINVAL;
3236 goto exit;
3237 }
3238 neighborScanRefreshPeriod = roamScanRefreshPeriod * 1000;
3239
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003240 hdd_info("Received Command to Set roam scan refresh period (Scan refresh period) = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003241 roamScanRefreshPeriod);
3242
3243 hdd_ctx->config->nNeighborResultsRefreshPeriod =
3244 neighborScanRefreshPeriod;
3245 sme_set_neighbor_scan_refresh_period(hdd_ctx->hHal,
3246 adapter->sessionId,
3247 neighborScanRefreshPeriod);
3248
3249exit:
3250 return ret;
3251}
3252
3253static int drv_cmd_get_roam_scan_refresh_period(hdd_adapter_t *adapter,
3254 hdd_context_t *hdd_ctx,
3255 uint8_t *command,
3256 uint8_t command_len,
3257 hdd_priv_data_t *priv_data)
3258{
3259 int ret = 0;
3260 uint16_t value =
3261 sme_get_neighbor_scan_refresh_period(hdd_ctx->hHal);
3262 char extra[32];
3263 uint8_t len = 0;
3264
3265 len = scnprintf(extra, sizeof(extra), "%s %d",
3266 "GETROAMSCANREFRESHPERIOD",
3267 (value / 1000));
3268 /* Returned value is in units of seconds */
Anurag Chouhan6d760662016-02-20 16:05:43 +05303269 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003270 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003271 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003272 ret = -EFAULT;
3273 }
3274
3275 return ret;
3276}
3277
3278static int drv_cmd_set_roam_mode(hdd_adapter_t *adapter,
3279 hdd_context_t *hdd_ctx,
3280 uint8_t *command,
3281 uint8_t command_len,
3282 hdd_priv_data_t *priv_data)
3283{
3284 int ret = 0;
3285 uint8_t *value = command;
3286 uint8_t roamMode = CFG_LFR_FEATURE_ENABLED_DEFAULT;
3287
3288 /* Move pointer to ahead of SETROAMMODE<delimiter> */
3289 value = value + SIZE_OF_SETROAMMODE + 1;
3290
3291 /* Convert the value from ascii to integer */
3292 ret = kstrtou8(value, SIZE_OF_SETROAMMODE, &roamMode);
3293 if (ret < 0) {
3294 /*
3295 * If the input value is greater than max value of datatype,
3296 * then also kstrtou8 fails
3297 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003298 hdd_err("kstrtou8 failed range [%d - %d]",
3299 CFG_LFR_FEATURE_ENABLED_MIN,
3300 CFG_LFR_FEATURE_ENABLED_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003301 ret = -EINVAL;
3302 goto exit;
3303 }
3304 if ((roamMode < CFG_LFR_FEATURE_ENABLED_MIN) ||
3305 (roamMode > CFG_LFR_FEATURE_ENABLED_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003306 hdd_err("Roam Mode value %d is out of range (Min: %d Max: %d)",
3307 roamMode,
3308 CFG_LFR_FEATURE_ENABLED_MIN,
3309 CFG_LFR_FEATURE_ENABLED_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003310 ret = -EINVAL;
3311 goto exit;
3312 }
3313
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003314 hdd_debug("Received Command to Set Roam Mode = %d",
3315 roamMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003316 /*
3317 * Note that
3318 * SETROAMMODE 0 is to enable LFR while
3319 * SETROAMMODE 1 is to disable LFR, but
3320 * notify_is_fast_roam_ini_feature_enabled 0/1 is to
3321 * enable/disable. So, we have to invert the value
3322 * to call sme_update_is_fast_roam_ini_feature_enabled.
3323 */
3324 if (CFG_LFR_FEATURE_ENABLED_MIN == roamMode)
3325 roamMode = CFG_LFR_FEATURE_ENABLED_MAX; /* Roam enable */
3326 else
3327 roamMode = CFG_LFR_FEATURE_ENABLED_MIN; /* Roam disable */
3328
3329 hdd_ctx->config->isFastRoamIniFeatureEnabled = roamMode;
3330 if (roamMode) {
3331 hdd_ctx->config->isRoamOffloadScanEnabled = roamMode;
3332 sme_update_roam_scan_offload_enabled(
3333 (tHalHandle)(hdd_ctx->hHal),
3334 hdd_ctx->config->isRoamOffloadScanEnabled);
3335 sme_update_is_fast_roam_ini_feature_enabled(
3336 hdd_ctx->hHal,
3337 adapter->sessionId,
3338 roamMode);
3339 } else {
3340 sme_update_is_fast_roam_ini_feature_enabled(
3341 hdd_ctx->hHal,
3342 adapter->sessionId,
3343 roamMode);
3344 hdd_ctx->config->isRoamOffloadScanEnabled = roamMode;
3345 sme_update_roam_scan_offload_enabled(
3346 (tHalHandle)(hdd_ctx->hHal),
3347 hdd_ctx->config->isRoamOffloadScanEnabled);
3348 }
3349
3350
3351exit:
3352 return ret;
3353}
3354
3355static int drv_cmd_get_roam_mode(hdd_adapter_t *adapter,
3356 hdd_context_t *hdd_ctx,
3357 uint8_t *command,
3358 uint8_t command_len,
3359 hdd_priv_data_t *priv_data)
3360{
3361 int ret = 0;
3362 bool roamMode = sme_get_is_lfr_feature_enabled(hdd_ctx->hHal);
3363 char extra[32];
3364 uint8_t len = 0;
3365
3366 /*
3367 * roamMode value shall be inverted because the sementics is different.
3368 */
3369 if (CFG_LFR_FEATURE_ENABLED_MIN == roamMode)
3370 roamMode = CFG_LFR_FEATURE_ENABLED_MAX;
3371 else
3372 roamMode = CFG_LFR_FEATURE_ENABLED_MIN;
3373
3374 len = scnprintf(extra, sizeof(extra), "%s %d", command, roamMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303375 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003376 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003377 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003378 ret = -EFAULT;
3379 }
3380
3381 return ret;
3382}
3383
3384static int drv_cmd_set_roam_delta(hdd_adapter_t *adapter,
3385 hdd_context_t *hdd_ctx,
3386 uint8_t *command,
3387 uint8_t command_len,
3388 hdd_priv_data_t *priv_data)
3389{
3390 int ret = 0;
3391 uint8_t *value = command;
3392 uint8_t roamRssiDiff = CFG_ROAM_RSSI_DIFF_DEFAULT;
3393
3394 /* Move pointer to ahead of SETROAMDELTA<delimiter> */
3395 value = value + command_len + 1;
3396
3397 /* Convert the value from ascii to integer */
3398 ret = kstrtou8(value, 10, &roamRssiDiff);
3399 if (ret < 0) {
3400 /*
3401 * If the input value is greater than max value of datatype,
3402 * then also kstrtou8 fails
3403 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003404 hdd_err("kstrtou8 failed range [%d - %d]",
3405 CFG_ROAM_RSSI_DIFF_MIN,
3406 CFG_ROAM_RSSI_DIFF_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003407 ret = -EINVAL;
3408 goto exit;
3409 }
3410
3411 if ((roamRssiDiff < CFG_ROAM_RSSI_DIFF_MIN) ||
3412 (roamRssiDiff > CFG_ROAM_RSSI_DIFF_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003413 hdd_err("Roam rssi diff value %d is out of range (Min: %d Max: %d)",
3414 roamRssiDiff,
3415 CFG_ROAM_RSSI_DIFF_MIN,
3416 CFG_ROAM_RSSI_DIFF_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003417 ret = -EINVAL;
3418 goto exit;
3419 }
3420
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003421 hdd_info("Received Command to Set roam rssi diff = %d",
3422 roamRssiDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003423
3424 hdd_ctx->config->RoamRssiDiff = roamRssiDiff;
3425 sme_update_roam_rssi_diff(hdd_ctx->hHal,
3426 adapter->sessionId,
3427 roamRssiDiff);
3428
3429exit:
3430 return ret;
3431}
3432
3433static int drv_cmd_get_roam_delta(hdd_adapter_t *adapter,
3434 hdd_context_t *hdd_ctx,
3435 uint8_t *command,
3436 uint8_t command_len,
3437 hdd_priv_data_t *priv_data)
3438{
3439 int ret = 0;
3440 uint8_t roamRssiDiff =
3441 sme_get_roam_rssi_diff(hdd_ctx->hHal);
3442 char extra[32];
3443 uint8_t len = 0;
3444
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303445 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003446 TRACE_CODE_HDD_GETROAMDELTA_IOCTL,
3447 adapter->sessionId, roamRssiDiff));
3448
3449 len = scnprintf(extra, sizeof(extra), "%s %d",
3450 command, roamRssiDiff);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303451 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003452
3453 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003454 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003455 ret = -EFAULT;
3456 }
3457
3458 return ret;
3459}
3460
3461static int drv_cmd_get_band(hdd_adapter_t *adapter,
3462 hdd_context_t *hdd_ctx,
3463 uint8_t *command,
3464 uint8_t command_len,
3465 hdd_priv_data_t *priv_data)
3466{
3467 int ret = 0;
3468 int band = -1;
3469 char extra[32];
3470 uint8_t len = 0;
3471
3472 hdd_get_band_helper(hdd_ctx, &band);
3473
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303474 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003475 TRACE_CODE_HDD_GETBAND_IOCTL,
3476 adapter->sessionId, band));
3477
3478 len = scnprintf(extra, sizeof(extra), "%s %d", command, band);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303479 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003480
3481 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003482 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003483 ret = -EFAULT;
3484 }
3485
3486 return ret;
3487}
3488
3489static int drv_cmd_set_roam_scan_channels(hdd_adapter_t *adapter,
3490 hdd_context_t *hdd_ctx,
3491 uint8_t *command,
3492 uint8_t command_len,
3493 hdd_priv_data_t *priv_data)
3494{
3495 return hdd_parse_set_roam_scan_channels(adapter, command);
3496}
3497
3498static int drv_cmd_get_roam_scan_channels(hdd_adapter_t *adapter,
3499 hdd_context_t *hdd_ctx,
3500 uint8_t *command,
3501 uint8_t command_len,
3502 hdd_priv_data_t *priv_data)
3503{
3504 int ret = 0;
3505 uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
3506 uint8_t numChannels = 0;
3507 uint8_t j = 0;
3508 char extra[128] = { 0 };
3509 int len;
3510
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303511 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003512 sme_get_roam_scan_channel_list(hdd_ctx->hHal,
3513 ChannelList,
3514 &numChannels,
3515 adapter->sessionId)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003516 hdd_alert("failed to get roam scan channel list");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003517 ret = -EFAULT;
3518 goto exit;
3519 }
3520
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303521 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003522 TRACE_CODE_HDD_GETROAMSCANCHANNELS_IOCTL,
3523 adapter->sessionId, numChannels));
3524 /*
3525 * output channel list is of the format
3526 * [Number of roam scan channels][Channel1][Channel2]...
3527 * copy the number of channels in the 0th index
3528 */
3529 len = scnprintf(extra, sizeof(extra), "%s %d", command,
3530 numChannels);
Selvaraj, Sridhar5cc4af42016-10-19 10:41:59 +05303531 for (j = 0; (j < numChannels) && len <= sizeof(extra); j++)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003532 len += scnprintf(extra + len, sizeof(extra) - len,
3533 " %d", ChannelList[j]);
3534
Anurag Chouhan6d760662016-02-20 16:05:43 +05303535 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003536 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003537 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003538 ret = -EFAULT;
3539 goto exit;
3540 }
3541
3542exit:
3543 return ret;
3544}
3545
3546static int drv_cmd_get_ccx_mode(hdd_adapter_t *adapter,
3547 hdd_context_t *hdd_ctx,
3548 uint8_t *command,
3549 uint8_t command_len,
3550 hdd_priv_data_t *priv_data)
3551{
3552 int ret = 0;
3553 bool eseMode = sme_get_is_ese_feature_enabled(hdd_ctx->hHal);
3554 char extra[32];
3555 uint8_t len = 0;
3556
3557 /*
3558 * Check if the features OKC/ESE/11R are supported simultaneously,
3559 * then this operation is not permitted (return FAILURE)
3560 */
3561 if (eseMode &&
3562 hdd_is_okc_mode_enabled(hdd_ctx) &&
3563 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003564 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003565 ret = -EPERM;
3566 goto exit;
3567 }
3568
3569 len = scnprintf(extra, sizeof(extra), "%s %d",
3570 "GETCCXMODE", eseMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303571 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003572 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003573 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003574 ret = -EFAULT;
3575 goto exit;
3576 }
3577
3578exit:
3579 return ret;
3580}
3581
3582static int drv_cmd_get_okc_mode(hdd_adapter_t *adapter,
3583 hdd_context_t *hdd_ctx,
3584 uint8_t *command,
3585 uint8_t command_len,
3586 hdd_priv_data_t *priv_data)
3587{
3588 int ret = 0;
3589 bool okcMode = hdd_is_okc_mode_enabled(hdd_ctx);
3590 char extra[32];
3591 uint8_t len = 0;
3592
3593 /*
3594 * Check if the features OKC/ESE/11R are supported simultaneously,
3595 * then this operation is not permitted (return FAILURE)
3596 */
3597 if (okcMode &&
3598 sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
3599 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003600 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003601 ret = -EPERM;
3602 goto exit;
3603 }
3604
3605 len = scnprintf(extra, sizeof(extra), "%s %d",
3606 "GETOKCMODE", okcMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303607 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003608
3609 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003610 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003611 ret = -EFAULT;
3612 goto exit;
3613 }
3614
3615exit:
3616 return ret;
3617}
3618
3619static int drv_cmd_get_fast_roam(hdd_adapter_t *adapter,
3620 hdd_context_t *hdd_ctx,
3621 uint8_t *command,
3622 uint8_t command_len,
3623 hdd_priv_data_t *priv_data)
3624{
3625 int ret = 0;
3626 bool lfrMode = sme_get_is_lfr_feature_enabled(hdd_ctx->hHal);
3627 char extra[32];
3628 uint8_t len = 0;
3629
3630 len = scnprintf(extra, sizeof(extra), "%s %d",
3631 "GETFASTROAM", lfrMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303632 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003633
3634 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003635 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003636 ret = -EFAULT;
3637 }
3638
3639 return ret;
3640}
3641
3642static int drv_cmd_get_fast_transition(hdd_adapter_t *adapter,
3643 hdd_context_t *hdd_ctx,
3644 uint8_t *command,
3645 uint8_t command_len,
3646 hdd_priv_data_t *priv_data)
3647{
3648 int ret = 0;
3649 bool ft = sme_get_is_ft_feature_enabled(hdd_ctx->hHal);
3650 char extra[32];
3651 uint8_t len = 0;
3652
3653 len = scnprintf(extra, sizeof(extra), "%s %d",
3654 "GETFASTTRANSITION", ft);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303655 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003656
3657 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003658 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003659 ret = -EFAULT;
3660 }
3661
3662 return ret;
3663}
3664
3665static int drv_cmd_set_roam_scan_channel_min_time(hdd_adapter_t *adapter,
3666 hdd_context_t *hdd_ctx,
3667 uint8_t *command,
3668 uint8_t command_len,
3669 hdd_priv_data_t *priv_data)
3670{
3671 int ret = 0;
3672 uint8_t *value = command;
3673 uint8_t minTime = CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_DEFAULT;
3674
3675 /* Move pointer to ahead of SETROAMSCANCHANNELMINTIME<delimiter> */
3676 value = value + command_len + 1;
3677
3678 /* Convert the value from ascii to integer */
3679 ret = kstrtou8(value, 10, &minTime);
3680 if (ret < 0) {
3681 /*
3682 * If the input value is greater than max value of datatype,
3683 * then also kstrtou8 fails
3684 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003685 hdd_err("kstrtou8 failed range [%d - %d]",
3686 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN,
3687 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003688 ret = -EINVAL;
3689 goto exit;
3690 }
3691
3692 if ((minTime < CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN) ||
3693 (minTime > CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003694 hdd_err("scan min channel time value %d is out of range (Min: %d Max: %d)",
3695 minTime,
3696 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN,
3697 CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003698 ret = -EINVAL;
3699 goto exit;
3700 }
3701
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303702 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003703 TRACE_CODE_HDD_SETROAMSCANCHANNELMINTIME_IOCTL,
3704 adapter->sessionId, minTime));
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003705 hdd_info("Received Command to change channel min time = %d",
3706 minTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003707
3708 hdd_ctx->config->nNeighborScanMinChanTime = minTime;
3709 sme_set_neighbor_scan_min_chan_time(hdd_ctx->hHal,
3710 minTime,
3711 adapter->sessionId);
3712
3713exit:
3714 return ret;
3715}
3716
3717static int drv_cmd_send_action_frame(hdd_adapter_t *adapter,
3718 hdd_context_t *hdd_ctx,
3719 uint8_t *command,
3720 uint8_t command_len,
3721 hdd_priv_data_t *priv_data)
3722{
Srinivas Girigowda1efc80e2016-08-26 18:53:47 -07003723 return hdd_parse_sendactionframe(adapter, command,
3724 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003725}
3726
3727static int drv_cmd_get_roam_scan_channel_min_time(hdd_adapter_t *adapter,
3728 hdd_context_t *hdd_ctx,
3729 uint8_t *command,
3730 uint8_t command_len,
3731 hdd_priv_data_t *priv_data)
3732{
3733 int ret = 0;
3734 uint16_t val = sme_get_neighbor_scan_min_chan_time(hdd_ctx->hHal,
3735 adapter->sessionId);
3736 char extra[32];
3737 uint8_t len = 0;
3738
3739 /* value is interms of msec */
3740 len = scnprintf(extra, sizeof(extra), "%s %d",
3741 "GETROAMSCANCHANNELMINTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303742 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003743
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303744 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003745 TRACE_CODE_HDD_GETROAMSCANCHANNELMINTIME_IOCTL,
3746 adapter->sessionId, val));
3747
3748 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003749 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003750 ret = -EFAULT;
3751 }
3752
3753 return ret;
3754}
3755
3756static int drv_cmd_set_scan_channel_time(hdd_adapter_t *adapter,
3757 hdd_context_t *hdd_ctx,
3758 uint8_t *command,
3759 uint8_t command_len,
3760 hdd_priv_data_t *priv_data)
3761{
3762 int ret = 0;
3763 uint8_t *value = command;
3764 uint16_t maxTime = CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_DEFAULT;
3765
3766 /* Move pointer to ahead of SETSCANCHANNELTIME<delimiter> */
3767 value = value + command_len + 1;
3768
3769 /* Convert the value from ascii to integer */
3770 ret = kstrtou16(value, 10, &maxTime);
3771 if (ret < 0) {
3772 /*
3773 * If the input value is greater than max value of datatype,
3774 * then also kstrtou8 fails
3775 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003776 hdd_err("kstrtou16 failed range [%d - %d]",
3777 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN,
3778 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003779 ret = -EINVAL;
3780 goto exit;
3781 }
3782
3783 if ((maxTime < CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN) ||
3784 (maxTime > CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003785 hdd_err("lfr mode value %d is out of range (Min: %d Max: %d)",
3786 maxTime,
3787 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN,
3788 CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003789 ret = -EINVAL;
3790 goto exit;
3791 }
3792
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003793 hdd_info("Received Command to change channel max time = %d",
3794 maxTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003795
3796 hdd_ctx->config->nNeighborScanMaxChanTime = maxTime;
3797 sme_set_neighbor_scan_max_chan_time(hdd_ctx->hHal,
3798 adapter->sessionId,
3799 maxTime);
3800
3801exit:
3802 return ret;
3803}
3804
3805static int drv_cmd_get_scan_channel_time(hdd_adapter_t *adapter,
3806 hdd_context_t *hdd_ctx,
3807 uint8_t *command,
3808 uint8_t command_len,
3809 hdd_priv_data_t *priv_data)
3810{
3811 int ret = 0;
3812 uint16_t val = sme_get_neighbor_scan_max_chan_time(hdd_ctx->hHal,
3813 adapter->sessionId);
3814 char extra[32];
3815 uint8_t len = 0;
3816
3817 /* value is interms of msec */
3818 len = scnprintf(extra, sizeof(extra), "%s %d",
3819 "GETSCANCHANNELTIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303820 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003821
3822 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003823 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003824 ret = -EFAULT;
3825 }
3826
3827 return ret;
3828}
3829
3830static int drv_cmd_set_scan_home_time(hdd_adapter_t *adapter,
3831 hdd_context_t *hdd_ctx,
3832 uint8_t *command,
3833 uint8_t command_len,
3834 hdd_priv_data_t *priv_data)
3835{
3836 int ret = 0;
3837 uint8_t *value = command;
3838 uint16_t val = CFG_NEIGHBOR_SCAN_TIMER_PERIOD_DEFAULT;
3839
3840 /* Move pointer to ahead of SETSCANHOMETIME<delimiter> */
3841 value = value + command_len + 1;
3842
3843 /* Convert the value from ascii to integer */
3844 ret = kstrtou16(value, 10, &val);
3845 if (ret < 0) {
3846 /*
3847 * If the input value is greater than max value of datatype,
3848 * then also kstrtou8 fails
3849 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003850 hdd_err("kstrtou16 failed range [%d - %d]",
3851 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN,
3852 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003853 ret = -EINVAL;
3854 goto exit;
3855 }
3856
3857 if ((val < CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN) ||
3858 (val > CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003859 hdd_err("scan home time value %d is out of range (Min: %d Max: %d)",
3860 val,
3861 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN,
3862 CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003863 ret = -EINVAL;
3864 goto exit;
3865 }
3866
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003867 hdd_info("Received Command to change scan home time = %d",
3868 val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003869
3870 hdd_ctx->config->nNeighborScanPeriod = val;
3871 sme_set_neighbor_scan_period(hdd_ctx->hHal,
3872 adapter->sessionId, val);
3873
3874exit:
3875 return ret;
3876}
3877
3878static int drv_cmd_get_scan_home_time(hdd_adapter_t *adapter,
3879 hdd_context_t *hdd_ctx,
3880 uint8_t *command,
3881 uint8_t command_len,
3882 hdd_priv_data_t *priv_data)
3883{
3884 int ret = 0;
3885 uint16_t val = sme_get_neighbor_scan_period(hdd_ctx->hHal,
3886 adapter->
3887 sessionId);
3888 char extra[32];
3889 uint8_t len = 0;
3890
3891 /* value is interms of msec */
3892 len = scnprintf(extra, sizeof(extra), "%s %d",
3893 "GETSCANHOMETIME", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303894 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003895
3896 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003897 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003898 ret = -EFAULT;
3899 }
3900
3901 return ret;
3902}
3903
3904static int drv_cmd_set_roam_intra_band(hdd_adapter_t *adapter,
3905 hdd_context_t *hdd_ctx,
3906 uint8_t *command,
3907 uint8_t command_len,
3908 hdd_priv_data_t *priv_data)
3909{
3910 int ret = 0;
3911 uint8_t *value = command;
3912 uint8_t val = CFG_ROAM_INTRA_BAND_DEFAULT;
3913
3914 /* Move pointer to ahead of SETROAMINTRABAND<delimiter> */
3915 value = value + command_len + 1;
3916
3917 /* Convert the value from ascii to integer */
3918 ret = kstrtou8(value, 10, &val);
3919 if (ret < 0) {
3920 /*
3921 * If the input value is greater than max value of datatype,
3922 * then also kstrtou8 fails
3923 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003924 hdd_err("kstrtou8 failed range [%d - %d]",
3925 CFG_ROAM_INTRA_BAND_MIN,
3926 CFG_ROAM_INTRA_BAND_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003927 ret = -EINVAL;
3928 goto exit;
3929 }
3930
3931 if ((val < CFG_ROAM_INTRA_BAND_MIN) ||
3932 (val > CFG_ROAM_INTRA_BAND_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003933 hdd_err("intra band mode value %d is out of range (Min: %d Max: %d)",
3934 val,
3935 CFG_ROAM_INTRA_BAND_MIN,
3936 CFG_ROAM_INTRA_BAND_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003937 ret = -EINVAL;
3938 goto exit;
3939 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003940 hdd_info("Received Command to change intra band = %d",
3941 val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003942
3943 hdd_ctx->config->nRoamIntraBand = val;
3944 sme_set_roam_intra_band(hdd_ctx->hHal, val);
3945
3946exit:
3947 return ret;
3948}
3949
3950static int drv_cmd_get_roam_intra_band(hdd_adapter_t *adapter,
3951 hdd_context_t *hdd_ctx,
3952 uint8_t *command,
3953 uint8_t command_len,
3954 hdd_priv_data_t *priv_data)
3955{
3956 int ret = 0;
3957 uint16_t val = sme_get_roam_intra_band(hdd_ctx->hHal);
3958 char extra[32];
3959 uint8_t len = 0;
3960
3961 /* value is interms of msec */
3962 len = scnprintf(extra, sizeof(extra), "%s %d",
3963 "GETROAMINTRABAND", val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05303964 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003965 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003966 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003967 ret = -EFAULT;
3968 }
3969
3970 return ret;
3971}
3972
3973static int drv_cmd_set_scan_n_probes(hdd_adapter_t *adapter,
3974 hdd_context_t *hdd_ctx,
3975 uint8_t *command,
3976 uint8_t command_len,
3977 hdd_priv_data_t *priv_data)
3978{
3979 int ret = 0;
3980 uint8_t *value = command;
3981 uint8_t nProbes = CFG_ROAM_SCAN_N_PROBES_DEFAULT;
3982
3983 /* Move pointer to ahead of SETSCANNPROBES<delimiter> */
3984 value = value + command_len + 1;
3985
3986 /* Convert the value from ascii to integer */
3987 ret = kstrtou8(value, 10, &nProbes);
3988 if (ret < 0) {
3989 /*
3990 * If the input value is greater than max value of datatype,
3991 * then also kstrtou8 fails
3992 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07003993 hdd_err("kstrtou8 failed range [%d - %d]",
3994 CFG_ROAM_SCAN_N_PROBES_MIN,
3995 CFG_ROAM_SCAN_N_PROBES_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003996 ret = -EINVAL;
3997 goto exit;
3998 }
3999
4000 if ((nProbes < CFG_ROAM_SCAN_N_PROBES_MIN) ||
4001 (nProbes > CFG_ROAM_SCAN_N_PROBES_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004002 hdd_err("NProbes value %d is out of range (Min: %d Max: %d)",
4003 nProbes,
4004 CFG_ROAM_SCAN_N_PROBES_MIN,
4005 CFG_ROAM_SCAN_N_PROBES_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004006 ret = -EINVAL;
4007 goto exit;
4008 }
4009
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004010 hdd_info("Received Command to Set nProbes = %d",
4011 nProbes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004012
4013 hdd_ctx->config->nProbes = nProbes;
4014 sme_update_roam_scan_n_probes(hdd_ctx->hHal,
4015 adapter->sessionId, nProbes);
4016
4017exit:
4018 return ret;
4019}
4020
4021static int drv_cmd_get_scan_n_probes(hdd_adapter_t *adapter,
4022 hdd_context_t *hdd_ctx,
4023 uint8_t *command,
4024 uint8_t command_len,
4025 hdd_priv_data_t *priv_data)
4026{
4027 int ret = 0;
4028 uint8_t val = sme_get_roam_scan_n_probes(hdd_ctx->hHal);
4029 char extra[32];
4030 uint8_t len = 0;
4031
4032 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304033 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004034 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004035 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004036 ret = -EFAULT;
4037 }
4038
4039 return ret;
4040}
4041
4042static int drv_cmd_set_scan_home_away_time(hdd_adapter_t *adapter,
4043 hdd_context_t *hdd_ctx,
4044 uint8_t *command,
4045 uint8_t command_len,
4046 hdd_priv_data_t *priv_data)
4047{
4048 int ret = 0;
4049 uint8_t *value = command;
4050 uint16_t homeAwayTime = CFG_ROAM_SCAN_HOME_AWAY_TIME_DEFAULT;
4051
4052 /* input value is in units of msec */
4053
4054 /* Move pointer to ahead of SETSCANHOMEAWAYTIME<delimiter> */
4055 value = value + command_len + 1;
4056
4057 /* Convert the value from ascii to integer */
4058 ret = kstrtou16(value, 10, &homeAwayTime);
4059 if (ret < 0) {
4060 /*
4061 * If the input value is greater than max value of datatype,
4062 * then also kstrtou8 fails
4063 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004064 hdd_err("kstrtou8 failed range [%d - %d]",
4065 CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN,
4066 CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004067 ret = -EINVAL;
4068 goto exit;
4069 }
4070
4071 if ((homeAwayTime < CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN) ||
4072 (homeAwayTime > CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004073 hdd_err("homeAwayTime value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004074 homeAwayTime,
4075 CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN,
4076 CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX);
4077 ret = -EINVAL;
4078 goto exit;
4079 }
4080
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004081 hdd_info("Received Command to Set scan away time = %d",
4082 homeAwayTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004083
4084 if (hdd_ctx->config->nRoamScanHomeAwayTime !=
4085 homeAwayTime) {
4086 hdd_ctx->config->nRoamScanHomeAwayTime = homeAwayTime;
4087 sme_update_roam_scan_home_away_time(hdd_ctx->hHal,
4088 adapter->sessionId,
4089 homeAwayTime,
4090 true);
4091 }
4092
4093exit:
4094 return ret;
4095}
4096
4097static int drv_cmd_get_scan_home_away_time(hdd_adapter_t *adapter,
4098 hdd_context_t *hdd_ctx,
4099 uint8_t *command,
4100 uint8_t command_len,
4101 hdd_priv_data_t *priv_data)
4102{
4103 int ret = 0;
4104 uint16_t val = sme_get_roam_scan_home_away_time(hdd_ctx->hHal);
4105 char extra[32];
4106 uint8_t len = 0;
4107
4108 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304109 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004110
4111 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004112 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004113 ret = -EFAULT;
4114 }
4115
4116 return ret;
4117}
4118
4119static int drv_cmd_reassoc(hdd_adapter_t *adapter,
4120 hdd_context_t *hdd_ctx,
4121 uint8_t *command,
4122 uint8_t command_len,
4123 hdd_priv_data_t *priv_data)
4124{
4125 return hdd_parse_reassoc(adapter, command);
4126}
4127
4128static int drv_cmd_set_wes_mode(hdd_adapter_t *adapter,
4129 hdd_context_t *hdd_ctx,
4130 uint8_t *command,
4131 uint8_t command_len,
4132 hdd_priv_data_t *priv_data)
4133{
4134 int ret = 0;
4135 uint8_t *value = command;
4136 uint8_t wesMode = CFG_ENABLE_WES_MODE_NAME_DEFAULT;
4137
4138 /* Move pointer to ahead of SETWESMODE<delimiter> */
4139 value = value + command_len + 1;
4140
4141 /* Convert the value from ascii to integer */
4142 ret = kstrtou8(value, 10, &wesMode);
4143 if (ret < 0) {
4144 /*
4145 * If the input value is greater than max value of datatype,
4146 * then also kstrtou8 fails
4147 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004148 hdd_err("kstrtou8 failed range [%d - %d]",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004149 CFG_ENABLE_WES_MODE_NAME_MIN,
4150 CFG_ENABLE_WES_MODE_NAME_MAX);
4151 ret = -EINVAL;
4152 goto exit;
4153 }
4154
4155 if ((wesMode < CFG_ENABLE_WES_MODE_NAME_MIN) ||
4156 (wesMode > CFG_ENABLE_WES_MODE_NAME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004157 hdd_err("WES Mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004158 wesMode,
4159 CFG_ENABLE_WES_MODE_NAME_MIN,
4160 CFG_ENABLE_WES_MODE_NAME_MAX);
4161 ret = -EINVAL;
4162 goto exit;
4163 }
4164
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004165 hdd_info("Received Command to Set WES Mode rssi diff = %d",
4166 wesMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004167
4168 hdd_ctx->config->isWESModeEnabled = wesMode;
4169 sme_update_wes_mode(hdd_ctx->hHal, wesMode, adapter->sessionId);
4170
4171exit:
4172 return ret;
4173}
4174
4175static int drv_cmd_get_wes_mode(hdd_adapter_t *adapter,
4176 hdd_context_t *hdd_ctx,
4177 uint8_t *command,
4178 uint8_t command_len,
4179 hdd_priv_data_t *priv_data)
4180{
4181 int ret = 0;
4182 bool wesMode = sme_get_wes_mode(hdd_ctx->hHal);
4183 char extra[32];
4184 uint8_t len = 0;
4185
4186 len = scnprintf(extra, sizeof(extra), "%s %d", command, wesMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304187 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004188 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004189 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004190 ret = -EFAULT;
4191 }
4192
4193 return ret;
4194}
4195
4196static int drv_cmd_set_opportunistic_rssi_diff(hdd_adapter_t *adapter,
4197 hdd_context_t *hdd_ctx,
4198 uint8_t *command,
4199 uint8_t command_len,
4200 hdd_priv_data_t *priv_data)
4201{
4202 int ret = 0;
4203 uint8_t *value = command;
4204 uint8_t nOpportunisticThresholdDiff =
4205 CFG_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF_DEFAULT;
4206
4207 /* Move pointer to ahead of SETOPPORTUNISTICRSSIDIFF<delimiter> */
4208 value = value + command_len + 1;
4209
4210 /* Convert the value from ascii to integer */
4211 ret = kstrtou8(value, 10, &nOpportunisticThresholdDiff);
4212 if (ret < 0) {
4213 /*
4214 * If the input value is greater than max value of datatype,
4215 * then also kstrtou8 fails
4216 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004217 hdd_err("kstrtou8 failed.");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004218 ret = -EINVAL;
4219 goto exit;
4220 }
4221
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004222 hdd_info("Received Command to Set Opportunistic Threshold diff = %d",
4223 nOpportunisticThresholdDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004224
4225 sme_set_roam_opportunistic_scan_threshold_diff(hdd_ctx->hHal,
4226 adapter->sessionId,
4227 nOpportunisticThresholdDiff);
4228
4229exit:
4230 return ret;
4231}
4232
4233static int drv_cmd_get_opportunistic_rssi_diff(hdd_adapter_t *adapter,
4234 hdd_context_t *hdd_ctx,
4235 uint8_t *command,
4236 uint8_t command_len,
4237 hdd_priv_data_t *priv_data)
4238{
4239 int ret = 0;
4240 int8_t val = sme_get_roam_opportunistic_scan_threshold_diff(
4241 hdd_ctx->hHal);
4242 char extra[32];
4243 uint8_t len = 0;
4244
4245 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304246 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004247 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004248 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004249 ret = -EFAULT;
4250 }
4251
4252 return ret;
4253}
4254
4255static int drv_cmd_set_roam_rescan_rssi_diff(hdd_adapter_t *adapter,
4256 hdd_context_t *hdd_ctx,
4257 uint8_t *command,
4258 uint8_t command_len,
4259 hdd_priv_data_t *priv_data)
4260{
4261 int ret = 0;
4262 uint8_t *value = command;
4263 uint8_t nRoamRescanRssiDiff = CFG_ROAM_RESCAN_RSSI_DIFF_DEFAULT;
4264
4265 /* Move pointer to ahead of SETROAMRESCANRSSIDIFF<delimiter> */
4266 value = value + command_len + 1;
4267
4268 /* Convert the value from ascii to integer */
4269 ret = kstrtou8(value, 10, &nRoamRescanRssiDiff);
4270 if (ret < 0) {
4271 /*
4272 * If the input value is greater than max value of datatype,
4273 * then also kstrtou8 fails
4274 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004275 hdd_err("kstrtou8 failed.");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004276 ret = -EINVAL;
4277 goto exit;
4278 }
4279
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004280 hdd_info("Received Command to Set Roam Rescan RSSI Diff = %d",
4281 nRoamRescanRssiDiff);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004282
4283 sme_set_roam_rescan_rssi_diff(hdd_ctx->hHal,
4284 adapter->sessionId,
4285 nRoamRescanRssiDiff);
4286
4287exit:
4288 return ret;
4289}
4290
4291static int drv_cmd_get_roam_rescan_rssi_diff(hdd_adapter_t *adapter,
4292 hdd_context_t *hdd_ctx,
4293 uint8_t *command,
4294 uint8_t command_len,
4295 hdd_priv_data_t *priv_data)
4296{
4297 int ret = 0;
4298 uint8_t val = sme_get_roam_rescan_rssi_diff(hdd_ctx->hHal);
4299 char extra[32];
4300 uint8_t len = 0;
4301
4302 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304303 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004304 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004305 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004306 ret = -EFAULT;
4307 }
4308
4309 return ret;
4310}
4311
4312static int drv_cmd_set_fast_roam(hdd_adapter_t *adapter,
4313 hdd_context_t *hdd_ctx,
4314 uint8_t *command,
4315 uint8_t command_len,
4316 hdd_priv_data_t *priv_data)
4317{
4318 int ret = 0;
4319 uint8_t *value = command;
4320 uint8_t lfrMode = CFG_LFR_FEATURE_ENABLED_DEFAULT;
4321
4322 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4323 value = value + command_len + 1;
4324
4325 /* Convert the value from ascii to integer */
4326 ret = kstrtou8(value, 10, &lfrMode);
4327 if (ret < 0) {
4328 /*
4329 * If the input value is greater than max value of datatype,
4330 * then also kstrtou8 fails
4331 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004332 hdd_err("kstrtou8 failed range [%d - %d]",
4333 CFG_LFR_FEATURE_ENABLED_MIN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004334 CFG_LFR_FEATURE_ENABLED_MAX);
4335 ret = -EINVAL;
4336 goto exit;
4337 }
4338
4339 if ((lfrMode < CFG_LFR_FEATURE_ENABLED_MIN) ||
4340 (lfrMode > CFG_LFR_FEATURE_ENABLED_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004341 hdd_err("lfr mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004342 lfrMode,
4343 CFG_LFR_FEATURE_ENABLED_MIN,
4344 CFG_LFR_FEATURE_ENABLED_MAX);
4345 ret = -EINVAL;
4346 goto exit;
4347 }
4348
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004349 hdd_info("Received Command to change lfr mode = %d",
4350 lfrMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004351
4352 hdd_ctx->config->isFastRoamIniFeatureEnabled = lfrMode;
4353 sme_update_is_fast_roam_ini_feature_enabled(hdd_ctx->hHal,
4354 adapter->
4355 sessionId,
4356 lfrMode);
4357
4358exit:
4359 return ret;
4360}
4361
4362static int drv_cmd_set_fast_transition(hdd_adapter_t *adapter,
4363 hdd_context_t *hdd_ctx,
4364 uint8_t *command,
4365 uint8_t command_len,
4366 hdd_priv_data_t *priv_data)
4367{
4368 int ret = 0;
4369 uint8_t *value = command;
4370 uint8_t ft = CFG_FAST_TRANSITION_ENABLED_NAME_DEFAULT;
4371
4372 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4373 value = value + command_len + 1;
4374
4375 /* Convert the value from ascii to integer */
4376 ret = kstrtou8(value, 10, &ft);
4377 if (ret < 0) {
4378 /*
4379 * If the input value is greater than max value of datatype,
4380 * then also kstrtou8 fails
4381 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004382 hdd_err("kstrtou8 failed range [%d - %d]",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004383 CFG_FAST_TRANSITION_ENABLED_NAME_MIN,
4384 CFG_FAST_TRANSITION_ENABLED_NAME_MAX);
4385 ret = -EINVAL;
4386 goto exit;
4387 }
4388
4389 if ((ft < CFG_FAST_TRANSITION_ENABLED_NAME_MIN) ||
4390 (ft > CFG_FAST_TRANSITION_ENABLED_NAME_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004391 hdd_err("ft mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004392 ft,
4393 CFG_FAST_TRANSITION_ENABLED_NAME_MIN,
4394 CFG_FAST_TRANSITION_ENABLED_NAME_MAX);
4395 ret = -EINVAL;
4396 goto exit;
4397 }
4398
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004399 hdd_info("Received Command to change ft mode = %d", ft);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004400
4401 hdd_ctx->config->isFastTransitionEnabled = ft;
4402 sme_update_fast_transition_enabled(hdd_ctx->hHal, ft);
4403
4404exit:
4405 return ret;
4406}
4407
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004408static int drv_cmd_fast_reassoc(hdd_adapter_t *adapter,
4409 hdd_context_t *hdd_ctx,
4410 uint8_t *command,
4411 uint8_t command_len,
4412 hdd_priv_data_t *priv_data)
4413{
4414 int ret = 0;
4415 uint8_t *value = command;
4416 uint8_t channel = 0;
4417 tSirMacAddr targetApBssid;
4418 uint32_t roamId = 0;
4419 tCsrRoamModifyProfileFields modProfileFields;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004420 tCsrHandoffRequest handoffInfo;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004421 hdd_station_ctx_t *pHddStaCtx;
4422
Krunal Sonibe766b02016-03-10 13:00:44 -08004423 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004424 hdd_warn("Unsupported in mode %s(%d)",
4425 hdd_device_mode_to_string(adapter->device_mode),
4426 adapter->device_mode);
4427 return -EINVAL;
4428 }
4429
4430 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
4431
4432 /* if not associated, no need to proceed with reassoc */
4433 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004434 hdd_info("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004435 ret = -EINVAL;
4436 goto exit;
4437 }
4438
4439 ret = hdd_parse_reassoc_command_v1_data(value, targetApBssid,
4440 &channel);
4441 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004442 hdd_err("Failed to parse reassoc command data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004443 goto exit;
4444 }
4445
4446 /*
4447 * if the target bssid is same as currently associated AP,
4448 * issue reassoc to same AP
4449 */
Ankit Guptaa5076012016-09-14 11:32:19 -07004450 if (!qdf_mem_cmp(targetApBssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004451 pHddStaCtx->conn_info.bssId.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +05304452 QDF_MAC_ADDR_SIZE)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004453 hdd_info("Reassoc BSSID is same as currently associated AP bssid");
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304454 if (roaming_offload_enabled(hdd_ctx)) {
4455 hdd_wma_send_fastreassoc_cmd((int)adapter->sessionId,
Padma, Santhosh Kumaraf9f08c2016-10-21 21:26:29 +05304456 targetApBssid,
4457 pHddStaCtx->conn_info.operationChannel);
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304458 } else {
4459 sme_get_modify_profile_fields(hdd_ctx->hHal,
4460 adapter->sessionId,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004461 &modProfileFields);
Deepak Dhamdhere5fda0e42016-06-24 18:30:02 +05304462 sme_roam_reassoc(hdd_ctx->hHal, adapter->sessionId,
4463 NULL, modProfileFields, &roamId, 1);
4464 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004465 return 0;
4466 }
4467
Padma, Santhosh Kumaraf9f08c2016-10-21 21:26:29 +05304468 /* Check channel number is a valid channel number */
4469 if (QDF_STATUS_SUCCESS !=
4470 wlan_hdd_validate_operation_channel(adapter, channel)) {
4471 hdd_err("Invalid Channel [%d]", channel);
4472 return -EINVAL;
4473 }
4474
Varun Reddy Yeturud351a6c2016-03-16 14:01:00 -07004475 if (roaming_offload_enabled(hdd_ctx)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004476 hdd_wma_send_fastreassoc_cmd((int)adapter->sessionId,
4477 targetApBssid, (int)channel);
4478 goto exit;
4479 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004480 /* Proceed with reassoc */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004481 handoffInfo.channel = channel;
4482 handoffInfo.src = FASTREASSOC;
Varun Reddy Yeturua66f9c52016-02-17 09:58:40 -08004483 qdf_mem_copy(handoffInfo.bssid.bytes, targetApBssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004484 sizeof(tSirMacAddr));
4485 sme_handoff_request(hdd_ctx->hHal, adapter->sessionId,
4486 &handoffInfo);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004487exit:
4488 return ret;
4489}
4490
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004491static int drv_cmd_set_roam_scan_control(hdd_adapter_t *adapter,
4492 hdd_context_t *hdd_ctx,
4493 uint8_t *command,
4494 uint8_t command_len,
4495 hdd_priv_data_t *priv_data)
4496{
4497 int ret = 0;
4498 uint8_t *value = command;
4499 uint8_t roamScanControl = 0;
4500
4501 /* Move pointer to ahead of SETROAMSCANCONTROL<delimiter> */
4502 value = value + command_len + 1;
4503
4504 /* Convert the value from ascii to integer */
4505 ret = kstrtou8(value, 10, &roamScanControl);
4506 if (ret < 0) {
4507 /*
4508 * If the input value is greater than max value of datatype,
4509 * then also kstrtou8 fails
4510 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004511 hdd_err("kstrtou8 failed ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004512 ret = -EINVAL;
4513 goto exit;
4514 }
4515
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004516 hdd_info("Received Command to Set roam scan control = %d",
4517 roamScanControl);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004518
4519 if (0 != roamScanControl) {
4520 ret = 0; /* return success but ignore param value "true" */
4521 goto exit;
4522 }
4523
4524 sme_set_roam_scan_control(hdd_ctx->hHal,
4525 adapter->sessionId,
4526 roamScanControl);
4527
4528exit:
4529 return ret;
4530}
4531
4532static int drv_cmd_set_okc_mode(hdd_adapter_t *adapter,
4533 hdd_context_t *hdd_ctx,
4534 uint8_t *command,
4535 uint8_t command_len,
4536 hdd_priv_data_t *priv_data)
4537{
4538 int ret = 0;
4539 uint8_t *value = command;
4540 uint8_t okcMode = CFG_OKC_FEATURE_ENABLED_DEFAULT;
4541
4542 /*
4543 * Check if the features OKC/ESE/11R are supported simultaneously,
4544 * then this operation is not permitted (return FAILURE)
4545 */
4546 if (sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
4547 hdd_is_okc_mode_enabled(hdd_ctx) &&
4548 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004549 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004550 ret = -EPERM;
4551 goto exit;
4552 }
4553
4554 /* Move pointer to ahead of SETOKCMODE<delimiter> */
4555 value = value + command_len + 1;
4556
4557 /* Convert the value from ascii to integer */
4558 ret = kstrtou8(value, 10, &okcMode);
4559 if (ret < 0) {
4560 /*
4561 * If the input value is greater than max value of datatype,
4562 * then also kstrtou8 fails
4563 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004564 hdd_err("kstrtou8 failed range [%d - %d]",
4565 CFG_OKC_FEATURE_ENABLED_MIN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004566 CFG_OKC_FEATURE_ENABLED_MAX);
4567 ret = -EINVAL;
4568 goto exit;
4569 }
4570
4571 if ((okcMode < CFG_OKC_FEATURE_ENABLED_MIN) ||
4572 (okcMode > CFG_OKC_FEATURE_ENABLED_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004573 hdd_err("Okc mode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004574 okcMode,
4575 CFG_OKC_FEATURE_ENABLED_MIN,
4576 CFG_OKC_FEATURE_ENABLED_MAX);
4577 ret = -EINVAL;
4578 goto exit;
4579 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004580 hdd_info("Received Command to change okc mode = %d",
4581 okcMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004582
4583 hdd_ctx->config->isOkcIniFeatureEnabled = okcMode;
4584
4585exit:
4586 return ret;
4587}
4588
4589static int drv_cmd_get_roam_scan_control(hdd_adapter_t *adapter,
4590 hdd_context_t *hdd_ctx,
4591 uint8_t *command,
4592 uint8_t command_len,
4593 hdd_priv_data_t *priv_data)
4594{
4595 int ret = 0;
4596 bool roamScanControl = sme_get_roam_scan_control(hdd_ctx->hHal);
4597 char extra[32];
4598 uint8_t len = 0;
4599
4600 len = scnprintf(extra, sizeof(extra), "%s %d",
4601 command, roamScanControl);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304602 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004603 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004604 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004605 ret = -EFAULT;
4606 }
4607
4608 return ret;
4609}
4610
4611static int drv_cmd_bt_coex_mode(hdd_adapter_t *adapter,
4612 hdd_context_t *hdd_ctx,
4613 uint8_t *command,
4614 uint8_t command_len,
4615 hdd_priv_data_t *priv_data)
4616{
4617 int ret = 0;
4618 char *bcMode;
4619
4620 bcMode = command + 11;
4621 if ('1' == *bcMode) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004622 hdd_debug("BTCOEXMODE %d", *bcMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004623 hdd_ctx->btCoexModeSet = true;
4624 ret = wlan_hdd_scan_abort(adapter);
4625 if (ret < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004626 hdd_err("Failed to abort existing scan status: %d",
4627 ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004628 }
4629 } else if ('2' == *bcMode) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004630 hdd_debug("BTCOEXMODE %d", *bcMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004631 hdd_ctx->btCoexModeSet = false;
4632 }
4633
4634 return ret;
4635}
4636
4637static int drv_cmd_scan_active(hdd_adapter_t *adapter,
4638 hdd_context_t *hdd_ctx,
4639 uint8_t *command,
4640 uint8_t command_len,
4641 hdd_priv_data_t *priv_data)
4642{
4643 hdd_ctx->ioctl_scan_mode = eSIR_ACTIVE_SCAN;
4644 return 0;
4645}
4646
4647static int drv_cmd_scan_passive(hdd_adapter_t *adapter,
4648 hdd_context_t *hdd_ctx,
4649 uint8_t *command,
4650 uint8_t command_len,
4651 hdd_priv_data_t *priv_data)
4652{
4653 hdd_ctx->ioctl_scan_mode = eSIR_PASSIVE_SCAN;
4654 return 0;
4655}
4656
4657static int drv_cmd_get_dwell_time(hdd_adapter_t *adapter,
4658 hdd_context_t *hdd_ctx,
4659 uint8_t *command,
4660 uint8_t command_len,
4661 hdd_priv_data_t *priv_data)
4662{
4663 int ret = 0;
4664 struct hdd_config *pCfg =
4665 (WLAN_HDD_GET_CTX(adapter))->config;
4666 char extra[32];
4667 uint8_t len = 0;
4668
4669 memset(extra, 0, sizeof(extra));
4670 ret = hdd_get_dwell_time(pCfg, command, extra, sizeof(extra), &len);
Anurag Chouhan6d760662016-02-20 16:05:43 +05304671 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004672 if (ret != 0 || copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004673 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004674 ret = -EFAULT;
4675 goto exit;
4676 }
4677 ret = len;
4678exit:
4679 return ret;
4680}
4681
4682static int drv_cmd_set_dwell_time(hdd_adapter_t *adapter,
4683 hdd_context_t *hdd_ctx,
4684 uint8_t *command,
4685 uint8_t command_len,
4686 hdd_priv_data_t *priv_data)
4687{
4688 return hdd_set_dwell_time(adapter, command);
4689}
4690
4691static int drv_cmd_miracast(hdd_adapter_t *adapter,
4692 hdd_context_t *hdd_ctx,
4693 uint8_t *command,
4694 uint8_t command_len,
4695 hdd_priv_data_t *priv_data)
4696{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304697 QDF_STATUS ret_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004698 int ret = 0;
4699 tHalHandle hHal;
4700 uint8_t filterType = 0;
4701 hdd_context_t *pHddCtx = NULL;
4702 uint8_t *value;
4703
4704 pHddCtx = WLAN_HDD_GET_CTX(adapter);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05304705 if (wlan_hdd_validate_context(pHddCtx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004706 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004707
4708 hHal = pHddCtx->hHal;
4709 value = command + 9;
4710
4711 /* Convert the value from ascii to integer */
4712 ret = kstrtou8(value, 10, &filterType);
4713 if (ret < 0) {
4714 /*
4715 * If the input value is greater than max value of datatype,
4716 * then also kstrtou8 fails
4717 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004718 hdd_err("kstrtou8 failed range ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004719 ret = -EINVAL;
4720 goto exit;
4721 }
4722 if ((filterType < WLAN_HDD_DRIVER_MIRACAST_CFG_MIN_VAL)
4723 || (filterType >
4724 WLAN_HDD_DRIVER_MIRACAST_CFG_MAX_VAL)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004725 hdd_err("Accepted Values are 0 to 2. 0-Disabled, 1-Source, 2-Sink ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004726 ret = -EINVAL;
4727 goto exit;
4728 }
4729 /* Filtertype value should be either 0-Disabled, 1-Source, 2-sink */
4730 pHddCtx->miracast_value = filterType;
4731
4732 ret_status = sme_set_miracast(hHal, filterType);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304733 if (QDF_STATUS_SUCCESS != ret_status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004734 hdd_err("Failed to set miracast");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004735 return -EBUSY;
4736 }
4737
Tushnim Bhattacharyyaca50b322015-12-28 17:14:36 -08004738 if (cds_is_mcc_in_24G())
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004739 return cds_set_mas(adapter, filterType);
4740
4741exit:
4742 return ret;
4743}
4744
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004745/* Function header is left blank intentionally */
4746static int hdd_parse_set_ibss_oui_data_command(uint8_t *command, uint8_t *ie,
4747 int32_t *oui_length, int32_t limit)
4748{
4749 uint8_t len;
4750 uint8_t data;
4751
4752 while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) {
4753 command++;
4754 limit--;
4755 }
4756
4757 len = 2;
4758
4759 while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) &&
4760 (limit > 1)) {
4761 sscanf(command, "%02x", (unsigned int *)&data);
4762 ie[len++] = data;
4763 command += 2;
4764 limit -= 2;
4765 }
4766
4767 *oui_length = len - 2;
4768
4769 while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) {
4770 command++;
4771 limit--;
4772 }
4773
4774 while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) &&
4775 (limit > 1)) {
4776 sscanf(command, "%02x", (unsigned int *)&data);
4777 ie[len++] = data;
4778 command += 2;
4779 limit -= 2;
4780 }
4781
4782 ie[0] = IE_EID_VENDOR;
4783 ie[1] = len - 2;
4784
4785 return len;
4786}
4787
4788/**
4789 * drv_cmd_set_ibss_beacon_oui_data() - set ibss oui data command
4790 * @adapter: Pointer to adapter
4791 * @hdd_ctx: Pointer to HDD context
4792 * @command: Pointer to command string
4793 * @command_len : Command length
4794 * @priv_data : Pointer to priv data
4795 *
4796 * Return:
4797 * int status code
4798 */
4799static int drv_cmd_set_ibss_beacon_oui_data(hdd_adapter_t *adapter,
4800 hdd_context_t *hdd_ctx,
4801 uint8_t *command,
4802 uint8_t command_len,
4803 hdd_priv_data_t *priv_data)
4804{
4805 int i = 0;
4806 int status;
4807 int ret = 0;
4808 uint8_t *ibss_ie;
4809 int32_t oui_length = 0;
4810 uint32_t ibss_ie_length;
4811 uint8_t *value = command;
4812 tSirModifyIE ibssModifyIE;
4813 tCsrRoamProfile *pRoamProfile;
4814 hdd_wext_state_t *pWextState;
4815
4816
Krunal Sonibe766b02016-03-10 13:00:44 -08004817 if (QDF_IBSS_MODE != adapter->device_mode) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004818 hdd_info("Device_mode %s(%d) not IBSS",
4819 hdd_device_mode_to_string(adapter->device_mode),
4820 adapter->device_mode);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004821 return ret;
4822 }
4823
4824 pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(adapter);
4825
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004826 hdd_info("received command %s", ((char *)value));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004827
4828
4829 /* validate argument of command */
4830 if (strlen(value) <= command_len) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004831 hdd_err("No arguments in command length %zu",
4832 strlen(value));
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004833 ret = -EFAULT;
4834 goto exit;
4835 }
4836
4837 /* moving to arguments of commands */
4838 value = value + command_len;
4839 command_len = strlen(value);
4840
4841 /* oui_data can't be less than 3 bytes */
4842 if (command_len < (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004843 hdd_err("Invalid SETIBSSBEACONOUIDATA command length %d",
4844 command_len);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004845 ret = -EFAULT;
4846 goto exit;
4847 }
4848
4849 ibss_ie = qdf_mem_malloc(command_len);
4850 if (!ibss_ie) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004851 hdd_err("Could not allocate memory for command length %d",
4852 command_len);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004853 ret = -ENOMEM;
4854 goto exit;
4855 }
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004856
4857 ibss_ie_length = hdd_parse_set_ibss_oui_data_command(value, ibss_ie,
4858 &oui_length,
4859 command_len);
4860 if (ibss_ie_length <= (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004861 hdd_err("Could not parse command %s return length %d",
4862 value, ibss_ie_length);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004863 ret = -EFAULT;
4864 qdf_mem_free(ibss_ie);
4865 goto exit;
4866 }
4867
4868 pRoamProfile = &pWextState->roamProfile;
4869
4870 qdf_copy_macaddr(&ibssModifyIE.bssid,
4871 pRoamProfile->BSSIDs.bssid);
4872
4873 ibssModifyIE.smeSessionId = adapter->sessionId;
4874 ibssModifyIE.notify = true;
4875 ibssModifyIE.ieID = IE_EID_VENDOR;
4876 ibssModifyIE.ieIDLen = ibss_ie_length;
4877 ibssModifyIE.ieBufferlength = ibss_ie_length;
4878 ibssModifyIE.pIEBuffer = ibss_ie;
4879 ibssModifyIE.oui_length = oui_length;
4880
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004881 hdd_warn("ibss_ie length %d oui_length %d ibss_ie:",
4882 ibss_ie_length, oui_length);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004883 while (i < ibssModifyIE.ieBufferlength)
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004884 hdd_warn("0x%x", ibss_ie[i++]);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004885
4886 /* Probe Bcn modification */
4887 sme_modify_add_ie(WLAN_HDD_GET_HAL_CTX(adapter),
4888 &ibssModifyIE, eUPDATE_IE_PROBE_BCN);
4889
4890 /* Populating probe resp frame */
4891 sme_modify_add_ie(WLAN_HDD_GET_HAL_CTX(adapter),
4892 &ibssModifyIE, eUPDATE_IE_PROBE_RESP);
4893
4894 qdf_mem_free(ibss_ie);
4895
4896 status = sme_send_cesium_enable_ind((tHalHandle)(hdd_ctx->hHal),
4897 adapter->sessionId);
4898 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004899 hdd_err("Could not send cesium enable indication %d",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004900 status);
4901 ret = -EINVAL;
4902 goto exit;
4903 }
4904
4905exit:
4906 return ret;
4907}
4908
4909static int drv_cmd_set_rmc_enable(hdd_adapter_t *adapter,
4910 hdd_context_t *hdd_ctx,
4911 uint8_t *command,
4912 uint8_t command_len,
4913 hdd_priv_data_t *priv_data)
4914{
4915 int ret = 0;
4916 uint8_t *value = command;
4917 uint8_t ucRmcEnable = 0;
4918 int status;
4919
Krunal Sonibe766b02016-03-10 13:00:44 -08004920 if ((QDF_IBSS_MODE != adapter->device_mode) &&
4921 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004922 hdd_err("Received SETRMCENABLE cmd in invalid mode %s(%d)",
4923 hdd_device_mode_to_string(adapter->device_mode),
4924 adapter->device_mode);
4925 hdd_err("SETRMCENABLE cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004926 ret = -EINVAL;
4927 goto exit;
4928 }
4929
4930 status = hdd_parse_setrmcenable_command(value, &ucRmcEnable);
4931 if (status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004932 hdd_err("Invalid SETRMCENABLE command ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004933 ret = -EINVAL;
4934 goto exit;
4935 }
4936
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004937 hdd_info("ucRmcEnable %d ", ucRmcEnable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004938
4939 if (true == ucRmcEnable) {
4940 status = sme_enable_rmc((tHalHandle)
4941 (hdd_ctx->hHal),
4942 adapter->sessionId);
4943 } else if (false == ucRmcEnable) {
4944 status = sme_disable_rmc((tHalHandle)
4945 (hdd_ctx->hHal),
4946 adapter->sessionId);
4947 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004948 hdd_err("Invalid SETRMCENABLE command %d",
4949 ucRmcEnable);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004950 ret = -EINVAL;
4951 goto exit;
4952 }
4953
4954 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004955 hdd_err("SETRMC %d failed status %d",
4956 ucRmcEnable, status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004957 ret = -EINVAL;
4958 goto exit;
4959 }
4960
4961exit:
4962 return ret;
4963}
4964
4965static int drv_cmd_set_rmc_action_period(hdd_adapter_t *adapter,
4966 hdd_context_t *hdd_ctx,
4967 uint8_t *command,
4968 uint8_t command_len,
4969 hdd_priv_data_t *priv_data)
4970{
4971 int ret = 0;
4972 uint8_t *value = command;
4973 uint32_t uActionPeriod = 0;
4974 int status;
4975
Krunal Sonibe766b02016-03-10 13:00:44 -08004976 if ((QDF_IBSS_MODE != adapter->device_mode) &&
4977 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004978 hdd_err("Received SETRMC cmd in invalid mode %s(%d)",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004979 hdd_device_mode_to_string(adapter->device_mode),
4980 adapter->device_mode);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004981 hdd_err("SETRMC cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004982 ret = -EINVAL;
4983 goto exit;
4984 }
4985
4986 status = hdd_parse_setrmcactionperiod_command(value, &uActionPeriod);
4987 if (status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004988 hdd_err("Invalid SETRMCACTIONPERIOD command ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004989 ret = -EINVAL;
4990 goto exit;
4991 }
4992
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004993 hdd_info("uActionPeriod %d ",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08004994 uActionPeriod);
4995
4996 if (sme_cfg_set_int(hdd_ctx->hHal,
4997 WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY,
4998 uActionPeriod)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07004999 hdd_err("Could not set SETRMCACTIONPERIOD %d",
5000 uActionPeriod);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005001 ret = -EINVAL;
5002 goto exit;
5003 }
5004
5005 status = sme_send_rmc_action_period((tHalHandle)(hdd_ctx->hHal),
5006 adapter->sessionId);
5007 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005008 hdd_err("Could not send cesium enable indication %d",
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005009 status);
5010 ret = -EINVAL;
5011 goto exit;
5012 }
5013
5014exit:
5015 return ret;
5016}
5017
5018static int drv_cmd_get_ibss_peer_info_all(hdd_adapter_t *adapter,
5019 hdd_context_t *hdd_ctx,
5020 uint8_t *command,
5021 uint8_t command_len,
5022 hdd_priv_data_t *priv_data)
5023{
5024 int ret = 0;
5025 int status = QDF_STATUS_SUCCESS;
5026 hdd_station_ctx_t *pHddStaCtx = NULL;
5027 char *extra = NULL;
5028 int idx = 0;
5029 int length = 0;
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005030 uint8_t mac_addr[QDF_MAC_ADDR_SIZE];
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005031 uint32_t numOfBytestoPrint = 0;
5032
Krunal Sonibe766b02016-03-10 13:00:44 -08005033 if (QDF_IBSS_MODE != adapter->device_mode) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005034 hdd_warn("Unsupported in mode %s(%d)",
5035 hdd_device_mode_to_string(adapter->device_mode),
5036 adapter->device_mode);
5037 return -EINVAL;
5038 }
5039
5040 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005041 hdd_info("Received GETIBSSPEERINFOALL Command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005042
5043 /* Handle the command */
5044 status = hdd_cfg80211_get_ibss_peer_info_all(adapter);
5045 if (QDF_STATUS_SUCCESS == status) {
5046 /*
5047 * The variable extra needed to be allocated on the heap since
5048 * amount of memory required to copy the data for 32 devices
5049 * exceeds the size of 1024 bytes of default stack size. On
5050 * 64 bit devices, the default max stack size of 2048 bytes
5051 */
5052 extra = kmalloc(WLAN_MAX_BUF_SIZE, GFP_KERNEL);
5053
5054 if (NULL == extra) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005055 hdd_err("kmalloc failed");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005056 ret = -EINVAL;
5057 goto exit;
5058 }
5059
5060 /* Copy number of stations */
5061 length = scnprintf(extra, WLAN_MAX_BUF_SIZE, "%d ",
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005062 pHddStaCtx->ibss_peer_info.numPeers);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005063 numOfBytestoPrint = length;
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005064 for (idx = 0; idx < pHddStaCtx->ibss_peer_info.numPeers;
5065 idx++) {
5066 int8_t rssi;
5067 uint32_t tx_rate;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005068
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005069 qdf_mem_copy(mac_addr,
5070 pHddStaCtx->ibss_peer_info.peerInfoParams[idx].
5071 mac_addr, sizeof(mac_addr));
5072
5073 tx_rate =
5074 pHddStaCtx->ibss_peer_info.peerInfoParams[idx].
5075 txRate;
Sriram Madhvapathi85df7c72016-09-30 11:35:28 +05305076 /*
5077 * Only lower 3 bytes are rate info. Mask of the MSByte
5078 */
5079 tx_rate &= 0x00FFFFFF;
5080
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005081 rssi = pHddStaCtx->ibss_peer_info.peerInfoParams[idx].
5082 rssi;
5083
5084 length += scnprintf((extra + length),
5085 WLAN_MAX_BUF_SIZE - length,
5086 "%02x:%02x:%02x:%02x:%02x:%02x %d %d ",
5087 mac_addr[0], mac_addr[1], mac_addr[2],
5088 mac_addr[3], mac_addr[4], mac_addr[5],
5089 tx_rate, rssi);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005090 /*
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005091 * cdf_trace_msg has limitation of 512 bytes for the
5092 * print buffer. Hence printing the data in two chunks.
5093 * The first chunk will have the data for 16 devices
5094 * and the second chunk will have the rest.
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005095 */
5096 if (idx < NUM_OF_STA_DATA_TO_PRINT)
5097 numOfBytestoPrint = length;
5098 }
5099
5100 /*
5101 * Copy the data back into buffer, if the data to copy is
5102 * more than 512 bytes than we will split the data and do
5103 * it in two shots
5104 */
5105 if (copy_to_user(priv_data->buf, extra, numOfBytestoPrint)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005106 hdd_err("Copy into user data buffer failed ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005107 ret = -EFAULT;
5108 goto exit;
5109 }
5110
5111 priv_data->buf[numOfBytestoPrint] = '\0';
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005112 hdd_debug("%s", priv_data->buf);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005113
5114 if (length > numOfBytestoPrint) {
5115 if (copy_to_user
5116 (priv_data->buf + numOfBytestoPrint,
5117 extra + numOfBytestoPrint,
5118 length - numOfBytestoPrint + 1)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005119 hdd_err("Copy into user data buffer failed ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005120 ret = -EFAULT;
5121 goto exit;
5122 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005123 hdd_debug("%s", &priv_data->buf[numOfBytestoPrint]);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005124 }
5125
5126 /* Free temporary buffer */
5127 kfree(extra);
5128 } else {
5129 /* Command failed, log error */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005130 hdd_err("GETIBSSPEERINFOALL command failed with status code %d",
5131 status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005132 ret = -EINVAL;
5133 goto exit;
5134 }
5135 ret = 0;
5136
5137exit:
5138 return ret;
5139}
5140
5141/* Peer Info <Peer Addr> command */
5142static int drv_cmd_get_ibss_peer_info(hdd_adapter_t *adapter,
5143 hdd_context_t *hdd_ctx,
5144 uint8_t *command,
5145 uint8_t command_len,
5146 hdd_priv_data_t *priv_data)
5147{
5148 int ret = 0;
5149 uint8_t *value = command;
5150 QDF_STATUS status;
5151 hdd_station_ctx_t *pHddStaCtx = NULL;
5152 char extra[128] = { 0 };
5153 uint32_t length = 0;
5154 uint8_t staIdx = 0;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005155 struct qdf_mac_addr peerMacAddr;
5156
Krunal Sonibe766b02016-03-10 13:00:44 -08005157 if (QDF_IBSS_MODE != adapter->device_mode) {
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005158 hdd_warn("Unsupported in mode %s(%d)",
5159 hdd_device_mode_to_string(adapter->device_mode),
5160 adapter->device_mode);
5161 return -EINVAL;
5162 }
5163
5164 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5165
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005166 hdd_info("Received GETIBSSPEERINFO Command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005167
5168 /* if there are no peers, no need to continue with the command */
5169 if (eConnectionState_IbssConnected !=
5170 pHddStaCtx->conn_info.connState) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005171 hdd_info("No IBSS Peers coalesced");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005172 ret = -EINVAL;
5173 goto exit;
5174 }
5175
5176 /* Parse the incoming command buffer */
5177 status = hdd_parse_get_ibss_peer_info(value, &peerMacAddr);
5178 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005179 hdd_err("Invalid GETIBSSPEERINFO command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005180 ret = -EINVAL;
5181 goto exit;
5182 }
5183
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005184 /* Get station index for the peer mac address and sanitize it */
Deepak Dhamdhere5872c8c2016-06-02 15:51:47 -07005185 hdd_get_peer_sta_id(pHddStaCtx, &peerMacAddr, &staIdx);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005186
Naveen Rawatc45d1622016-07-05 12:20:09 -07005187 if (staIdx > MAX_PEERS) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005188 hdd_err("Invalid StaIdx %d returned", staIdx);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005189 ret = -EINVAL;
5190 goto exit;
5191 }
5192
5193 /* Handle the command */
5194 status = hdd_cfg80211_get_ibss_peer_info(adapter, staIdx);
5195 if (QDF_STATUS_SUCCESS == status) {
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005196 uint32_t txRate =
5197 pHddStaCtx->ibss_peer_info.peerInfoParams[0].txRate;
Sriram Madhvapathi85df7c72016-09-30 11:35:28 +05305198 /* Only lower 3 bytes are rate info. Mask of the MSByte */
5199 txRate &= 0x00FFFFFF;
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005200
5201 length = scnprintf(extra, sizeof(extra), "%d %d",
Rajeev Kumar94c9b452016-03-24 12:58:47 -07005202 (int)txRate,
5203 (int)pHddStaCtx->ibss_peer_info.
5204 peerInfoParams[0].rssi);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005205
5206 /* Copy the data back into buffer */
5207 if (copy_to_user(priv_data->buf, &extra, length + 1)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005208 hdd_err("copy data to user buffer failed GETIBSSPEERINFO command");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005209 ret = -EFAULT;
5210 goto exit;
5211 }
5212 } else {
5213 /* Command failed, log error */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005214 hdd_err("GETIBSSPEERINFO command failed with status code %d",
5215 status);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005216 ret = -EINVAL;
5217 goto exit;
5218 }
5219
5220 /* Success ! */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005221 hdd_debug("%s", priv_data->buf);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005222 ret = 0;
5223
5224exit:
5225 return ret;
5226}
5227
5228static int drv_cmd_set_rmc_tx_rate(hdd_adapter_t *adapter,
5229 hdd_context_t *hdd_ctx,
5230 uint8_t *command,
5231 uint8_t command_len,
5232 hdd_priv_data_t *priv_data)
5233{
5234 int ret = 0;
5235 uint8_t *value = command;
5236 uint32_t uRate = 0;
5237 tTxrateinfoflags txFlags = 0;
5238 tSirRateUpdateInd rateUpdateParams = {0};
5239 int status;
5240 struct hdd_config *pConfig = hdd_ctx->config;
5241
Krunal Sonibe766b02016-03-10 13:00:44 -08005242 if ((QDF_IBSS_MODE != adapter->device_mode) &&
5243 (QDF_SAP_MODE != adapter->device_mode)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005244 hdd_err("Received SETRMCTXRATE cmd in invalid mode %s(%d)",
5245 hdd_device_mode_to_string(adapter->device_mode),
5246 adapter->device_mode);
5247 hdd_err("SETRMCTXRATE cmd is allowed only in IBSS/SOFTAP mode");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005248 ret = -EINVAL;
5249 goto exit;
5250 }
5251
5252 status = hdd_parse_setrmcrate_command(value, &uRate, &txFlags);
5253 if (status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005254 hdd_err("Invalid SETRMCTXRATE command ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005255 ret = -EINVAL;
5256 goto exit;
5257 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005258 hdd_info("uRate %d ", uRate);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005259 /* -1 implies ignore this param */
5260 rateUpdateParams.ucastDataRate = -1;
5261
5262 /*
5263 * Fill the user specifieed RMC rate param
5264 * and the derived tx flags.
5265 */
5266 rateUpdateParams.nss = (pConfig->enable2x2 == 0) ? 0 : 1;
5267 rateUpdateParams.reliableMcastDataRate = uRate;
5268 rateUpdateParams.reliableMcastDataRateTxFlag = txFlags;
5269 rateUpdateParams.dev_mode = adapter->device_mode;
5270 rateUpdateParams.bcastDataRate = -1;
5271 memcpy(rateUpdateParams.bssid.bytes,
5272 adapter->macAddressCurrent.bytes,
5273 sizeof(rateUpdateParams.bssid));
5274 status = sme_send_rate_update_ind((tHalHandle) (hdd_ctx->hHal),
5275 &rateUpdateParams);
5276
5277exit:
5278 return ret;
5279}
5280
5281static int drv_cmd_set_ibss_tx_fail_event(hdd_adapter_t *adapter,
5282 hdd_context_t *hdd_ctx,
5283 uint8_t *command,
5284 uint8_t command_len,
5285 hdd_priv_data_t *priv_data)
5286{
5287 int ret = 0;
5288 char *value;
5289 uint8_t tx_fail_count = 0;
5290 uint16_t pid = 0;
5291
5292 value = command;
5293
5294 ret = hdd_parse_ibsstx_fail_event_params(value, &tx_fail_count, &pid);
5295
5296 if (0 != ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005297 hdd_info("Failed to parse SETIBSSTXFAILEVENT arguments");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005298 goto exit;
5299 }
5300
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005301 hdd_info("tx_fail_cnt=%hhu, pid=%hu", tx_fail_count, pid);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005302
5303 if (0 == tx_fail_count) {
5304 /* Disable TX Fail Indication */
5305 if (QDF_STATUS_SUCCESS ==
5306 sme_tx_fail_monitor_start_stop_ind(hdd_ctx->hHal,
5307 tx_fail_count,
5308 NULL)) {
5309 cesium_pid = 0;
5310 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005311 hdd_err("failed to disable TX Fail Event ");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005312 ret = -EINVAL;
5313 }
5314 } else {
5315 if (QDF_STATUS_SUCCESS ==
5316 sme_tx_fail_monitor_start_stop_ind(hdd_ctx->hHal,
5317 tx_fail_count,
5318 (void *)hdd_tx_fail_ind_callback)) {
5319 cesium_pid = pid;
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005320 hdd_info("Registered Cesium pid %u",
5321 cesium_pid);
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005322 } else {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005323 hdd_err("Failed to enable TX Fail Monitoring");
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08005324 ret = -EINVAL;
5325 }
5326 }
5327
5328exit:
5329 return ret;
5330}
5331
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08005332#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005333static int drv_cmd_set_ccx_roam_scan_channels(hdd_adapter_t *adapter,
5334 hdd_context_t *hdd_ctx,
5335 uint8_t *command,
5336 uint8_t command_len,
5337 hdd_priv_data_t *priv_data)
5338{
5339 int ret = 0;
5340 uint8_t *value = command;
5341 uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
5342 uint8_t numChannels = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305343 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005344
5345 ret = hdd_parse_channellist(value, ChannelList, &numChannels);
5346 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005347 hdd_err("Failed to parse channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005348 goto exit;
5349 }
5350 if (numChannels > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005351 hdd_err("number of channels (%d) supported exceeded max (%d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005352 numChannels,
5353 WNI_CFG_VALID_CHANNEL_LIST_LEN);
5354 ret = -EINVAL;
5355 goto exit;
5356 }
5357 status = sme_set_ese_roam_scan_channel_list(hdd_ctx->hHal,
5358 adapter->sessionId,
5359 ChannelList,
5360 numChannels);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305361 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005362 hdd_err("Failed to update channel list information");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005363 ret = -EINVAL;
5364 goto exit;
5365 }
5366
5367exit:
5368 return ret;
5369}
5370
5371static int drv_cmd_get_tsm_stats(hdd_adapter_t *adapter,
5372 hdd_context_t *hdd_ctx,
5373 uint8_t *command,
5374 uint8_t command_len,
5375 hdd_priv_data_t *priv_data)
5376{
5377 int ret = 0;
5378 uint8_t *value = command;
5379 char extra[128] = { 0 };
5380 int len = 0;
5381 uint8_t tid = 0;
5382 hdd_station_ctx_t *pHddStaCtx;
5383 tAniTrafStrmMetrics tsm_metrics;
5384
Krunal Sonibe766b02016-03-10 13:00:44 -08005385 if ((QDF_STA_MODE != adapter->device_mode) &&
5386 (QDF_P2P_CLIENT_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005387 hdd_warn("Unsupported in mode %s(%d)",
5388 hdd_device_mode_to_string(adapter->device_mode),
5389 adapter->device_mode);
5390 return -EINVAL;
5391 }
5392
5393 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5394
5395 /* if not associated, return error */
5396 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005397 hdd_err("Not associated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005398 ret = -EINVAL;
5399 goto exit;
5400 }
5401
5402 /* Move pointer to ahead of GETTSMSTATS<delimiter> */
5403 value = value + command_len + 1;
5404
5405 /* Convert the value from ascii to integer */
5406 ret = kstrtou8(value, 10, &tid);
5407 if (ret < 0) {
5408 /*
5409 * If the input value is greater than max value of datatype,
5410 * then also kstrtou8 fails
5411 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005412 hdd_err("kstrtou8 failed range [%d - %d]",
5413 TID_MIN_VALUE,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005414 TID_MAX_VALUE);
5415 ret = -EINVAL;
5416 goto exit;
5417 }
5418 if ((tid < TID_MIN_VALUE) || (tid > TID_MAX_VALUE)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005419 hdd_err("tid value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005420 tid, TID_MIN_VALUE, TID_MAX_VALUE);
5421 ret = -EINVAL;
5422 goto exit;
5423 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005424 hdd_info("Received Command to get tsm stats tid = %d",
5425 tid);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305426 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005427 hdd_get_tsm_stats(adapter, tid, &tsm_metrics)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005428 hdd_err("failed to get tsm stats");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005429 ret = -EFAULT;
5430 goto exit;
5431 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005432 hdd_info(
5433 "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 -08005434 tsm_metrics.UplinkPktQueueDly,
5435 tsm_metrics.UplinkPktQueueDlyHist[0],
5436 tsm_metrics.UplinkPktQueueDlyHist[1],
5437 tsm_metrics.UplinkPktQueueDlyHist[2],
5438 tsm_metrics.UplinkPktQueueDlyHist[3],
5439 tsm_metrics.UplinkPktTxDly,
5440 tsm_metrics.UplinkPktLoss,
5441 tsm_metrics.UplinkPktCount,
5442 tsm_metrics.RoamingCount,
5443 tsm_metrics.RoamingDly);
5444 /*
5445 * Output TSM stats is of the format
5446 * GETTSMSTATS [PktQueueDly]
5447 * [PktQueueDlyHist[0]]:[PktQueueDlyHist[1]] ...[RoamingDly]
5448 * eg., GETTSMSTATS 10 1:0:0:161 20 1 17 8 39800
5449 */
5450 len = scnprintf(extra,
5451 sizeof(extra),
5452 "%s %d %d:%d:%d:%d %u %d %d %d %d",
5453 command,
5454 tsm_metrics.UplinkPktQueueDly,
5455 tsm_metrics.UplinkPktQueueDlyHist[0],
5456 tsm_metrics.UplinkPktQueueDlyHist[1],
5457 tsm_metrics.UplinkPktQueueDlyHist[2],
5458 tsm_metrics.UplinkPktQueueDlyHist[3],
5459 tsm_metrics.UplinkPktTxDly,
5460 tsm_metrics.UplinkPktLoss,
5461 tsm_metrics.UplinkPktCount,
5462 tsm_metrics.RoamingCount,
5463 tsm_metrics.RoamingDly);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305464 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005465 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005466 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005467 ret = -EFAULT;
5468 goto exit;
5469 }
5470
5471exit:
5472 return ret;
5473}
5474
5475static int drv_cmd_set_cckm_ie(hdd_adapter_t *adapter,
5476 hdd_context_t *hdd_ctx,
5477 uint8_t *command,
5478 uint8_t command_len,
5479 hdd_priv_data_t *priv_data)
5480{
5481 int ret;
5482 uint8_t *value = command;
5483 uint8_t *cckmIe = NULL;
5484 uint8_t cckmIeLen = 0;
5485
5486 ret = hdd_parse_get_cckm_ie(value, &cckmIe, &cckmIeLen);
5487 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005488 hdd_err("Failed to parse cckm ie data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005489 goto exit;
5490 }
5491
5492 if (cckmIeLen > DOT11F_IE_RSN_MAX_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005493 hdd_err("CCKM Ie input length is more than max[%d]",
5494 DOT11F_IE_RSN_MAX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005495 if (NULL != cckmIe) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305496 qdf_mem_free(cckmIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005497 cckmIe = NULL;
5498 }
5499 ret = -EINVAL;
5500 goto exit;
5501 }
5502
5503 sme_set_cckm_ie(hdd_ctx->hHal, adapter->sessionId,
5504 cckmIe, cckmIeLen);
5505 if (NULL != cckmIe) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305506 qdf_mem_free(cckmIe);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005507 cckmIe = NULL;
5508 }
5509
5510exit:
5511 return ret;
5512}
5513
5514static int drv_cmd_ccx_beacon_req(hdd_adapter_t *adapter,
5515 hdd_context_t *hdd_ctx,
5516 uint8_t *command,
5517 uint8_t command_len,
5518 hdd_priv_data_t *priv_data)
5519{
5520 int ret;
5521 uint8_t *value = command;
5522 tCsrEseBeaconReq eseBcnReq;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305523 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005524
Krunal Sonibe766b02016-03-10 13:00:44 -08005525 if (QDF_STA_MODE != adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005526 hdd_warn("Unsupported in mode %s(%d)",
5527 hdd_device_mode_to_string(adapter->device_mode),
5528 adapter->device_mode);
5529 return -EINVAL;
5530 }
5531
5532 ret = hdd_parse_ese_beacon_req(value, &eseBcnReq);
5533 if (ret) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005534 hdd_err("Failed to parse ese beacon req");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005535 goto exit;
5536 }
5537
5538 if (!hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005539 hdd_info("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005540 hdd_indicate_ese_bcn_report_no_results(adapter,
5541 eseBcnReq.bcnReq[0].measurementToken,
5542 0x02, /* BIT(1) set for measurement done */
5543 0); /* no BSS */
5544 goto exit;
5545 }
5546
5547 status = sme_set_ese_beacon_request(hdd_ctx->hHal,
5548 adapter->sessionId,
5549 &eseBcnReq);
5550
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305551 if (QDF_STATUS_E_RESOURCES == status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005552 hdd_info("sme_set_ese_beacon_request failed (%d), a request already in progress",
5553 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005554 ret = -EBUSY;
5555 goto exit;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305556 } else if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005557 hdd_err("sme_set_ese_beacon_request failed (%d)",
5558 status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005559 ret = -EINVAL;
5560 goto exit;
5561 }
5562
5563exit:
5564 return ret;
5565}
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07005566
5567/**
5568 * drv_cmd_ccx_plm_req() - Set ESE PLM request
5569 * @adapter: Pointer to the HDD adapter
5570 * @hdd_ctx: Pointer to the HDD context
5571 * @command: Driver command string
5572 * @command_len: Driver command string length
5573 * @priv_data: Private data coming with the driver command. Unused here
5574 *
5575 * This function handles driver command that sets the ESE PLM request
5576 *
5577 * Return: 0 on success; negative errno otherwise
5578 */
5579static int drv_cmd_ccx_plm_req(hdd_adapter_t *adapter,
5580 hdd_context_t *hdd_ctx,
5581 uint8_t *command,
5582 uint8_t command_len,
5583 hdd_priv_data_t *priv_data)
5584{
5585 int ret = 0;
5586 uint8_t *value = command;
5587 QDF_STATUS status = QDF_STATUS_SUCCESS;
5588 tpSirPlmReq pPlmRequest = NULL;
5589
5590 pPlmRequest = qdf_mem_malloc(sizeof(tSirPlmReq));
5591 if (NULL == pPlmRequest) {
5592 ret = -ENOMEM;
5593 goto exit;
5594 }
5595
5596 status = hdd_parse_plm_cmd(value, pPlmRequest);
5597 if (QDF_STATUS_SUCCESS != status) {
5598 qdf_mem_free(pPlmRequest);
5599 pPlmRequest = NULL;
5600 ret = -EINVAL;
5601 goto exit;
5602 }
5603 pPlmRequest->sessionId = adapter->sessionId;
5604
5605 status = sme_set_plm_request(hdd_ctx->hHal, pPlmRequest);
5606 if (QDF_STATUS_SUCCESS != status) {
5607 qdf_mem_free(pPlmRequest);
5608 pPlmRequest = NULL;
5609 ret = -EINVAL;
5610 goto exit;
5611 }
5612
5613exit:
5614 return ret;
5615}
5616
5617/**
5618 * drv_cmd_set_ccx_mode() - Set ESE mode
5619 * @adapter: Pointer to the HDD adapter
5620 * @hdd_ctx: Pointer to the HDD context
5621 * @command: Driver command string
5622 * @command_len: Driver command string length
5623 * @priv_data: Private data coming with the driver command. Unused here
5624 *
5625 * This function handles driver command that sets ESE mode
5626 *
5627 * Return: 0 on success; negative errno otherwise
5628 */
5629static int drv_cmd_set_ccx_mode(hdd_adapter_t *adapter,
5630 hdd_context_t *hdd_ctx,
5631 uint8_t *command,
5632 uint8_t command_len,
5633 hdd_priv_data_t *priv_data)
5634{
5635 int ret = 0;
5636 uint8_t *value = command;
5637 uint8_t eseMode = CFG_ESE_FEATURE_ENABLED_DEFAULT;
5638
5639 /*
5640 * Check if the features OKC/ESE/11R are supported simultaneously,
5641 * then this operation is not permitted (return FAILURE)
5642 */
5643 if (sme_get_is_ese_feature_enabled(hdd_ctx->hHal) &&
5644 hdd_is_okc_mode_enabled(hdd_ctx) &&
5645 sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) {
5646 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
5647 ret = -EPERM;
5648 goto exit;
5649 }
5650
5651 /* Move pointer to ahead of SETCCXMODE<delimiter> */
5652 value = value + command_len + 1;
5653
5654 /* Convert the value from ascii to integer */
5655 ret = kstrtou8(value, 10, &eseMode);
5656 if (ret < 0) {
5657 /*
5658 * If the input value is greater than max value of datatype,
5659 * then also kstrtou8 fails
5660 */
5661 hdd_err("kstrtou8 failed range [%d - %d]",
5662 CFG_ESE_FEATURE_ENABLED_MIN,
5663 CFG_ESE_FEATURE_ENABLED_MAX);
5664 ret = -EINVAL;
5665 goto exit;
5666 }
5667
5668 if ((eseMode < CFG_ESE_FEATURE_ENABLED_MIN) ||
5669 (eseMode > CFG_ESE_FEATURE_ENABLED_MAX)) {
5670 hdd_err("Ese mode value %d is out of range (Min: %d Max: %d)",
5671 eseMode,
5672 CFG_ESE_FEATURE_ENABLED_MIN,
5673 CFG_ESE_FEATURE_ENABLED_MAX);
5674 ret = -EINVAL;
5675 goto exit;
5676 }
5677 hdd_info("Received Command to change ese mode = %d", eseMode);
5678
5679 hdd_ctx->config->isEseIniFeatureEnabled = eseMode;
5680 sme_update_is_ese_feature_enabled(hdd_ctx->hHal,
5681 adapter->sessionId,
5682 eseMode);
5683
5684exit:
5685 return ret;
5686}
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08005687#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005688
5689static int drv_cmd_set_mc_rate(hdd_adapter_t *adapter,
5690 hdd_context_t *hdd_ctx,
5691 uint8_t *command,
5692 uint8_t command_len,
5693 hdd_priv_data_t *priv_data)
5694{
5695 int ret = 0;
5696 uint8_t *value = command;
5697 int targetRate;
5698
5699 /* input value is in units of hundred kbps */
5700
5701 /* Move pointer to ahead of SETMCRATE<delimiter> */
5702 value = value + command_len + 1;
5703
5704 /* Convert the value from ascii to integer, decimal base */
5705 ret = kstrtouint(value, 10, &targetRate);
5706
5707 ret = wlan_hdd_set_mc_rate(adapter, targetRate);
5708 return ret;
5709}
5710
5711static int drv_cmd_max_tx_power(hdd_adapter_t *adapter,
5712 hdd_context_t *hdd_ctx,
5713 uint8_t *command,
5714 uint8_t command_len,
5715 hdd_priv_data_t *priv_data)
5716{
5717 int ret = 0;
5718 int status;
5719 int txPower;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305720 QDF_STATUS qdf_status;
5721 QDF_STATUS smeStatus;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005722 uint8_t *value = command;
Anurag Chouhan6d760662016-02-20 16:05:43 +05305723 struct qdf_mac_addr bssid = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
5724 struct qdf_mac_addr selfMac = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005725 hdd_adapter_list_node_t *pAdapterNode = NULL;
5726 hdd_adapter_list_node_t *pNext = NULL;
5727
5728 status = hdd_parse_setmaxtxpower_command(value, &txPower);
5729 if (status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005730 hdd_err("Invalid MAXTXPOWER command ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005731 ret = -EINVAL;
5732 goto exit;
5733 }
5734
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305735 qdf_status = hdd_get_front_adapter(hdd_ctx, &pAdapterNode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005736 while (NULL != pAdapterNode
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305737 && QDF_STATUS_SUCCESS == qdf_status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005738 adapter = pAdapterNode->pAdapter;
5739 /* Assign correct self MAC address */
Anurag Chouhanc5548422016-02-24 18:33:27 +05305740 qdf_copy_macaddr(&bssid,
Srinivas Girigowda97215232015-09-24 12:26:28 -07005741 &adapter->macAddressCurrent);
Anurag Chouhanc5548422016-02-24 18:33:27 +05305742 qdf_copy_macaddr(&selfMac,
Srinivas Girigowda97215232015-09-24 12:26:28 -07005743 &adapter->macAddressCurrent);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005744
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005745 hdd_info("Device mode %d max tx power %d selfMac: "
5746 MAC_ADDRESS_STR " bssId: " MAC_ADDRESS_STR " ",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005747 adapter->device_mode, txPower,
Srinivas Girigowda97215232015-09-24 12:26:28 -07005748 MAC_ADDR_ARRAY(selfMac.bytes),
5749 MAC_ADDR_ARRAY(bssid.bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005750
Srinivas Girigowda97215232015-09-24 12:26:28 -07005751 smeStatus = sme_set_max_tx_power(hdd_ctx->hHal,
5752 bssid, selfMac, txPower);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305753 if (QDF_STATUS_SUCCESS != status) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005754 hdd_err("Set max tx power failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005755 ret = -EINVAL;
5756 goto exit;
5757 }
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005758 hdd_info("Set max tx power success");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305759 qdf_status = hdd_get_next_adapter(hdd_ctx, pAdapterNode,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005760 &pNext);
5761 pAdapterNode = pNext;
5762 }
5763
5764exit:
5765 return ret;
5766}
5767
5768static int drv_cmd_set_dfs_scan_mode(hdd_adapter_t *adapter,
5769 hdd_context_t *hdd_ctx,
5770 uint8_t *command,
5771 uint8_t command_len,
5772 hdd_priv_data_t *priv_data)
5773{
5774 int ret = 0;
5775 uint8_t *value = command;
5776 uint8_t dfsScanMode = CFG_ROAMING_DFS_CHANNEL_DEFAULT;
5777
5778 /* Move pointer to ahead of SETDFSSCANMODE<delimiter> */
5779 value = value + command_len + 1;
5780
5781 /* Convert the value from ascii to integer */
5782 ret = kstrtou8(value, 10, &dfsScanMode);
5783 if (ret < 0) {
5784 /*
5785 * If the input value is greater than max value of datatype,
5786 * then also kstrtou8 fails
5787 */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005788 hdd_err("kstrtou8 failed range [%d - %d]",
5789 CFG_ROAMING_DFS_CHANNEL_MIN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005790 CFG_ROAMING_DFS_CHANNEL_MAX);
5791 ret = -EINVAL;
5792 goto exit;
5793 }
5794
5795 if ((dfsScanMode < CFG_ROAMING_DFS_CHANNEL_MIN) ||
5796 (dfsScanMode > CFG_ROAMING_DFS_CHANNEL_MAX)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005797 hdd_err("dfsScanMode value %d is out of range (Min: %d Max: %d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005798 dfsScanMode,
5799 CFG_ROAMING_DFS_CHANNEL_MIN,
5800 CFG_ROAMING_DFS_CHANNEL_MAX);
5801 ret = -EINVAL;
5802 goto exit;
5803 }
5804
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005805 hdd_info("Received Command to Set DFS Scan Mode = %d",
5806 dfsScanMode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005807
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005808 /* When DFS scanning is disabled, the DFS channels need to be
5809 * removed from the operation of device.
5810 */
5811 ret = wlan_hdd_disable_dfs_chan_scan(hdd_ctx, adapter,
5812 (dfsScanMode == CFG_ROAMING_DFS_CHANNEL_DISABLED));
5813 if (ret < 0) {
5814 /* Some conditions prevented it from disabling DFS channels */
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005815 hdd_err("disable/enable DFS channel request was denied");
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08005816 goto exit;
5817 }
5818
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005819 hdd_ctx->config->allowDFSChannelRoam = dfsScanMode;
5820 sme_update_dfs_scan_mode(hdd_ctx->hHal, adapter->sessionId,
5821 dfsScanMode);
5822
5823exit:
5824 return ret;
5825}
5826
5827static int drv_cmd_get_dfs_scan_mode(hdd_adapter_t *adapter,
5828 hdd_context_t *hdd_ctx,
5829 uint8_t *command,
5830 uint8_t command_len,
5831 hdd_priv_data_t *priv_data)
5832{
5833 int ret = 0;
5834 uint8_t dfsScanMode = sme_get_dfs_scan_mode(hdd_ctx->hHal);
5835 char extra[32];
5836 uint8_t len = 0;
5837
5838 len = scnprintf(extra, sizeof(extra), "%s %d", command, dfsScanMode);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305839 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005840 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005841 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005842 ret = -EFAULT;
5843 }
5844
5845 return ret;
5846}
5847
5848static int drv_cmd_get_link_status(hdd_adapter_t *adapter,
5849 hdd_context_t *hdd_ctx,
5850 uint8_t *command,
5851 uint8_t command_len,
5852 hdd_priv_data_t *priv_data)
5853{
5854 int ret = 0;
5855 int value = wlan_hdd_get_link_status(adapter);
5856 char extra[32];
5857 uint8_t len;
5858
5859 len = scnprintf(extra, sizeof(extra), "%s %d", command, value);
Anurag Chouhan6d760662016-02-20 16:05:43 +05305860 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005861 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005862 hdd_err("failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005863 ret = -EFAULT;
5864 }
5865
5866 return ret;
5867}
5868
5869#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
5870static int drv_cmd_enable_ext_wow(hdd_adapter_t *adapter,
5871 hdd_context_t *hdd_ctx,
5872 uint8_t *command,
5873 uint8_t command_len,
5874 hdd_priv_data_t *priv_data)
5875{
5876 uint8_t *value = command;
5877 int set_value;
5878
5879 /* Move pointer to ahead of ENABLEEXTWOW */
5880 value = value + command_len;
5881
Anurag Chouhan43e0c752016-09-03 16:17:02 +05305882 if (!(sscanf(value, "%d", &set_value))) {
5883 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
5884 ("No input identified"));
5885 return -EINVAL;
5886 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005887
5888 return hdd_enable_ext_wow_parser(adapter,
5889 adapter->sessionId,
5890 set_value);
5891}
5892
5893static int drv_cmd_set_app1_params(hdd_adapter_t *adapter,
5894 hdd_context_t *hdd_ctx,
5895 uint8_t *command,
5896 uint8_t command_len,
5897 hdd_priv_data_t *priv_data)
5898{
5899 int ret;
5900 uint8_t *value = command;
5901
5902 /* Move pointer to ahead of SETAPP1PARAMS */
5903 value = value + command_len;
5904
5905 ret = hdd_set_app_type1_parser(adapter,
5906 value, strlen(value));
5907 if (ret >= 0)
5908 hdd_ctx->is_extwow_app_type1_param_set = true;
5909
5910 return ret;
5911}
5912
5913static int drv_cmd_set_app2_params(hdd_adapter_t *adapter,
5914 hdd_context_t *hdd_ctx,
5915 uint8_t *command,
5916 uint8_t command_len,
5917 hdd_priv_data_t *priv_data)
5918{
5919 int ret;
5920 uint8_t *value = command;
5921
5922 /* Move pointer to ahead of SETAPP2PARAMS */
5923 value = value + command_len;
5924
5925 ret = hdd_set_app_type2_parser(adapter, value, strlen(value));
5926 if (ret >= 0)
5927 hdd_ctx->is_extwow_app_type2_param_set = true;
5928
5929 return ret;
5930}
5931#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
5932
5933#ifdef FEATURE_WLAN_TDLS
5934/**
5935 * drv_cmd_tdls_secondary_channel_offset() - secondary tdls off channel offset
5936 * @adapter: Pointer to the HDD adapter
5937 * @hdd_ctx: Pointer to the HDD context
5938 * @command: Driver command string
5939 * @command_len: Driver command string length
5940 * @priv_data: Private data coming with the driver command. Unused here
5941 *
5942 * This function handles driver command that sets the secondary tdls off channel
5943 * offset
5944 *
5945 * Return: 0 on success; negative errno otherwise
5946 */
5947static int drv_cmd_tdls_secondary_channel_offset(hdd_adapter_t *adapter,
5948 hdd_context_t *hdd_ctx,
5949 uint8_t *command,
5950 uint8_t command_len,
5951 hdd_priv_data_t *priv_data)
5952{
5953 int ret;
5954 uint8_t *value = command;
5955 int set_value;
5956
5957 /* Move pointer to point the string */
5958 value += command_len;
5959
5960 ret = sscanf(value, "%d", &set_value);
5961 if (ret != 1)
5962 return -EINVAL;
5963
Archana Ramachandran3abc3912016-04-29 17:01:32 -07005964 hdd_info("Tdls offchannel offset:%d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005965
5966 ret = hdd_set_tdls_secoffchanneloffset(hdd_ctx, set_value);
5967
5968 return ret;
5969}
5970
5971/**
5972 * drv_cmd_tdls_off_channel_mode() - set tdls off channel mode
5973 * @adapter: Pointer to the HDD adapter
5974 * @hdd_ctx: Pointer to the HDD context
5975 * @command: Driver command string
5976 * @command_len: Driver command string length
5977 * @priv_data: Private data coming with the driver command. Unused here
5978 *
5979 * This function handles driver command that sets tdls off channel mode
5980 *
5981 * Return: 0 on success; negative errno otherwise
5982 */
5983static int drv_cmd_tdls_off_channel_mode(hdd_adapter_t *adapter,
5984 hdd_context_t *hdd_ctx,
5985 uint8_t *command,
5986 uint8_t command_len,
5987 hdd_priv_data_t *priv_data)
5988{
5989 int ret;
5990 uint8_t *value = command;
5991 int set_value;
5992
5993 /* Move pointer to point the string */
5994 value += command_len;
5995
5996 ret = sscanf(value, "%d", &set_value);
5997 if (ret != 1)
5998 return -EINVAL;
5999
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006000 hdd_info("Tdls offchannel mode:%d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006001
6002 ret = hdd_set_tdls_offchannelmode(adapter, set_value);
6003
6004 return ret;
6005}
6006
6007/**
6008 * drv_cmd_tdls_off_channel() - set tdls off channel number
6009 * @adapter: Pointer to the HDD adapter
6010 * @hdd_ctx: Pointer to the HDD context
6011 * @command: Driver command string
6012 * @command_len: Driver command string length
6013 * @priv_data: Private data coming with the driver command. Unused here
6014 *
6015 * This function handles driver command that sets tdls off channel number
6016 *
6017 * Return: 0 on success; negative errno otherwise
6018 */
6019static int drv_cmd_tdls_off_channel(hdd_adapter_t *adapter,
6020 hdd_context_t *hdd_ctx,
6021 uint8_t *command,
6022 uint8_t command_len,
6023 hdd_priv_data_t *priv_data)
6024{
6025 int ret;
6026 uint8_t *value = command;
6027 int set_value;
6028
6029 /* Move pointer to point the string */
6030 value += command_len;
6031
6032 ret = sscanf(value, "%d", &set_value);
6033 if (ret != 1)
6034 return -EINVAL;
6035
Krishna Kumaar Natarajan4d090352015-10-26 18:30:53 -07006036 if (CDS_IS_DFS_CH(set_value)) {
6037 hdd_err("DFS channel %d is passed for hdd_set_tdls_offchannel",
6038 set_value);
6039 return -EINVAL;
6040 }
6041
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006042 hdd_info("Tdls offchannel num: %d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006043
6044 ret = hdd_set_tdls_offchannel(hdd_ctx, set_value);
6045
6046 return ret;
6047}
6048
6049/**
6050 * drv_cmd_tdls_scan() - set tdls scan type
6051 * @adapter: Pointer to the HDD adapter
6052 * @hdd_ctx: Pointer to the HDD context
6053 * @command: Driver command string
6054 * @command_len: Driver command string length
6055 * @priv_data: Private data coming with the driver command. Unused here
6056 *
6057 * This function handles driver command that sets tdls scan type
6058 *
6059 * Return: 0 on success; negative errno otherwise
6060 */
6061static int drv_cmd_tdls_scan(hdd_adapter_t *adapter,
6062 hdd_context_t *hdd_ctx,
6063 uint8_t *command,
6064 uint8_t command_len,
6065 hdd_priv_data_t *priv_data)
6066{
6067 int ret;
6068 uint8_t *value = command;
6069 int set_value;
6070
6071 /* Move pointer to point the string */
6072 value += command_len;
6073
6074 ret = sscanf(value, "%d", &set_value);
6075 if (ret != 1)
6076 return -EINVAL;
6077
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006078 hdd_info("Tdls scan type val: %d", set_value);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006079
6080 ret = hdd_set_tdls_scan_type(hdd_ctx, set_value);
6081
6082 return ret;
6083}
6084#endif
6085
6086static int drv_cmd_get_rssi(hdd_adapter_t *adapter,
6087 hdd_context_t *hdd_ctx,
6088 uint8_t *command,
6089 uint8_t command_len,
6090 hdd_priv_data_t *priv_data)
6091{
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006092 int ret = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006093 int8_t rssi = 0;
6094 char extra[32];
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006095
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006096 uint8_t len = 0;
6097
6098 wlan_hdd_get_rssi(adapter, &rssi);
6099
6100 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
Anurag Chouhan6d760662016-02-20 16:05:43 +05306101 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006102
6103 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006104 hdd_err("Failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006105 ret = -EFAULT;
6106 }
6107
6108 return ret;
6109}
6110
6111static int drv_cmd_get_linkspeed(hdd_adapter_t *adapter,
6112 hdd_context_t *hdd_ctx,
6113 uint8_t *command,
6114 uint8_t command_len,
6115 hdd_priv_data_t *priv_data)
6116{
6117 int ret;
6118 uint32_t link_speed = 0;
6119 char extra[32];
6120 uint8_t len = 0;
6121
6122 ret = wlan_hdd_get_link_speed(adapter, &link_speed);
6123 if (0 != ret)
6124 return ret;
6125
6126 len = scnprintf(extra, sizeof(extra), "%s %d", command, link_speed);
Anurag Chouhan6d760662016-02-20 16:05:43 +05306127 len = QDF_MIN(priv_data->total_len, len + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006128 if (copy_to_user(priv_data->buf, &extra, len)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006129 hdd_err("Failed to copy data to user buffer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006130 ret = -EFAULT;
6131 }
6132
6133 return ret;
6134}
6135
6136#ifdef FEATURE_NAPI
6137/**
6138 * hdd_parse_napi() - helper functions to drv_cmd_napi
6139 * @str : source string to parse
6140 * @cmd : pointer to cmd part after parsing
6141 * @sub : pointer to subcmd part after parsing
6142 * @aux : pointer to optional aux part after parsing
6143 *
6144 * Example:
6145 * NAPI SCALE <n> +-- IN str
6146 * | | +------ OUT aux
6147 * | +------------ OUT subcmd
6148 * +----------------- OUT cmd
6149 *
6150 * Return: ==0: success; !=0: failure
6151 */
6152static int hdd_parse_napi(char **str, char **cmd, char **sub, char **aux)
6153{
6154 int rc;
6155 char *token, *lcmd = NULL, *lsub = NULL, *laux = NULL;
6156
6157 NAPI_DEBUG("-->\n");
6158
6159 token = strsep(str, " \t");
6160 if (NULL == token) {
6161 hdd_err("cannot parse cmd");
6162 goto parse_end;
6163 }
6164 lcmd = token;
6165
6166 token = strsep(str, " \t");
6167 if (NULL == token) {
6168 hdd_err("cannot parse subcmd");
6169 goto parse_end;
6170 }
6171 lsub = token;
6172
6173 token = strsep(str, " \t");
6174 if (NULL == token)
6175 hdd_warn("cannot parse aux\n");
6176 else
6177 laux = token;
6178
6179parse_end:
6180 if ((NULL == lcmd) || (NULL == lsub))
6181 rc = -EINVAL;
6182 else {
6183 rc = 0;
6184 *cmd = lcmd;
6185 *sub = lsub;
6186 if (NULL != aux)
6187 *aux = laux;
6188 }
6189 NAPI_DEBUG("<--[rc=%d]\n", rc);
6190 return rc;
6191}
6192
6193
6194/**
6195 * hdd_parse_stats() - print NAPI stats into a buffer
6196 * @buf : buffer to write stats into
6197 * @max : "size of buffer"
6198 * @idp : NULL: all stats, otherwise, ptr to the NAPI instance
6199 * @napid: binary structure to retrieve the stats from
6200 *
6201 * Return: number of bytes written into the buffer
6202 */
6203int hdd_napi_stats(char *buf,
6204 int max,
6205 char *indp,
6206 struct qca_napi_data *napid)
6207{
6208 int n = 0;
6209 int i, j, k; /* NAPI, CPU, bucket indices */
6210 int from, to;
6211 struct qca_napi_info *napii;
6212 struct qca_napi_stat *napis;
6213
6214 NAPI_DEBUG("-->\n");
6215
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006216 if (NULL == napid)
6217 return n;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006218 if (NULL == indp) {
6219 from = 0;
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006220 to = CE_COUNT_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006221 } else {
6222 if (0 > kstrtoint(indp, 10, &to)) {
6223 from = 0;
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006224 to = CE_COUNT_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006225 } else
6226 from = to;
6227 }
6228
6229 for (i = from; i < to; i++)
6230 if (napid->ce_map & (0x01 << i)) {
6231 napii = &(napid->napis[i]);
6232 for (j = 0; j < NR_CPUS; j++) {
6233 napis = &(napii->stats[j]);
6234 n += scnprintf(buf + n, max - n,
6235 "STATS: NAPI[%d] CPU: %d scheds: %d polls: %d completes: %d done: %d ",
6236 i, j,
6237 napis->napi_schedules,
6238 napis->napi_polls,
6239 napis->napi_completes,
6240 napis->napi_workdone);
6241
6242 for (k = 0; k < QCA_NAPI_NUM_BUCKETS; k++) {
6243 n += scnprintf(
6244 buf + n, max - n,
6245 " %d",
6246 napis->napi_budget_uses[k]);
6247 }
6248 n += scnprintf(buf+n, max - n, "\n");
6249 }
6250 }
6251
6252 NAPI_DEBUG("<--[n=%d]\n", n);
6253 return n;
6254}
6255
6256/**
6257 * napi_set_scale() - sets the scale attribute in all NAPI entries
6258 * @sc : scale to set
6259 *
6260 * Return: void
6261 */
6262static void napi_set_scale(uint8_t sc)
6263{
6264 uint32_t i;
6265 struct qca_napi_data *napi_data;
6266
6267 napi_data = hdd_napi_get_all();
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006268 if (likely(NULL != napi_data))
6269 for (i = 0; i < CE_COUNT_MAX; i++)
6270 if (napi_data->ce_map & (0x01 << i))
6271 napi_data->napis[i].scale = sc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006272
6273 return;
6274}
6275/**
6276 * drv_cmd_napi() - processes NAPI commands
6277 * @adapter : net_device
6278 * @hdd_ctx : HDD context
6279 * @command : command string from user command (including "NAPI")
6280 * @command_len: length of command
6281 * @priv_data : ifr_data
6282 *
6283 * Commands supported:
6284 * NAPI ENABLE : enables NAPI administratively. Note that this may not
6285 * enable NAPI functionally, as some other conditions
6286 * may not have been satisfied yet
6287 * NAPI DISABLE : reverse operation of "enable"
6288 * NAPI STATUS : get global status of NAPI instances
6289 * NAPI STATS [<n>] : get the stats for a given NAPI instance
6290 * NAPI SCALE <n> : set the scale factor
6291 *
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006292 * Return: 0: success; !0: failure
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006293 */
6294static int drv_cmd_napi(hdd_adapter_t *adapter,
6295 hdd_context_t *hdd_ctx,
6296 uint8_t *command,
6297 uint8_t command_len,
6298 hdd_priv_data_t *priv_data)
6299{
6300 int rc = 0;
6301 int n, l;
6302 char *cmd = NULL, *subcmd = NULL, *aux = NULL;
6303 char *synopsis = "NAPI ENABLE\n"
6304 "NAPI DISABLE\n"
6305 "NAPI STATUS\n"
6306 "NAPI STATS [<n>] -- if no <n> then all\n"
6307 "NAPI SCALE <n> -- set the scale\n";
6308 char *reply = NULL;
6309
6310 /* make a local copy, as strsep modifies the str in place */
6311 char *str = NULL;
6312
6313 NAPI_DEBUG("-->\n");
6314
6315 /**
6316 * NOTE TO MAINTAINER: from this point to the end of the function,
6317 * please do not return anywhere in the code except the very end
6318 * to avoid memory leakage (goto end_drv_napi instead)
6319 * or make sure that reply+str is freed
6320 */
6321 reply = kmalloc(MAX_USER_COMMAND_SIZE, GFP_KERNEL);
6322 if (NULL == reply) {
6323 hdd_err("could not allocate reply buffer");
6324 rc = -ENOMEM;
6325 goto end_drv_napi;
6326 }
6327
6328 str = kmalloc(strlen(command) + 1, GFP_KERNEL);
6329 if (NULL == str) {
6330 hdd_err("could not allocate copy of input buffer");
6331 rc = -ENOMEM;
6332 goto end_drv_napi;
6333 }
6334
6335 strlcpy(str, command, strlen(command) + 1);
6336 hdd_debug("parsing command into cmd=0x%p sub=0x%p aux=0x%p\n",
6337 cmd, subcmd, aux);
6338
6339
6340 rc = hdd_parse_napi(&str, &cmd, &subcmd, &aux);
6341
6342 if (0 != rc) {
6343 const char *msg = "unknown or badly formatted cmd\n%s";
Anurag Chouhan6d760662016-02-20 16:05:43 +05306344 l = QDF_MIN(MAX_USER_COMMAND_SIZE,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006345 strlen(msg)+strlen(synopsis));
6346 n = scnprintf(reply, l, msg, synopsis);
6347
6348 if (copy_to_user(priv_data->buf, reply,
Anurag Chouhan6d760662016-02-20 16:05:43 +05306349 QDF_MIN(priv_data->total_len, l)))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006350 hdd_err("failed to copy data to user buffer");
6351 hdd_debug("reply: %s", reply);
6352
6353 rc = -EINVAL;
6354 } else {
6355 hdd_debug("cmd=(%s) subcmd=(%s) aux=(%s)\n",
6356 cmd, subcmd, aux);
6357 if (!strcmp(subcmd, "ENABLE"))
6358 hdd_napi_event(NAPI_EVT_CMD_STATE, (void *)1);
6359 else if (!strcmp(subcmd, "DISABLE"))
6360 hdd_napi_event(NAPI_EVT_CMD_STATE, (void *)0);
6361 else if (!strcmp(subcmd, "STATUS")) {
6362 int n = 0;
6363 uint32_t i;
6364 struct qca_napi_data *napi_data;
6365
6366 napi_data = hdd_napi_get_all();
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006367 if (unlikely(NULL == napi_data))
6368 goto status_end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006369 n += scnprintf(reply+n, MAX_USER_COMMAND_SIZE - n,
6370 "NAPI state: 0x%08x map: 0x%08x\n",
6371 napi_data->state,
6372 napi_data->ce_map);
6373
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006374 for (i = 0; i < CE_COUNT_MAX; i++)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006375 if (napi_data->ce_map & (0x01 << i)) {
6376 n += scnprintf(
6377 reply + n,
6378 MAX_USER_COMMAND_SIZE - n,
6379 "#%d: id: %d, scale=%d\n",
6380 i,
6381 napi_data->napis[i].id,
6382 napi_data->napis[i].scale);
6383 }
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006384 status_end:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006385 hdd_info("wlan: STATUS DATA:\n%s", reply);
6386 if (copy_to_user(priv_data->buf, reply,
Anurag Chouhan6d760662016-02-20 16:05:43 +05306387 QDF_MIN(n, priv_data->total_len)))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006388 rc = -EINVAL;
6389 } else if (!strcmp(subcmd, "STATS")) {
6390 int n = 0;
6391 struct qca_napi_data *napi_data;
6392
6393 napi_data = hdd_napi_get_all();
Orhan K AKYILDIZc4094612015-11-11 18:01:15 -08006394 if (NULL != napi_data) {
6395 n = hdd_napi_stats(reply, MAX_USER_COMMAND_SIZE,
6396 aux, napi_data);
6397 NAPI_DEBUG("STATS: returns %d\n", n);
6398 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006399 if (n > 0) {
6400 if (copy_to_user(priv_data->buf, reply,
Anurag Chouhan6d760662016-02-20 16:05:43 +05306401 QDF_MIN(priv_data->total_len,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006402 n)))
6403 rc = -EINVAL;
6404 hdd_info("wlan: STATS_DATA\n%s\n", reply);
6405 } else
6406 rc = -EINVAL;
6407 } else if (!strcmp(subcmd, "SCALE")) {
6408 if (NULL == aux) {
6409 rc = -EINVAL;
6410 hdd_err("wlan: SCALE cmd requires <n>");
6411 } else {
6412 uint8_t sc;
6413 rc = kstrtou8(aux, 10, &sc);
6414 if (rc) {
6415 hdd_err("wlan: bad scale (%s)", aux);
6416 rc = -EINVAL;
6417 } else
6418 napi_set_scale(sc);
6419 }
6420 } /* SCALE */
6421 }
6422end_drv_napi:
6423 if (NULL != str)
6424 kfree(str);
6425 if (NULL != reply)
6426 kfree(reply);
6427
6428 NAPI_DEBUG("<--[rc=%d]\n", rc);
6429 return rc;
6430}
6431#endif /* FEATURE_NAPI */
6432
6433/**
6434 * hdd_set_rx_filter() - set RX filter
6435 * @adapter: Pointer to adapter
6436 * @action: Filter action
6437 * @pattern: Address pattern
6438 *
6439 * Address pattern is most significant byte of address for example
6440 * 0x01 for IPV4 multicast address
6441 * 0x33 for IPV6 multicast address
6442 * 0xFF for broadcast address
6443 *
6444 * Return: 0 for success, non-zero for failure
6445 */
6446static int hdd_set_rx_filter(hdd_adapter_t *adapter, bool action,
6447 uint8_t pattern)
6448{
6449 int ret;
Frank Liuf95e8132016-09-29 19:01:30 +08006450 uint8_t i, j;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006451 tHalHandle handle;
6452 tSirRcvFltMcAddrList *filter;
6453 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
6454
6455 ret = wlan_hdd_validate_context(hdd_ctx);
6456 if (0 != ret)
6457 return ret;
6458
6459 handle = hdd_ctx->hHal;
6460
6461 if (NULL == handle) {
6462 hdd_err("HAL Handle is NULL");
6463 return -EINVAL;
6464 }
6465
6466 /*
6467 * If action is false it means start dropping packets
6468 * Set addr_filter_pattern which will be used when sending
6469 * MC/BC address list to target
6470 */
6471 if (!action)
6472 adapter->addr_filter_pattern = pattern;
6473 else
6474 adapter->addr_filter_pattern = 0;
6475
Krunal Sonibe766b02016-03-10 13:00:44 -08006476 if (((adapter->device_mode == QDF_STA_MODE) ||
6477 (adapter->device_mode == QDF_P2P_CLIENT_MODE)) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006478 adapter->mc_addr_list.mc_cnt &&
6479 hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
6480
6481
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306482 filter = qdf_mem_malloc(sizeof(*filter));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006483 if (NULL == filter) {
6484 hdd_err("Could not allocate Memory");
6485 return -ENOMEM;
6486 }
6487 filter->action = action;
Frank Liuf95e8132016-09-29 19:01:30 +08006488 for (i = 0, j = 0; i < adapter->mc_addr_list.mc_cnt; i++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006489 if (!memcmp(adapter->mc_addr_list.addr[i],
6490 &pattern, 1)) {
Frank Liuf95e8132016-09-29 19:01:30 +08006491 memcpy(filter->multicastAddr[j].bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006492 adapter->mc_addr_list.addr[i],
6493 sizeof(adapter->mc_addr_list.addr[i]));
Frank Liuf95e8132016-09-29 19:01:30 +08006494
Srinivas Girigowdaf2599dd2015-11-16 18:20:46 -08006495 hdd_info("%s RX filter : addr ="
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006496 MAC_ADDRESS_STR,
6497 action ? "setting" : "clearing",
Frank Liuf95e8132016-09-29 19:01:30 +08006498 MAC_ADDR_ARRAY(filter->multicastAddr[j].bytes));
6499 j++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006500 }
6501 }
Frank Liuf95e8132016-09-29 19:01:30 +08006502 filter->ulMulticastAddrCnt = j;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006503 /* Set rx filter */
6504 sme_8023_multicast_list(handle, adapter->sessionId, filter);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306505 qdf_mem_free(filter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006506 } else {
Srinivas Girigowdaf2599dd2015-11-16 18:20:46 -08006507 hdd_info("mode %d mc_cnt %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006508 adapter->device_mode, adapter->mc_addr_list.mc_cnt);
6509 }
6510
6511 return 0;
6512}
6513
6514/**
6515 * hdd_driver_rxfilter_comand_handler() - RXFILTER driver command handler
6516 * @command: Pointer to input string driver command
6517 * @adapter: Pointer to adapter
6518 * @action: Action to enable/disable filtering
6519 *
6520 * If action == false
6521 * Start filtering out data packets based on type
6522 * RXFILTER-REMOVE 0 -> Start filtering out unicast data packets
6523 * RXFILTER-REMOVE 1 -> Start filtering out broadcast data packets
6524 * RXFILTER-REMOVE 2 -> Start filtering out IPV4 mcast data packets
6525 * RXFILTER-REMOVE 3 -> Start filtering out IPV6 mcast data packets
6526 *
6527 * if action == true
6528 * Stop filtering data packets based on type
6529 * RXFILTER-ADD 0 -> Stop filtering unicast data packets
6530 * RXFILTER-ADD 1 -> Stop filtering broadcast data packets
6531 * RXFILTER-ADD 2 -> Stop filtering IPV4 mcast data packets
6532 * RXFILTER-ADD 3 -> Stop filtering IPV6 mcast data packets
6533 *
6534 * Current implementation only supports IPV4 address filtering by
6535 * selectively allowing IPV4 multicast data packest based on
6536 * address list received in .ndo_set_rx_mode
6537 *
6538 * Return: 0 for success, non-zero for failure
6539 */
6540static int hdd_driver_rxfilter_comand_handler(uint8_t *command,
6541 hdd_adapter_t *adapter,
6542 bool action)
6543{
6544 int ret = 0;
6545 uint8_t *value;
6546 uint8_t type;
6547
6548 value = command;
6549 /* Skip space after RXFILTER-REMOVE OR RXFILTER-ADD based on action */
6550 if (!action)
6551 value = command + 16;
6552 else
6553 value = command + 13;
6554 ret = kstrtou8(value, 10, &type);
6555 if (ret < 0) {
6556 hdd_err("kstrtou8 failed invalid input value %d", type);
6557 return -EINVAL;
6558 }
6559
6560 switch (type) {
6561 case 2:
6562 /* Set rx filter for IPV4 multicast data packets */
6563 ret = hdd_set_rx_filter(adapter, action, 0x01);
6564 break;
6565 default:
6566 hdd_info("Unsupported RXFILTER type %d", type);
6567 break;
6568 }
6569
6570 return ret;
6571}
6572
6573/**
6574 * drv_cmd_rx_filter_remove() - RXFILTER REMOVE driver command handler
6575 * @adapter: Pointer to network adapter
6576 * @hdd_ctx: Pointer to hdd context
6577 * @command: Pointer to input command
6578 * @command_len: Command length
6579 * @priv_data: Pointer to private data in command
6580 */
6581static int drv_cmd_rx_filter_remove(hdd_adapter_t *adapter,
6582 hdd_context_t *hdd_ctx,
6583 uint8_t *command,
6584 uint8_t command_len,
6585 hdd_priv_data_t *priv_data)
6586{
6587 return hdd_driver_rxfilter_comand_handler(command, adapter, false);
6588}
6589
6590/**
6591 * drv_cmd_rx_filter_add() - RXFILTER ADD driver command handler
6592 * @adapter: Pointer to network adapter
6593 * @hdd_ctx: Pointer to hdd context
6594 * @command: Pointer to input command
6595 * @command_len: Command length
6596 * @priv_data: Pointer to private data in command
6597 */
6598static int drv_cmd_rx_filter_add(hdd_adapter_t *adapter,
6599 hdd_context_t *hdd_ctx,
6600 uint8_t *command,
6601 uint8_t command_len,
6602 hdd_priv_data_t *priv_data)
6603{
6604 return hdd_driver_rxfilter_comand_handler(command, adapter, true);
6605}
6606
Archana Ramachandran393f3792015-11-13 17:13:21 -08006607/**
6608 * hdd_parse_setantennamode_command() - HDD Parse SETANTENNAMODE
6609 * command
6610 * @value: Pointer to SETANTENNAMODE command
6611 * @mode: Pointer to antenna mode
6612 * @reason: Pointer to reason for set antenna mode
6613 *
6614 * This function parses the SETANTENNAMODE command passed in the format
6615 * SETANTENNAMODE<space>mode
6616 *
6617 * Return: 0 for success non-zero for failure
6618 */
6619static int hdd_parse_setantennamode_command(const uint8_t *value)
6620{
6621 const uint8_t *in_ptr = value;
6622 int tmp, v;
6623 char arg1[32];
6624
6625 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
6626
6627 /* no argument after the command */
6628 if (NULL == in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006629 hdd_err("No argument after the command");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006630 return -EINVAL;
6631 }
6632
6633 /* no space after the command */
6634 if (SPACE_ASCII_VALUE != *in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006635 hdd_err("No space after the command");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006636 return -EINVAL;
6637 }
6638
6639 /* remove empty spaces */
6640 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
6641 in_ptr++;
6642
6643 /* no argument followed by spaces */
6644 if ('\0' == *in_ptr) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006645 hdd_err("No argument followed by spaces");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006646 return -EINVAL;
6647 }
6648
6649 /* get the argument i.e. antenna mode */
6650 v = sscanf(in_ptr, "%31s ", arg1);
6651 if (1 != v) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006652 hdd_err("argument retrieval from cmd string failed");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006653 return -EINVAL;
6654 }
6655
6656 v = kstrtos32(arg1, 10, &tmp);
6657 if (v < 0) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07006658 hdd_err("argument string to int conversion failed");
Archana Ramachandran393f3792015-11-13 17:13:21 -08006659 return -EINVAL;
6660 }
6661
6662 return tmp;
6663}
6664
6665/**
6666 * hdd_is_supported_chain_mask_2x2() - Verify if supported chain
6667 * mask is 2x2 mode
6668 * @hdd_ctx: Pointer to hdd contex
6669 *
6670 * Return: true if supported chain mask 2x2 else false
6671 */
6672static bool hdd_is_supported_chain_mask_2x2(hdd_context_t *hdd_ctx)
6673{
6674 /*
6675 * Revisit and the update logic to determine the number
6676 * of TX/RX chains supported in the system when
6677 * antenna sharing per band chain mask support is
6678 * brought in
6679 */
6680 return (hdd_ctx->config->enable2x2 == 0x01) ? true : false;
6681}
6682
6683/**
6684 * hdd_is_supported_chain_mask_1x1() - Verify if the supported
6685 * chain mask is 1x1
6686 * @hdd_ctx: Pointer to hdd contex
6687 *
6688 * Return: true if supported chain mask 1x1 else false
6689 */
6690static bool hdd_is_supported_chain_mask_1x1(hdd_context_t *hdd_ctx)
6691{
6692 /*
6693 * Revisit and update the logic to determine the number
6694 * of TX/RX chains supported in the system when
6695 * antenna sharing per band chain mask support is
6696 * brought in
6697 */
6698 return (!hdd_ctx->config->enable2x2) ? true : false;
6699}
6700
6701/**
6702 * drv_cmd_set_antenna_mode() - SET ANTENNA MODE driver command
6703 * handler
6704 * @adapter: Pointer to network adapter
6705 * @hdd_ctx: Pointer to hdd context
6706 * @command: Pointer to input command
6707 * @command_len: Command length
6708 * @priv_data: Pointer to private data in command
6709 */
6710static int drv_cmd_set_antenna_mode(hdd_adapter_t *adapter,
6711 hdd_context_t *hdd_ctx,
6712 uint8_t *command,
6713 uint8_t command_len,
6714 hdd_priv_data_t *priv_data)
6715{
6716 struct sir_antenna_mode_param params;
6717 QDF_STATUS status;
6718 int ret = 0;
6719 int mode;
6720 uint8_t *value = command;
6721 uint8_t smps_mode;
6722 uint8_t smps_enable;
6723
6724 if (((1 << QDF_STA_MODE) != hdd_ctx->concurrency_mode) ||
6725 (hdd_ctx->no_of_active_sessions[QDF_STA_MODE] > 1)) {
6726 hdd_err("Operation invalid in non sta or concurrent mode");
6727 ret = -EPERM;
6728 goto exit;
6729 }
6730
6731 mode = hdd_parse_setantennamode_command(value);
6732 if (mode < 0) {
6733 hdd_err("Invalid SETANTENNA command");
6734 ret = mode;
6735 goto exit;
6736 }
6737
6738 hdd_info("Processing antenna mode switch to: %d", mode);
6739
6740 if (hdd_ctx->current_antenna_mode == mode) {
6741 hdd_err("System already in the requested mode");
6742 ret = 0;
6743 goto exit;
6744 }
6745
6746 if ((HDD_ANTENNA_MODE_2X2 == mode) &&
6747 (!hdd_is_supported_chain_mask_2x2(hdd_ctx))) {
6748 hdd_err("System does not support 2x2 mode");
6749 ret = -EPERM;
6750 goto exit;
6751 }
6752
6753 if ((HDD_ANTENNA_MODE_1X1 == mode) &&
6754 hdd_is_supported_chain_mask_1x1(hdd_ctx)) {
6755 hdd_err("System only supports 1x1 mode");
6756 ret = 0;
6757 goto exit;
6758 }
6759
6760 switch (mode) {
6761 case HDD_ANTENNA_MODE_1X1:
6762 params.num_rx_chains = 1;
6763 params.num_tx_chains = 1;
6764 break;
6765 case HDD_ANTENNA_MODE_2X2:
6766 params.num_rx_chains = 2;
6767 params.num_tx_chains = 2;
6768 break;
6769 default:
6770 hdd_err("unsupported antenna mode");
6771 ret = -EINVAL;
6772 goto exit;
6773 }
6774
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006775 /* Check TDLS status and update antenna mode */
6776 if ((QDF_STA_MODE == adapter->device_mode) &&
Kabilan Kannan32eb5022016-10-04 12:24:50 -07006777 cds_is_sta_active_connection_exists()) {
Archana Ramachandran2ad7de22016-04-22 16:53:25 -07006778 ret = wlan_hdd_tdls_antenna_switch(hdd_ctx, adapter,
6779 mode);
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006780 if (0 != ret)
6781 goto exit;
6782 }
6783
Archana Ramachandran393f3792015-11-13 17:13:21 -08006784 params.set_antenna_mode_resp =
6785 (void *)wlan_hdd_soc_set_antenna_mode_cb;
6786 hdd_info("Set antenna mode rx chains: %d tx chains: %d",
6787 params.num_rx_chains,
6788 params.num_tx_chains);
6789
6790
6791 INIT_COMPLETION(hdd_ctx->set_antenna_mode_cmpl);
6792 status = sme_soc_set_antenna_mode(hdd_ctx->hHal, &params);
6793 if (QDF_STATUS_SUCCESS != status) {
6794 hdd_err("set antenna mode failed status : %d", status);
6795 ret = -EFAULT;
6796 goto exit;
6797 }
6798
6799 ret = wait_for_completion_timeout(
6800 &hdd_ctx->set_antenna_mode_cmpl,
6801 msecs_to_jiffies(WLAN_WAIT_TIME_ANTENNA_MODE_REQ));
6802 if (!ret) {
6803 ret = -EFAULT;
6804 hdd_err("send set antenna mode timed out");
6805 goto exit;
6806 }
6807
6808 /* Update SME SMPS config */
6809 if (HDD_ANTENNA_MODE_1X1 == mode) {
6810 smps_enable = true;
6811 smps_mode = HDD_SMPS_MODE_STATIC;
6812 } else {
6813 smps_enable = false;
6814 smps_mode = HDD_SMPS_MODE_DISABLED;
6815 }
6816
6817 hdd_info("Update SME SMPS enable: %d mode: %d",
6818 smps_enable, smps_mode);
6819 status = sme_update_mimo_power_save(
6820 hdd_ctx->hHal, smps_enable, smps_mode, false);
6821 if (QDF_STATUS_SUCCESS != status) {
6822 hdd_err("Update SMPS config failed enable: %d mode: %d status: %d",
6823 smps_enable, smps_mode, status);
6824 ret = -EFAULT;
6825 goto exit;
6826 }
6827
Archana Ramachandran393f3792015-11-13 17:13:21 -08006828 hdd_ctx->current_antenna_mode = mode;
Archana Ramachandran5041b252016-04-25 14:29:25 -07006829 /* Update the user requested nss in the mac context.
6830 * This will be used in tdls protocol engine to form tdls
6831 * Management frames.
6832 */
6833 sme_update_user_configured_nss(
6834 hdd_ctx->hHal,
6835 hdd_ctx->current_antenna_mode);
Archana Ramachandran393f3792015-11-13 17:13:21 -08006836
Archana Ramachandran5041b252016-04-25 14:29:25 -07006837 hdd_info("Successfully switched to mode: %d x %d",
6838 hdd_ctx->current_antenna_mode,
6839 hdd_ctx->current_antenna_mode);
6840 ret = 0;
Archana Ramachandran393f3792015-11-13 17:13:21 -08006841exit:
Kabilan Kannanff89f742016-08-15 18:14:10 -07006842#ifdef FEATURE_WLAN_TDLS
6843 /* Reset tdls NSS flags */
6844 if (hdd_ctx->tdls_nss_switch_in_progress &&
6845 hdd_ctx->tdls_nss_teardown_complete) {
6846 hdd_ctx->tdls_nss_switch_in_progress = false;
6847 hdd_ctx->tdls_nss_teardown_complete = false;
6848 }
6849 hdd_info("tdls_nss_switch_in_progress: %d tdls_nss_teardown_complete: %d",
6850 hdd_ctx->tdls_nss_switch_in_progress,
6851 hdd_ctx->tdls_nss_teardown_complete);
6852#endif
Archana Ramachandran393f3792015-11-13 17:13:21 -08006853 hdd_info("Set antenna status: %d current mode: %d",
6854 ret, hdd_ctx->current_antenna_mode);
6855 return ret;
6856
6857}
6858
6859/**
6860 * drv_cmd_get_antenna_mode() - GET ANTENNA MODE driver command
6861 * handler
6862 * @adapter: Pointer to hdd adapter
6863 * @hdd_ctx: Pointer to hdd context
6864 * @command: Pointer to input command
6865 * @command_len: length of the command
6866 * @priv_data: private data coming with the driver command
6867 *
6868 * Return: 0 for success non-zero for failure
6869 */
6870static inline int drv_cmd_get_antenna_mode(hdd_adapter_t *adapter,
6871 hdd_context_t *hdd_ctx,
6872 uint8_t *command,
6873 uint8_t command_len,
6874 hdd_priv_data_t *priv_data)
6875{
6876 uint32_t antenna_mode = 0;
6877 char extra[32];
6878 uint8_t len = 0;
6879
6880 antenna_mode = hdd_ctx->current_antenna_mode;
6881 len = scnprintf(extra, sizeof(extra), "%s %d", command,
6882 antenna_mode);
6883 len = QDF_MIN(priv_data->total_len, len + 1);
6884 if (copy_to_user(priv_data->buf, &extra, len)) {
6885 hdd_err("Failed to copy data to user buffer");
6886 return -EFAULT;
6887 }
6888
6889 hdd_info("Get antenna mode: %d", antenna_mode);
6890
6891 return 0;
6892}
6893
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006894/*
6895 * dummy (no-op) hdd driver command handler
6896 */
6897static int drv_cmd_dummy(hdd_adapter_t *adapter,
6898 hdd_context_t *hdd_ctx,
6899 uint8_t *command,
6900 uint8_t command_len,
6901 hdd_priv_data_t *priv_data)
6902{
6903 hdd_info("%s: Ignoring driver command \"%s\"",
6904 adapter->dev->name, command);
6905 return 0;
6906}
6907
6908/*
6909 * handler for any unsupported wlan hdd driver command
6910 */
6911static int drv_cmd_invalid(hdd_adapter_t *adapter,
6912 hdd_context_t *hdd_ctx,
6913 uint8_t *command,
6914 uint8_t command_len,
6915 hdd_priv_data_t *priv_data)
6916{
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306917 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006918 TRACE_CODE_HDD_UNSUPPORTED_IOCTL,
6919 adapter->sessionId, 0));
6920
6921 hdd_warn("%s: Unsupported driver command \"%s\"",
6922 adapter->dev->name, command);
6923
6924 return -ENOTSUPP;
6925}
6926
6927/**
6928 * drv_cmd_set_fcc_channel() - handle fcc constraint request
6929 * @adapter: HDD adapter
6930 * @hdd_ctx: HDD context
6931 * @command: command ptr, SET_FCC_CHANNEL 0/1 is the command
6932 * @command_len: command len
6933 * @priv_data: private data
6934 *
6935 * Return: status
6936 */
6937static int drv_cmd_set_fcc_channel(hdd_adapter_t *adapter,
6938 hdd_context_t *hdd_ctx,
6939 uint8_t *command,
6940 uint8_t command_len,
6941 hdd_priv_data_t *priv_data)
6942{
6943 uint8_t *value;
6944 uint8_t fcc_constraint;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306945 QDF_STATUS status;
Amar Singhal83a047a2016-05-19 15:56:11 -07006946 bool scan_pending;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006947 int ret = 0;
6948
6949 /*
6950 * this command would be called by user-space when it detects WLAN
6951 * ON after airplane mode is set. When APM is set, WLAN turns off.
6952 * But it can be turned back on. Otherwise; when APM is turned back
6953 * off, WLAN would turn back on. So at that point the command is
6954 * expected to come down. 0 means disable, 1 means enable. The
6955 * constraint is removed when parameter 1 is set or different
6956 * country code is set
6957 */
6958
6959 value = command + command_len + 1;
6960
6961 ret = kstrtou8(value, 10, &fcc_constraint);
6962 if ((ret < 0) || (fcc_constraint > 1)) {
6963 /*
6964 * If the input value is greater than max value of datatype,
6965 * then also it is a failure
6966 */
6967 hdd_err("value out of range");
6968 return -EINVAL;
6969 }
6970
Amar Singhal83a047a2016-05-19 15:56:11 -07006971 scan_pending = !qdf_list_empty(&hdd_ctx->hdd_scan_req_q);
6972 status = sme_handle_set_fcc_channel(hdd_ctx->hHal, !fcc_constraint,
6973 scan_pending);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306974 if (status != QDF_STATUS_SUCCESS) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006975 hdd_err("sme disable fn. returned err");
6976 ret = -EPERM;
6977 }
6978
6979 return ret;
6980}
6981
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05306982/**
6983 * hdd_parse_set_channel_switch_command() - Parse and validate CHANNEL_SWITCH
6984 * command
6985 * @value: Pointer to the command
6986 * @chan_number: Pointer to the channel number
6987 * @chan_bw: Pointer to the channel bandwidth
6988 *
6989 * Parses and provides the channel number and channel width from the input
6990 * command which is expected to be of the format: CHANNEL_SWITCH <CH> <BW>
6991 * <CH> is channel number to move (where 1 = channel 1, 149 = channel 149, ...)
6992 * <BW> is bandwidth to move (where 20 = BW 20, 40 = BW 40, 80 = BW 80)
6993 *
6994 * Return: 0 for success, non-zero for failure
6995 */
6996static int hdd_parse_set_channel_switch_command(uint8_t *value,
6997 uint32_t *chan_number,
6998 uint32_t *chan_bw)
6999{
7000 const uint8_t *in_ptr = value;
7001 int ret;
7002
7003 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
7004
7005 /* no argument after the command */
7006 if (NULL == in_ptr) {
7007 hdd_err("No argument after the command");
7008 return -EINVAL;
7009 }
7010
7011 /* no space after the command */
7012 if (SPACE_ASCII_VALUE != *in_ptr) {
7013 hdd_err("No space after the command ");
7014 return -EINVAL;
7015 }
7016
7017 /* remove empty spaces and move the next argument */
7018 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
7019 in_ptr++;
7020
7021 /* no argument followed by spaces */
7022 if ('\0' == *in_ptr) {
7023 hdd_err("No argument followed by spaces");
7024 return -EINVAL;
7025 }
7026
7027 /* get the two arguments: channel number and bandwidth */
7028 ret = sscanf(in_ptr, "%u %u", chan_number, chan_bw);
7029 if (ret != 2) {
7030 hdd_err("Arguments retrieval from cmd string failed");
7031 return -EINVAL;
7032 }
7033
7034 return 0;
7035}
7036
7037/**
7038 * drv_cmd_set_channel_switch() - Switch SAP/P2P-GO operating channel
7039 * @adapter: HDD adapter
7040 * @hdd_ctx: HDD context
7041 * @command: Pointer to the input command CHANNEL_SWITCH
7042 * @command_len: Command len
7043 * @priv_data: Private data
7044 *
7045 * Handles private IOCTL CHANNEL_SWITCH command to switch the operating channel
7046 * of SAP/P2P-GO
7047 *
7048 * Return: 0 for success, non-zero for failure
7049 */
7050static int drv_cmd_set_channel_switch(hdd_adapter_t *adapter,
7051 hdd_context_t *hdd_ctx,
7052 uint8_t *command,
7053 uint8_t command_len,
7054 hdd_priv_data_t *priv_data)
7055{
7056 struct net_device *dev = adapter->dev;
7057 int status;
7058 uint32_t chan_number = 0, chan_bw = 0;
7059 uint8_t *value = command;
Kiran Kumar Lokere13644672016-02-29 15:40:10 -08007060 enum phy_ch_width width;
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307061
Krunal Sonibe766b02016-03-10 13:00:44 -08007062 if ((adapter->device_mode != QDF_P2P_GO_MODE) &&
7063 (adapter->device_mode != QDF_SAP_MODE)) {
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307064 hdd_err("IOCTL CHANNEL_SWITCH not supported for mode %d",
7065 adapter->device_mode);
7066 return -EINVAL;
7067 }
7068
7069 status = hdd_parse_set_channel_switch_command(value,
7070 &chan_number, &chan_bw);
7071 if (status) {
7072 hdd_err("Invalid CHANNEL_SWITCH command");
7073 return status;
7074 }
7075
7076 if ((chan_bw != 20) && (chan_bw != 40) && (chan_bw != 80)) {
7077 hdd_err("BW %d is not allowed for CHANNEL_SWITCH", chan_bw);
7078 return -EINVAL;
7079 }
7080
7081 if (chan_bw == 80)
7082 width = CH_WIDTH_80MHZ;
7083 else if (chan_bw == 40)
7084 width = CH_WIDTH_40MHZ;
7085 else
7086 width = CH_WIDTH_20MHZ;
7087
7088 hdd_info("CH:%d BW:%d", chan_number, chan_bw);
7089
7090 status = hdd_softap_set_channel_change(dev, chan_number, width);
7091 if (status) {
7092 hdd_err("Set channel change fail");
7093 return status;
7094 }
7095
7096 return 0;
7097}
7098
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007099/*
7100 * The following table contains all supported WLAN HDD
7101 * IOCTL driver commands and the handler for each of them.
7102 */
7103static const hdd_drv_cmd_t hdd_drv_cmds[] = {
7104 {"P2P_DEV_ADDR", drv_cmd_p2p_dev_addr},
7105 {"P2P_SET_NOA", drv_cmd_p2p_set_noa},
7106 {"P2P_SET_PS", drv_cmd_p2p_set_ps},
7107 {"SETBAND", drv_cmd_set_band},
7108 {"SETWMMPS", drv_cmd_set_wmmps},
7109 {"COUNTRY", drv_cmd_country},
7110 {"SETSUSPENDMODE", drv_cmd_dummy},
7111 {"SET_AP_WPS_P2P_IE", drv_cmd_dummy},
7112 {"BTCOEXSCAN", drv_cmd_dummy},
7113 {"RXFILTER", drv_cmd_dummy},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007114 {"SETROAMTRIGGER", drv_cmd_set_roam_trigger},
7115 {"GETROAMTRIGGER", drv_cmd_get_roam_trigger},
7116 {"SETROAMSCANPERIOD", drv_cmd_set_roam_scan_period},
7117 {"GETROAMSCANPERIOD", drv_cmd_get_roam_scan_period},
7118 {"SETROAMSCANREFRESHPERIOD", drv_cmd_set_roam_scan_refresh_period},
7119 {"GETROAMSCANREFRESHPERIOD", drv_cmd_get_roam_scan_refresh_period},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007120 {"SETROAMMODE", drv_cmd_set_roam_mode},
7121 {"GETROAMMODE", drv_cmd_get_roam_mode},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007122 {"SETROAMDELTA", drv_cmd_set_roam_delta},
7123 {"GETROAMDELTA", drv_cmd_get_roam_delta},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007124 {"GETBAND", drv_cmd_get_band},
7125 {"SETROAMSCANCHANNELS", drv_cmd_set_roam_scan_channels},
7126 {"GETROAMSCANCHANNELS", drv_cmd_get_roam_scan_channels},
7127 {"GETCCXMODE", drv_cmd_get_ccx_mode},
7128 {"GETOKCMODE", drv_cmd_get_okc_mode},
7129 {"GETFASTROAM", drv_cmd_get_fast_roam},
7130 {"GETFASTTRANSITION", drv_cmd_get_fast_transition},
7131 {"SETROAMSCANCHANNELMINTIME", drv_cmd_set_roam_scan_channel_min_time},
7132 {"SENDACTIONFRAME", drv_cmd_send_action_frame},
7133 {"GETROAMSCANCHANNELMINTIME", drv_cmd_get_roam_scan_channel_min_time},
7134 {"SETSCANCHANNELTIME", drv_cmd_set_scan_channel_time},
7135 {"GETSCANCHANNELTIME", drv_cmd_get_scan_channel_time},
7136 {"SETSCANHOMETIME", drv_cmd_set_scan_home_time},
7137 {"GETSCANHOMETIME", drv_cmd_get_scan_home_time},
7138 {"SETROAMINTRABAND", drv_cmd_set_roam_intra_band},
7139 {"GETROAMINTRABAND", drv_cmd_get_roam_intra_band},
7140 {"SETSCANNPROBES", drv_cmd_set_scan_n_probes},
7141 {"GETSCANNPROBES", drv_cmd_get_scan_n_probes},
7142 {"SETSCANHOMEAWAYTIME", drv_cmd_set_scan_home_away_time},
7143 {"GETSCANHOMEAWAYTIME", drv_cmd_get_scan_home_away_time},
7144 {"REASSOC", drv_cmd_reassoc},
7145 {"SETWESMODE", drv_cmd_set_wes_mode},
7146 {"GETWESMODE", drv_cmd_get_wes_mode},
7147 {"SETOPPORTUNISTICRSSIDIFF", drv_cmd_set_opportunistic_rssi_diff},
7148 {"GETOPPORTUNISTICRSSIDIFF", drv_cmd_get_opportunistic_rssi_diff},
7149 {"SETROAMRESCANRSSIDIFF", drv_cmd_set_roam_rescan_rssi_diff},
7150 {"GETROAMRESCANRSSIDIFF", drv_cmd_get_roam_rescan_rssi_diff},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007151 {"SETFASTROAM", drv_cmd_set_fast_roam},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007152 {"SETFASTTRANSITION", drv_cmd_set_fast_transition},
7153 {"FASTREASSOC", drv_cmd_fast_reassoc},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007154 {"SETROAMSCANCONTROL", drv_cmd_set_roam_scan_control},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007155 {"SETOKCMODE", drv_cmd_set_okc_mode},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007156 {"GETROAMSCANCONTROL", drv_cmd_get_roam_scan_control},
7157 {"BTCOEXMODE", drv_cmd_bt_coex_mode},
7158 {"SCAN-ACTIVE", drv_cmd_scan_active},
7159 {"SCAN-PASSIVE", drv_cmd_scan_passive},
7160 {"GETDWELLTIME", drv_cmd_get_dwell_time},
7161 {"SETDWELLTIME", drv_cmd_set_dwell_time},
7162 {"MIRACAST", drv_cmd_miracast},
Rajeev Kumar8e3e2832015-11-06 16:02:54 -08007163 {"SETIBSSBEACONOUIDATA", drv_cmd_set_ibss_beacon_oui_data},
7164 {"SETRMCENABLE", drv_cmd_set_rmc_enable},
7165 {"SETRMCACTIONPERIOD", drv_cmd_set_rmc_action_period},
7166 {"GETIBSSPEERINFOALL", drv_cmd_get_ibss_peer_info_all},
7167 {"GETIBSSPEERINFO", drv_cmd_get_ibss_peer_info},
7168 {"SETRMCTXRATE", drv_cmd_set_rmc_tx_rate},
7169 {"SETIBSSTXFAILEVENT", drv_cmd_set_ibss_tx_fail_event},
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08007170#ifdef FEATURE_WLAN_ESE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007171 {"SETCCXROAMSCANCHANNELS", drv_cmd_set_ccx_roam_scan_channels},
7172 {"GETTSMSTATS", drv_cmd_get_tsm_stats},
7173 {"SETCCKMIE", drv_cmd_set_cckm_ie},
Srinivas Girigowdad79b3452016-07-19 18:39:46 -07007174 {"CCXBEACONREQ", drv_cmd_ccx_beacon_req},
7175 {"CCXPLMREQ", drv_cmd_ccx_plm_req},
7176 {"SETCCXMODE", drv_cmd_set_ccx_mode},
Srinivas Girigowda515a9ef2015-12-11 11:00:48 -08007177#endif /* FEATURE_WLAN_ESE */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007178 {"SETMCRATE", drv_cmd_set_mc_rate},
7179 {"MAXTXPOWER", drv_cmd_max_tx_power},
7180 {"SETDFSSCANMODE", drv_cmd_set_dfs_scan_mode},
7181 {"GETDFSSCANMODE", drv_cmd_get_dfs_scan_mode},
7182 {"GETLINKSTATUS", drv_cmd_get_link_status},
7183#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
7184 {"ENABLEEXTWOW", drv_cmd_enable_ext_wow},
7185 {"SETAPP1PARAMS", drv_cmd_set_app1_params},
7186 {"SETAPP2PARAMS", drv_cmd_set_app2_params},
7187#endif
7188#ifdef FEATURE_WLAN_TDLS
7189 {"TDLSSECONDARYCHANNELOFFSET", drv_cmd_tdls_secondary_channel_offset},
7190 {"TDLSOFFCHANNELMODE", drv_cmd_tdls_off_channel_mode},
7191 {"TDLSOFFCHANNEL", drv_cmd_tdls_off_channel},
7192 {"TDLSSCAN", drv_cmd_tdls_scan},
7193#endif
7194 {"RSSI", drv_cmd_get_rssi},
7195 {"LINKSPEED", drv_cmd_get_linkspeed},
7196#ifdef FEATURE_NAPI
7197 {"NAPI", drv_cmd_napi},
7198#endif /* FEATURE_NAPI */
7199 {"RXFILTER-REMOVE", drv_cmd_rx_filter_remove},
7200 {"RXFILTER-ADD", drv_cmd_rx_filter_add},
7201 {"SET_FCC_CHANNEL", drv_cmd_set_fcc_channel},
Chandrasekaran, Manishekar794a0982016-01-12 19:42:20 +05307202 {"CHANNEL_SWITCH", drv_cmd_set_channel_switch},
Archana Ramachandran393f3792015-11-13 17:13:21 -08007203 {"SETANTENNAMODE", drv_cmd_set_antenna_mode},
7204 {"GETANTENNAMODE", drv_cmd_get_antenna_mode},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007205};
7206
7207/**
7208 * hdd_drv_cmd_process() - chooses and runs the proper
7209 * handler based on the input command
7210 * @adapter: Pointer to the hdd adapter
7211 * @cmd: Pointer to the driver command
7212 * @priv_data: Pointer to the data associated with the command
7213 *
7214 * This function parses the input hdd driver command and runs
7215 * the proper handler
7216 *
7217 * Return: 0 for success non-zero for failure
7218 */
7219static int hdd_drv_cmd_process(hdd_adapter_t *adapter,
7220 uint8_t *cmd,
7221 hdd_priv_data_t *priv_data)
7222{
7223 hdd_context_t *hdd_ctx;
7224 int i;
7225 const int cmd_num_total = ARRAY_SIZE(hdd_drv_cmds);
7226 uint8_t *cmd_i = NULL;
7227 hdd_drv_cmd_handler_t handler = NULL;
7228 int len = 0;
7229
7230 if (!adapter || !cmd || !priv_data) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007231 hdd_err("at least 1 param is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007232 return -EINVAL;
7233 }
7234
7235 hdd_ctx = (hdd_context_t *)adapter->pHddCtx;
7236
7237 for (i = 0; i < cmd_num_total; i++) {
7238
7239 cmd_i = (uint8_t *)hdd_drv_cmds[i].cmd;
7240 handler = hdd_drv_cmds[i].handler;
7241 len = strlen(cmd_i);
7242
7243 if (!handler) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007244 hdd_err("no. %d handler is NULL", i);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007245 return -EINVAL;
7246 }
7247
7248 if (strncasecmp(cmd, cmd_i, len) == 0)
7249 return handler(adapter, hdd_ctx,
7250 cmd, len, priv_data);
7251 }
7252
7253 return drv_cmd_invalid(adapter, hdd_ctx, cmd, len, priv_data);
7254}
7255
7256/**
7257 * hdd_driver_command() - top level wlan hdd driver command handler
7258 * @adapter: Pointer to the hdd adapter
7259 * @priv_data: Pointer to the raw command data
7260 *
7261 * This function is the top level wlan hdd driver command handler. It
7262 * handles the command with the help of hdd_drv_cmd_process()
7263 *
7264 * Return: 0 for success non-zero for failure
7265 */
7266static int hdd_driver_command(hdd_adapter_t *adapter,
7267 hdd_priv_data_t *priv_data)
7268{
7269 uint8_t *command = NULL;
7270 int ret = 0;
7271
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307272 ENTER();
7273
Anurag Chouhan6d760662016-02-20 16:05:43 +05307274 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007275 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007276 return -EINVAL;
7277 }
7278
7279 /*
7280 * Note that valid pointers are provided by caller
7281 */
7282
7283 /* copy to local struct to avoid numerous changes to legacy code */
7284 if (priv_data->total_len <= 0 ||
7285 priv_data->total_len > WLAN_PRIV_DATA_MAX_LEN) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007286 hdd_warn("Invalid priv_data.total_len(%d)!!!",
7287 priv_data->total_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007288 ret = -EINVAL;
7289 goto exit;
7290 }
7291
7292 /* Allocate +1 for '\0' */
7293 command = kmalloc(priv_data->total_len + 1, GFP_KERNEL);
7294 if (!command) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007295 hdd_err("failed to allocate memory");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007296 ret = -ENOMEM;
7297 goto exit;
7298 }
7299
7300 if (copy_from_user(command, priv_data->buf, priv_data->total_len)) {
7301 ret = -EFAULT;
7302 goto exit;
7303 }
7304
7305 /* Make sure the command is NUL-terminated */
7306 command[priv_data->total_len] = '\0';
7307
7308 hdd_info("%s: %s", adapter->dev->name, command);
7309 ret = hdd_drv_cmd_process(adapter, command, priv_data);
7310
7311exit:
7312 if (command)
7313 kfree(command);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307314 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007315 return ret;
7316}
7317
7318#ifdef CONFIG_COMPAT
7319static int hdd_driver_compat_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
7320{
7321 struct {
7322 compat_uptr_t buf;
7323 int used_len;
7324 int total_len;
7325 } compat_priv_data;
7326 hdd_priv_data_t priv_data;
7327 int ret = 0;
7328
7329 /*
7330 * Note that adapter and ifr have already been verified by caller,
7331 * and HDD context has also been validated
7332 */
7333 if (copy_from_user(&compat_priv_data, ifr->ifr_data,
7334 sizeof(compat_priv_data))) {
7335 ret = -EFAULT;
7336 goto exit;
7337 }
7338 priv_data.buf = compat_ptr(compat_priv_data.buf);
7339 priv_data.used_len = compat_priv_data.used_len;
7340 priv_data.total_len = compat_priv_data.total_len;
7341 ret = hdd_driver_command(adapter, &priv_data);
7342exit:
7343 return ret;
7344}
7345#else /* CONFIG_COMPAT */
7346static int hdd_driver_compat_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
7347{
7348 /* will never be invoked */
7349 return 0;
7350}
7351#endif /* CONFIG_COMPAT */
7352
7353static int hdd_driver_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
7354{
7355 hdd_priv_data_t priv_data;
7356 int ret = 0;
7357
7358 /*
7359 * Note that adapter and ifr have already been verified by caller,
7360 * and HDD context has also been validated
7361 */
7362 if (copy_from_user(&priv_data, ifr->ifr_data, sizeof(priv_data)))
7363 ret = -EFAULT;
7364 else
7365 ret = hdd_driver_command(adapter, &priv_data);
7366
7367 return ret;
7368}
7369
7370/**
7371 * __hdd_ioctl() - ioctl handler for wlan network interfaces
7372 * @dev: device upon which the ioctl was received
7373 * @ifr: ioctl request information
7374 * @cmd: ioctl command
7375 *
7376 * This function does initial processing of wlan device ioctls.
7377 * Currently two flavors of ioctls are supported. The primary ioctl
7378 * that is supported is the (SIOCDEVPRIVATE + 1) ioctl which is used
7379 * for Android "DRIVER" commands. The other ioctl that is
7380 * conditionally supported is the SIOCIOCTLTX99 ioctl which is used
7381 * for FTM on some platforms. This function simply verifies that the
7382 * driver is in a sane state, and that the ioctl is one of the
7383 * supported flavors, in which case flavor-specific handlers are
7384 * dispatched.
7385 *
7386 * Return: 0 on success, non-zero on error
7387 */
7388static int __hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7389{
7390 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
7391 hdd_context_t *hdd_ctx;
7392 int ret;
7393
Jeff Johnson3c3994a2016-02-11 08:12:30 -08007394 ENTER_DEV(dev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307395
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007396 if (dev != adapter->dev) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007397 hdd_alert("HDD adapter/dev inconsistency");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007398 ret = -ENODEV;
7399 goto exit;
7400 }
7401
7402 if ((!ifr) || (!ifr->ifr_data)) {
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007403 hdd_err("invalid data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007404 ret = -EINVAL;
7405 goto exit;
7406 }
7407#if defined(QCA_WIFI_FTM) && defined(LINUX_QCMBR)
Anurag Chouhan6d760662016-02-20 16:05:43 +05307408 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007409 if (SIOCIOCTLTX99 == cmd) {
7410 ret = wlan_hdd_qcmbr_unified_ioctl(adapter, ifr);
7411 goto exit;
7412 }
7413 }
7414#endif
7415
7416 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
7417 ret = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307418 if (ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007419 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007420
7421 switch (cmd) {
7422 case (SIOCDEVPRIVATE + 1):
7423 if (is_compat_task())
7424 ret = hdd_driver_compat_ioctl(adapter, ifr);
7425 else
7426 ret = hdd_driver_ioctl(adapter, ifr);
7427 break;
7428 default:
Archana Ramachandran3abc3912016-04-29 17:01:32 -07007429 hdd_err("unknown ioctl %d", cmd);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007430 ret = -EINVAL;
7431 break;
7432 }
7433exit:
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307434 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007435 return ret;
7436}
7437
7438/**
7439 * hdd_ioctl() - ioctl handler (wrapper) for wlan network interfaces
7440 * @dev: device upon which the ioctl was received
7441 * @ifr: ioctl request information
7442 * @cmd: ioctl command
7443 *
7444 * This function acts as an SSR-protecting wrapper to __hdd_ioctl()
7445 * which is where the ioctls are really handled.
7446 *
7447 * Return: 0 on success, non-zero on error
7448 */
7449int hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7450{
7451 int ret;
7452
7453 cds_ssr_protect(__func__);
7454 ret = __hdd_ioctl(dev, ifr, cmd);
7455 cds_ssr_unprotect(__func__);
7456 return ret;
7457}